phplaraveleloquent

Eloquent model producing infinite loops with any queries


I have a Model with a protected $withCount property, and it always gets into an infinite loop. If remove that property, the model will return data. The project I am working in has another Model using $withCount and it returns the child object count fine. I've combed through the working model and compared it with mine, and as far as I can tell I have set everything up correctly. Any idea (or hints to chase down) why this would always get an infinite loop?

<?php

namespace App\Models;


use DateTime;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * @property Team team
 * @property string name
 * @property string notes
 * @property HasMany<ShiftAssignment> shiftAssignments
 * @property DateTime created_at
 * @property DateTime modified_at
 * @property DateTime deleted_at
 *
 * @method static where(string $string, mixed $id)
 */
class Calendar extends Model
{
    use SoftDeletes;

    /**
     * @return BelongsTo<Team> Get the team for the Calendar
     */
    public function team(): BelongsTo {
        return $this->belongsTo(Team::class);
    }

    /**
     * @return HasMany Get all the relationships for the calendar.
     */
    public function shiftAssignments(): HasMany {
        return $this->hasMany(ShiftAssignment::class);
    }

    /**
     * If we want any relationship counts to be return automatically, add them here.
     */
    protected $withCount = [
        'shift_assignments'
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'created_at' => 'datetime:Y-m-dTh:i:sZ',
            'modified_at' => 'datetime:Y-m-dTh:i:sZ',
            'deleted_at' => 'datetime:Y-m-dTh:i:sZ',
        ];
    }
}

These both produce an infinite loops:

Calendar::with('team_id', $team->id);
Calendar::all();

Solution

  • Laravel is case-sensitive. Change the $withCount property to:

    protected $withCount = [
        'shiftAssignments'
    ];
    

    If ShiftAssignment has a relationship back to Calendar, it could create a circular reference. Check if there’s a relationship in ShiftAssignment that references Calendar and ensure it’s not causing a loop.

    The way you are using Calendar::with('team_id', $team->id); seems incorrect. The with() method is used for eager loading relationships, and it should reference the relationship name, not the foreign key. Instead, use:

    Calendar::with('team')->where('team_id', $team->id)->get();
    

    Start with simple query Calendar::all(); and gradually add complexity. Then add the withCount and check for issues.

    Use dd() to check the output of your queries:

    dd(Calendar::withCount('shiftAssignments')->get());