0

I'm trying to migrate a Laravel 5 API with MySQL 5.7 to a Laravel 9 API with MySQL 8.

Almost everything is working well, except on a few queries that tries to load data with their parent, recursively.

On Laravel 5, i came up with this following solutions : Recursive Eloquent Models | Laravel ORM from self referencing table get N level hierarchy JSON

It was working like a charm, but on Laravel 9, I get a HTTP 500 error from Apache, which tells me in the logs the following error :

PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes)

I tried at first to increase the memory in php.ini, but it was getting worst as the server was getting very laggy, so I had to restart Apache and go back with the 128M default value. Also on my Laravel 5 environment, I did not need to increase memory.

I was also suspecting the MySQL 8 upgrade to be involved in this problem, but by connecting to my MySQL 5.7 database, i had the same issue, so I think it comes from the way that Laravel loads relations in the 9 version.

Here is my Model code :

<?php
  namespace App\Models\Consommation;

  use Illuminate\Database\Eloquent\Model;

  class ConsoRequestAttribut extends Model
  {
    protected $table = 'conso_request_attribut';
    public $incrementing = false;
    protected $primaryKey = 'id_attribut';
    public $timestamps = false;

    const ERROR_DELETE_ATTRIBUTE = 1;
    const SUCCESS_DELETE_ATTRIBUTE = 0;

    protected $fillable = [
        'id_attribut',
        'code_type_attribut',
        'valeur',
        'id_parent_attribut'
    ];

    public function parent_attribut() {
        return $this->belongsTo('App\Models\Consommation\ConsoRequestAttribut', 'id_parent_attribut', 'id_attribut');
    }

    public function parent() {
        return $this->parent_attribut()->with('parent');
    }

    ...
   }

So on my Laravel 9 app, if I remove the ->with('parent') in my parent() function, the query result is returned and I don't have a 500 HTTP error, so I think the problem is with recursive loading.

Any idea ?

Thanks

CTR
  • 183
  • 8

2 Answers2

0

It is better to call nested relationships like this:

public function parent() {
    return $this->with('parent_attribut.parent');
}
Vüsal Hüseynli
  • 889
  • 1
  • 4
  • 16
  • does this solve the question ? I dont think so. – ThS Sep 15 '22 at 11:41
  • If i use your code in my model I get the following error : `Call to undefined method Illuminate\\Database\\Eloquent\\Builder::addEagerConstraints()"`. It seems that this error pops up because this is not a relation? – CTR Sep 15 '22 at 12:04
  • I think so. Are you sure you have the `parent` relationship in `ConsoRequestAttribut` model? – Vüsal Hüseynli Sep 15 '22 at 12:29
  • Yes I have replaced my `parent()` function with yours and this error is throwed. Or do you mean that I need to have something else in my `ConsoRequestAttribut` model in addition to that ? – CTR Sep 15 '22 at 13:07
  • Wait I just realized that you have defined relationship in the same model. It means your table related to itself? If so, then what is `parent` relationship you have defined in `with('parent')`? It looks like a recursive function not even relationship – Vüsal Hüseynli Sep 15 '22 at 13:09
  • Yes that's a recursive function indeed and yes the table is related to itself ! Here is what the data returned looks like on my Laravel 5 app : https://img.onl/RXOoLk – CTR Sep 15 '22 at 13:27
  • Hmm, so strange. I can't say anything without debugging it to deeper. It is better to use `debugbar` package to see actual sql query. It may be lazy loaded so you are getting `memory size exhausted` exception. Sorry I don't have any other idea – Vüsal Hüseynli Sep 15 '22 at 13:32
0

I did not succeed to load the parent entity recursively with my ConsoRequestAttribut model, as I'm still stuck with the same memory problem. So it's not really "resolved".

As an alternative, in my ConsoRequestAttributRepository class, I made a function to load parent of entity recursively, which works perfectly :

public function retrieveRecursivelyConsoRequestAttributeParent(ConsoRequestAttribut $attribut)
{
    $parent = ConsoRequestAttribut::where('id_attribut', $attribut->id_parent_attribut)
        ->first();

    $attribut->parent = $parent;

    if($parent->id_parent_attribut != null)
        $this->retrieveRecursivelyConsoRequestAttributeParent($parent);
}
CTR
  • 183
  • 8