Laravel Model is freezing the server. Timeout error

1.5k Views Asked by At

I'm having a really strange issue here. I have a user model (detailed below).

It all works fine until I added the getReportsSharedAttribute function. When this is added, the server freezes and I get:

 PHP Fatal error:  Maximum execution time of 60 seconds exceeded in C:\Users\User\PhpstormProjects\laravel-vue\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasRelationships.php on line 637

more:

exception: "Symfony\\Component\\ErrorHandler\\Error\\FatalError"
file: "C:\\Users\\User\\PhpstormProjects\\laravel-vue\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Concerns\\HasAttributes.php"

I thought there was something up with the code, so I ran it manually in a controller and dumped it, it worked fine.

So I tried it as a relation instead of an attribute. Same error.

So then I thought, is it just specific to the ReportingSetAssigned model, so I did another query on another collection, and another, and I still get the timeout error.

I tried another Model, it worked fine, for no apparent reason. Even though there were a lot more records inside. It doesn't seem to be dependant on how many columns are involved in the return. None of my tables have more than 50 records inside, even in the relations.

What's going on here? Is there some limit somewhere?

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\HasApiTokens;
use stdClass;
use Illuminate\Database\Eloquent\SoftDeletes;



class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, SoftDeletes;
    public $appends = [
        'full_name',
        'profile_photo_thumb',
        'permissions_alt',
        'line_managed_only_id',
        'line_managers_only_id',
        'permissions_meetings_only_id',
        'reports_shared',
    ];

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    protected $dates = ['deleted_at'];

    public function permissions(){
        return $this->belongsToMany(Permission::class);
    }

    public function timelineitems(){
        return $this->hasMany(TimelineItem::class);
    }

    public function line_managers(){
        return $this->belongsToMany(User::class,'permissions_lm','user_id','lm_id');
    }

    public function line_managed(){
        return $this->belongsToMany(User::class,'permissions_lm','lm_id','user_id');
    }

    public function permissions_meetings(){
        return $this->belongsToMany(Area::class,'permissions_meetings','user_id','area_id')->withPivot('level');
    }

    public function getPermissionsMeetingsOnlyIdAttribute(){
        return $this->permissions_meetings()->pluck('permissions_meetings.area_id');
    }

    public function permissions_qed(){
        return $this->belongsToMany(Area::class,'permissions_qed','user_id','area_id')->withPivot('level');
    }

    public function permissions_reporting(){
        return $this->belongsToMany(Area::class,'permissions_reporting','user_id','area_id')->withPivot('level');
    }

    public function permissions_reporting_sets(){
        return $this->belongsToMany(ReportingSet::class,'permissions_reporting_sets','user_id','set_id')->withPivot('level');
    }

    public function improvement_category_objective_action_milestones(){
        return $this->belongsToMany(ImprovementSetCategoryObjectiveActionMilestone::class);
    }

    public function planning_review_forms(){
        return $this->hasMany(PerformanceManagementSetAssigned::class)->whereHas('set', function($q) {
            $q->where('appraisal', 0);
        });
    }

    public function appraisal_forms(){
        return $this->hasMany(PerformanceManagementSetAssigned::class)->whereHas('set', function($q) {
            $q->where('appraisal', 1);
        });
    }

    public function performance_manager_set_as_lm(){
        return $this->belongsTo(PerformanceManagementSetAssigned::class, 'lm_id');
    }

    public function getPermissionsAttribute(){
        return $this->permissions()->get();
    }

    public function getLineManagersOnlyIdAttribute(){
        return $this->line_managers()->pluck('permissions_lm.lm_id');
    }

    public function getLineManagedOnlyIdAttribute(){
        return $this->line_managed()->pluck('permissions_lm.user_id');
    }

    public function hasPermissionTo($permission){
        if(auth()->user()->super_admin){
            return true;
        }
        if($permission==='super_admin'&&auth()->user()->super_admin){
            return true;
        }
        if(!is_array($permission)){
            $access = $this->permissions()->where('permission', $permission)->exists();
            if($access){
                return true;
            }
            return false;
        }else{
            foreach($permission as $p){
                $access = $this->permissions()->where('permission', $permission)->exists();
                if($access){
                    return true;
                }
            }
        }
    }

    public function checkPermissionReportingSet($permission){
        $access = $this->permissions_reporting_sets()->where('set_id', $permission)->first();
        if($access){
            if($access->pivot->level=='read'){
                return 'read';
            }
            if($access->pivot->level=='write'){
                return 'write';
            }
        }
    }

    public function checkPermissionReportingArea($permission){
        $access = $this->permissions_reporting()->where('area_id', $permission)->first();
        if($access){
            if($access->pivot->level=='true'){
                return true;
            }
        }
    }

    public function truePermission($permission){
        $access = $this->permissions()->where('permission', $permission)->exists();
        if($access){
            return true;
        }
    }

    public function updateTimeline($type_main,$type_sub,$title,$content,$icon,$color,$link,$relevant_id = null,$user_id = null){
        if(!$user_id){
            $user_id = $this->id;
        }

        $t = new TimelineItem();
        $t->type_main = $type_main;
        $t->type_sub = $type_sub;
        $t->title = $title;
        $t->content = $content;
        $t->icon = $icon;
        $t->color = $color;
        $t->link = $link;
        $t->user_id = $user_id;
        $t->relevant_id = $relevant_id;

        $t->save();
    }
    public function getPermissionsForVueAttribute(){
        $permissions = $this->permissions;
        $new = [];
        foreach($permissions as $p){
            $new[$p->permission] = true;
        }

        $new['meeting_areas'] = [];
        $permissions = $this->permissions_meetings;
        foreach($permissions as $p){
            $new['meeting_areas'][$p->id] = $p->pivot->level;
        }

        $new['qed_areas'] = [];
        $permissions = $this->permissions_qed;
        foreach($permissions as $p){
            $new['qed_areas'][$p->id] = $p->pivot->level;
        }

        $new['reporting_areas'] = [];
        $permissions = $this->permissions_reporting;
        foreach($permissions as $p){
            $new['reporting_areas'][$p->id] = $p->pivot->level;
        }

        $new['reporting_sets'] = [];
        $permissions = $this->permissions_reporting_sets;
        foreach($permissions as $p){
            $new['reporting_sets'][$p->id] = $p->pivot->level;
        }

        return json_encode($new);
    }
    public function getPermissionsAltAttribute(){
        //General permissions
        $permissions = Permission::get();
        $newP = [];
        foreach($permissions as $p){
            $newP[$p->permission] = false;
        }

        $permissions = $this->permissions;
        foreach($permissions as $p){
            $newP[$p->permission] = true;
        }

        $newP['meeting_areas'] = [];
        $newP['qed_areas'] = [];
        $newP['reporting_areas'] = [];
        $newP['reporting_sets'] = [];

        foreach(Area::orderBy('name', 'ASC')->get() as $p){
            $newP['meeting_areas'][$p->id] = "false";
            $newP['qed_areas'][$p->id] = "false";
            $newP['reporting_areas'][$p->id] = "false";
        }

        $meetings = DB::table('permissions_meetings')->where('user_id', '=', $this->id)->get();
        foreach($meetings as $p){
            $newP['meeting_areas'][$p->area_id] = $p->level;
        }
        $qed = DB::table('permissions_qed')->where('user_id', '=', $this->id)->get();
        foreach($qed as $p){
            $newP['qed_areas'][$p->area_id] = $p->level;
        }
        $reporting = DB::table('permissions_reporting')->where('user_id', '=', $this->id)->get();
        foreach($reporting as $p){
            $newP['reporting_areas'][$p->area_id] = $p->level;
        }

        foreach(ReportingSet::orderBy('name', 'ASC')->get() as $p){
            $newP['reporting_sets'][$p->id] = "false";
        }

        $reporting = DB::table('permissions_reporting_sets')->where('user_id', '=', $this->id)->get();
        foreach($reporting as $p){
            $newP['reporting_sets'][$p->set_id] = $p->level;
        }

        return $newP;
    }
    public function getCyclesAttribute(){
        return Cycle::orderBy('id')->get();
    }
    public function getFullNameAttribute(){
        return $this->first_name . " " . $this->last_name;
    }
    public function getProfilePhotoThumbAttribute(){
        if($this->profile_photo){ return "THUMB-" . $this->profile_photo; }else{ return "no-avatar.png"; }
    }
    public function getReportsSharedAttribute(){
        return ReportingSet::where('observee_id', $this->id)->where('observee_share', 1)->where('published', 1)->without('set.modules')->get()->toArray();
    }

    public function canLineManage($id){
        if($this->super_admin==1) return true;
        foreach($this->line_managed as $lm){
            if($lm->id==$id){
                return true;
            }
        }
    }

}

EDIT: If I run this code in a controller, it does't hang at all. It loads up the data in less than a second EDIT: Restarted computer, still happening

1

There are 1 best solutions below

5
On

This looks a lot like an infinitive call-loop, please refer to this on github issue Allowed Memory size exhaused when accessing undefined index in toArray

You are just running out of memory when calling parent::toArray(). You either need to reduce the amount of items in your collection or increase your allowed memory allocation.