Laravel 9 - Eloquent model : Trying to load self model parents recursively - php

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

It is better to call nested relationships like this:
public function parent() {
return $this->with('parent_attribut.parent');
}

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);
}

Related

Cant able to import 1M excel data with laravel-excel package and laravel queue

I want to import a csv:xlsx file which has 50 column and 1M rows
I tried with laravel-excel package and Laravel queue. Some how i cant import the data. Nginx timeout given. I modify the max execution time in my php setting
In import controller
public function import(Request $request) { Excel::import(new LeadsImport, $request->file); }
In LeadsImport
public function collection(Collection $rows) { dispatch(new ImportJob($rows)); }
You should not call this type of heavy tasks from the browser because you are going to get timeout or worse out of memory error, due to the nature of webpages and the typical configuration.
I would make a custom command which make the heavy task of importing the 1M rows and for this if you use Eloquent make use of cursor or chunk methods of eloquent.
Hope this help.
https://qiita.com/ryo511/items/ebcd1c1b2ad5addc5c9d

Export big Excel with Laravel Excel 3.1

Hello I need help with Laravel Excel 3.1 with Laravel 7.
I have to export an excel with arround 300,000 records o more and download or save in public folder to download...
So when i do it with this plugin, localhost works fine. But in the server it shows an error 500.
I set memory limit = -1 and time execution = 1800.
it takes time to appear error 500 arround 10min or less.
This is my code:
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
class ProductsExport implements FromQuery
{
protected $filters;
use Exportable;
function __construct($filters) {
$this->filters= $filters;
}
public function query()
{
return Product::query()
->where($this->filters)
->orderby('name');
}
}
Controller
(new ProductsExport($filters)->queue('products.xlsx');
return back()->withSuccess('Export started!');
In excel.php I just configured chunk_size to 5000. I don't know what else I need to configure here
I know that i need to use queue for big data, and i used it, but i dont know what else to do.

Laravel method attributesToArray() not running on production

I'm deploying my application to my production environment and it's not working as expected. I've narrowed the issue down to one line inside this loop in my controller;
foreach($temp_table_data as $a_payment) {
//array_push($payments, $a_payment->payment); //big collection object
array_push($payments, $a_payment->payment->first()->attributesToArray()); //smaller object
}
The error I get is call to a member function attributesToArray() on a non object. This seems crazy to be because - as the old saying goes - it works fine on my machine.
My dev. environment is Ubuntu trusty64 on PHP 5.5.21 and my production is RedHat Linux PHP 5.5.11. I thought these differences were very minor (maybe I'm wrong?).
If I do a print_r($temp_table_data() then I get a big collection returned. The same on both servers. So at some point it just stops liking either payment (that's a method) or first()
Here is partial of my TempTable.php Model with the payment method;
public function payment(){
return $this->hasMany('App\Models\Payment', 'Vendor ZIP', 'postcode');
}
And my Payment.php model (part of it);
class Payment extends Model {
protected $table = 'headquarters_data';
public function tempTable()
{
return $this->belongsTo('App\Models\TempTable', 'postcode', 'Vendor ZIP');
}
One of the tempTable models doesnt have a Payment and the attributesToArray() method is failing.
Try this and see if it works.
foreach($temp_table_data as $a_payment) {
$payment = $a_payment->payment->first();
if(!is_null($payment)){
$payments[] = $payment->attributesToArray();
}
}
the problem is that in production you have probably changed the data in your database and calling to first() method returns null then you are trying to call attributesToArray() on a null, which is wrong!
you should do a isset() function before calling attributesToArray().
if(isset($a_payment->payment->first()))
array_push($payments, $a_payment->payment->first()->attributesToArray());

laravel 'class not found' error on production

Slightly odd one here.
I have Persons and Actions. Persons can have many Actions, while each Action belongs to only one Person. I'm using Chumper's Datatables to display a list of people, including a count of their actions.
Since migrating to a production (forge) server, I'm getting
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR)
Class 'action' not found
when calling the datatable. The error shown
/­vendor/­laravel/­framework/­src/­Illuminate/­Database/­Eloquent/­Model.php:721
public function hasOne($related, $foreignKey = null, $localKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
suggests it's a problem with my hasMany relationship:
# /models/Person.php
class Person extends Eloquent {
public function actions()
{
return $this->hasMany('Action');
}
# /models/Action.php
class Action extends Eloquent {
public function person()
{
return $this->belongsTo('Person', 'person_id');
}
I assume these are fine, however, as it all works locally. Datatables also works fine elsewhere, calling through other items and their related actions with no trouble.
I've tried composer dump-autoload and artisan dump-autoload on the production server, to no avail. The deployment script on forge is below:
git pull origin master
composer install
php artisan migrate --env=production
I can't tell if it's a config issue, a database issue, a code issue or something else entirely. I've been back through the many similar questions but nothing's jumped out. Any help much appreciated.
for who may have the same problem, triple check the casing of your model! I had it wrong, that's why locally on mac was working but not on the server
So I think I'd borked this one myself.
I'd been lazy and left function datatablePersons() in PersonsController.php using an old 'count' method, relying on long-defunct relationships (that caused n+1, so had to be binned), hence it wobbling over an actions class whenever that relationship was called upon.
Datatable functions in other controllers (with a cleaner 'count' method) work fine, so I've just rewritten datatablePersons() to use the same method.
I've not quite got the query right (in eloquent, at least) yet - see this question here: mysql join ON and AND to laravel eloquent - but the class not found error has certainly gone away.
I'm (massively) guessing that the classmap on the local machine hadn't been flushed since whatever was removed was removed, while the production machine is rebuilt every push, hence the disparity...?
Either way, it's no longer an issue.

"User" model broken after Laravel 4.1 upgrade

I have upgraded Laravel from 4.0 to 4.1 recently in a few instances. Today I did the upgrade in yet another instance and found out that there is something wrong with the User model. The models/User.php file is still there, but I don't think it is used by Laravel anymore. My question is: why?
To demonstrate the issue, I have created the following entries in my routes.php:
Route::get('test1', function()
{
$course = Course::find(4);
return ($course->users()->first());
});
Route::get('test2', function()
{
$user = User::find(22);
return ($user->courses()->first());
});
Both these entries are correct regarding syntax and the database object (course with id 4 exists and user with id 22 exists). My Course.php model has the following:
public function users()
{
return $this->belongsToMany('User')->withPivot('participant_role')->withTimestamps();
}
And my User.php has a corresponding entry:
public function courses()
{
return $this->belongsToMany('Course')->withPivot('participant_role')->withTimestamps();
}
Now if I launch the first URL, /test1, I get a working JSON entry as a result. As expected.
With the second URL, /test2 however I get an error message:
BadMethodCallException
Call to undefined method Illuminate\Database\Query\Builder::courses()
open: /home/simoa/laravelapps/clientname/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php `
I think there is something wrong here. Why is my Laravel instance trying to call the courses() method from the Illuminate\Database\Query\Builder class? That isn't normal, right?
As I said earlier, everything else works perfectly, except things to do with the User model.
The issue was caused by an invalid entry in the file vendor/composer/autoload_classmap.php.
For some reason during the 4.1 upgrade (probably running the command: composer update) the entry for 'User' => $baseDir . '/app/models/User.php' has turned into 'User' => $baseDir . '/app/models/old_User.php' in that file.
I did have an old backup/dev file called old_User.phpin my models directory and for some reason, it seems, composer has mapped User class to that file.
Solution: delete old_User.php and re-run composer update.
try running php artisan clear-compiled and then php artisan optimize

Categories