Search code examples
phplaraveleloquentlaravel-5.5

Laravel query builder get custom attribute


I'm trying to get a custom attribute (https://laravel.com/docs/5.5/eloquent-mutators#defining-an-accessor) from a query.

Right now I have:

User.php

public function getViewUrlAttribute()
{
    return route('admin.users.view', ['id' => $this->id]);
}

public function role()
{
    return $this->belongsTo('App\Role')->withDefault([
        'name' => 'User'
    ]);
}

UserController.php

public function dataTable(Request $request)
{
    $length = $request->has('length') ? $request->input('length') : 10;
    $orderDirection = $request->input('orderDirection');
    $searchValue = $request->input('search');

    $users = User::select('id', 'name', 'email', 'created_at')->with('role:name')->limit($length);

    if ($request->has('orderBy')) {
        if ($request->has('orderDirection')) {
            $users = $users->orderBy($request->input('orderBy'), $request->input('orderDirection') > 0 ? 'asc' : 'desc');
        } else {
            $users = $users->orderBy($request->input('orderBy'), 'desc');
        }
    }

    return $users->get();
}

Returns

[
 {
  "id": 1,
  "name": "User",
  "email": "[email protected]",
  "created_at": "2018-04-24 14:14:12",
  "role": {
   "name": "User"
  }
 }
]

So the thing is: there's any way to also get the view_url attribute? (I tried inside the with() but it fails)

Also can I return only the role name and not the whole object as you can see in the "Return" code? (I would like something like: "role": "User").

(Of course I'm trying to avoid running raw sql)

Thanks!


Solution

  • You're almost done...

    1- To add a custom attribute you need to append it on the Model with $appends attribute:

    protected $appends = ['view_url'];
    

    And define your attribute method:

    public function getViewUrlAttribute()
    {
        return route('admin.users.view', ['id' => $this->id]);
    }
    

    2- To add attribute to a model from another related model, I think you should try :

    // to add them as attribute automatically
    protected $appends = ['view_url', 'role_name'];
    
    // to hide attributes or relations from json/array
    protected $hidden = ['role']; // hide the role relation
    
    public function getRoleNameAttribute()
    {
        // if relation is not loaded yet, load it first in case you don't use eager loading
        if ( ! array_key_exists('role', $this->relations)) 
            $this->load('role');
    
        $role = $this->getRelation('role');
    
        // then return the name directly
        return $role->name;
    }
    

    Then you might not event need ->with('role') eager loading.