skip to Main Content

When accessing model attrs inside relation logic in laravel the attrs are all null when eager loading, if lazy loading it works fine.

Model relation :

public function organization()
    {
        return $this->belongsTo(Organization::class, 'organization_id');
    }

public function currentOrder()
{
        
        // Note that this will not work if eager loading the relation
        // for some reason all model's attrs are null when eager loading
        $subscription = $this->organization->currentAdhesionSubscription;

        if ($subscription) {
            return $this->morphOne(Order::class, 'parent')
                ->whereHas('ticketsWithPrice', fn($q) => $q->where('ticket_id', $subscription->ticket_id));
        }
}

If lazy load the relation it works :

$model->load('currentOrder');
$model->currentOrder;

If eager loading it won’t work :

$model = Model::with('currentOrder')->first();
$model->currnetOrder // Error of accessing "currentAdhesionSubscription" on null which is organization which is a relation, but even when I access an attr of the model such as id it returns null when eager loading

Why model attrs are null when being accessed from whithin an eager loaded relation ?

2

Answers


  1. When you do Model::with('currentOrder')->first(), you are not in the scope of a specific model instance, so $this in your relation will be an empty instance of the model you are working with, essentially the same as if you do new Model().

    You should always think in database context when writing relations. So one thing you could do in your case is to manually join the needed tables. In your case, you have plenty of Models/tables involved, so it might also be a good idea to step back and re-think the database structure.

    Login or Signup to reply.
  2. Modify currentOrder Logic for Eager Loading

    Use eager loading to load organization separately and avoid accessing it inside the relation logic:

    public function currentOrder()
    {
        // Remove the direct access to organization in the relation definition
        return $this->morphOne(Order::class, 'parent')
            ->whereHas('ticketsWithPrice', function ($q) {
                // Access ticket_id in a different way during eager loading
                $q->where('ticket_id', function ($query) {
                    $query->select('ticket_id')
                          ->from('subscriptions') // Assume the table name is 'subscriptions'
                          ->where('organization_id', $this->organization_id)
                          ->limit(1);
                });
            });
    }
    

    using this approach, you’re essentially avoiding the need to access the organization relation inside currentOrder.

    Another approach is to Manually Load organization Before currentOrder in Eager Loading by doing this:

    $model = Model::with('organization') // Eager load organization first
        ->with(['currentOrder' => function ($query) {
            $query->with('ticketsWithPrice');
        }])
        ->first();
    
    // Now both `organization` and `currentOrder` should be loaded correctly.
    

    with the approach above, you’re ensuring that the organization relationship is eager loaded before resolving the currentOrder relation.

    Another approach is to preload the currentAdhesionSubscription relation in the same query as organization to ensure it’s available when currentOrder is resolved

    $model = Model::with(['organization.currentAdhesionSubscription', 'currentOrder'])->first();
    

    doing this, ensures that when currentOrder is being resolved, the necessary data from organization is already available.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search