Sumsar
Sumsar

Reputation: 134

Laravel appending accessor unexpectedly also add relationship to response

Thank you for taking time to help me understand this issue.

I have a 'Vehicle' class like the following: (to keep i simple i removed alot of methods and fillables)

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

use App\Trip;

class Vehicle extends Model
{
    public $fillable = [
       ...
    ];

    protected $appends = [
        'LastTrip'
    ];

    public function trips()
    {
        return $this->hasMany(Trip::class);
    }

    public function getLastTripAttribute()
    {
        return $this->trips->last();
    }
}

The issue is that when i return a instance of this class from a controller. It serializes the 'trips' relationship, so that every trip is in my response.

This however only happens when i try to append the 'LastTrip' accessor. If I change it to the following, the issue doesn't persist

protected $appends = [
    #'LastTrip'
];

I'm only trying to get it to serialize the 'LastTrip' accessor.

I hope i made my issue clear, and please let me know if i can apply any futhere information.

Thanks for helping.

Upvotes: 2

Views: 134

Answers (2)

IGP
IGP

Reputation: 15786

This happens because your accessor does the following:

  1. Load the full trips relationship
  2. set the last item from the trips collection as last_trip attribute.

Change your code to the following:

public function getLastTripAttribute()
{
    // If the relation is already loaded, avoid doing an extra SQL query
    if ($this->relationLoaded('trips')) {
        return $this->trips->last();
    // Otherwise, get the last trip from an SQL query.
    } else {
        return $this->trips()->orderByDesc('id')->first();
    }
}

Upvotes: 3

Ruben Danielyan
Ruben Danielyan

Reputation: 768

EDITED:

When you call $this->trips->last() it fetches all trips and then assigns the last to LastTrip. But if you use parentheses after 'trips' it has to get only 1 row from db, try this:

public function getLastTripAttribute()
{
    return $this->trips()->latest()->first();
}

or

public function getLastTripAttribute()
{
    return $this->trips()->orderByDesc('id')->first();
}

Upvotes: 2

Related Questions