简体   繁体   中英

Laravel 5 Eloquent appending relationships to JSON on multiple levels

So it is pretty easy to include relationships on models such as:

class User extends Model {
     protected $with=['roles']
}

class Role extends Model {
     protected $with=['permissions']
}

when there's a get request to the user resource, it will include associated roles automagically.

But in this setup, the role resources returned with user resource also includes it's own included relationships like:

{user:{id:1, roles:[{id:1, permissions:[{id:1..

This generates huge objects, that mostly include unnecessary related child models.

I can workaround this by setting attributes to replace the default relationship includes but the API i am working on has 30+ resources and that path isn't the ideal beause it will require me to write a lot of repeated code on models.

is there a way to manage the depth of appended relationships easily?

i imagine something like:

class Role extends Model {
     protected $with=['permissions'];
     protected $includeWith=[]; // role wont have the permissions appended when included
}

If somebody is still interested in a solution for this: Laravel 5.5 introduced Api Resources which is a great way to organize the api responses. Just don't include any relationships on your model and append them on the resource.

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class UserResource extends Resource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
            'roles'=> $this->roles

        ];
    }
}

Instead of the built-in '$with' array, you could roll your own attribute using $appends:

class User extends Model
{
    protected $appends = ['roles_list'];

    // ...
    // other stuff here, like relationship definitions
    // ...

    public function getRolesListAttribute()
    {
        return $this->roles;
        //OR build 'roles_list' manually, returning whatever you like.
    }
}

The only downside is you have to look out for 'roles_list' instead of 'roles', on the receiving end.

If the object sizes and memory usage is becoming a problem then you just have to leave the with off in some cases.

Other code itself does not need to change but more queries will be made in total. Where needed you can do explicit eager or lazy eager loading.

If you have already declared relationship & you wants to append that relationship data then you can do it like this below example

class User extends Model
{
    /* your other code */

    /**
      * The accessors to append to the model's array form.
      *
      * @var array
      */
    protected $appends = [
        'company_list',
    ];

    // ...
    // other stuff here, like relationship definitions
    // ...

    /**
     * Get the Companies List with User Id.
     *
     * @return array
     */
     public function getCompanyListAttribute()
     {
        return $this->company()->get();
     }

     /**
      * Get the company for the user.
      * 
      * one-to-many relationship
      */
     public function Company()
     {
         return $this->hasMany(CompanyList::class, 'company_owner_id');
     }
}

now, it will append companies details with User details array

for example I get user details using user id like this

 echo User::find(2);

then it will returns array like below

Array ( [id] => 2 [name] => Merritt Roob [email] => kerluke.mariano@example.net [email_verified_at] => 2021-12-07T08:34:43.000000Z [contact] => [profile_photo_path] => [created_at] => 2021-12-07T08:34:43.000000Z [updated_at] => 2021-12-07T08:34:43.000000Z [company_list] => Array ( [0] => Array ( [id] => 1 [company_name] => Prof. Dorcas Strosin II [company_email] => paxton91@example.com [company_contact] => 1-986-702-4140 [company_owner_id] => 2 [created_at] => 2021-12-07T08:34:43.000000Z [updated_at] => 2021-12-07T08:34:43.000000Z ) ) )

I hope this above example is helps to others Thanks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM