Nika Kurashvili
Nika Kurashvili

Reputation: 6472

Laravel filter data after with closure

I have one quite simple question, Imagine I have Orders model and now I am writing something like that :

Order::where('status', 1)->with('orderer')->get();

Ok. It's simple and returns something like that:

 {
      id: 1,
      price: 200,
      status: 1,
      income: 21,
      orderer_id: 4,
      orderer: {
        //some orderer fields
      }
  }

now I don't want to get the whole object, I want to remove income, orderer_id and status properties from data. if I write something like that : get(["id", "price"]) I end up without orderer object (get(["id", "price", "orderer"]) doesn't work too), I couldn't make it work even using select(), so what is the solution? Also I don't want to hide it from everyone, for example admin should know income but user shouldn't, so $hidden field will not work.

Upvotes: 0

Views: 593

Answers (3)

Mihir Bhende
Mihir Bhende

Reputation: 9055

You can add select() but make sure select does not take array but comma separated arguments :

$orders = Order::where('status', 1)->with('orderer');

if($user->role == 'admin'){
   $orders->select('id','income','status','price');
}
else{
   $orders->select('id','status','price');
}

$orders = $orders->get();

Above will first check the current logged in user's role and accordingly will select the columns required.

Upvotes: 2

Jason bamber
Jason bamber

Reputation: 459

If you are looking for a built in Laravel way to handle this, you could use API Resources: https://laravel.com/docs/5.7/eloquent-resources

php atrisan make:resource OrderResource

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class OrderResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        $current_role = $request->user()->role; //or however you determine admin etc

        $out = [
            'id'    => $this->id,
            'price' => $this->price,
            'orderer'=> $this->orderer,
        ];

        if($current_role == 'admin'){

            $out['income'] = $this->income;
            $out['status'] = $this->status;

        }
        return $out;
    }
}

In your Controller action

return OrderResource::collection(Order::where('status', 1)->with('orderer')->get());

If you want something a little more robust, consider https://github.com/spatie/laravel-fractal

Upvotes: 0

sietse85
sietse85

Reputation: 1506

https://scotch.io/bar-talk/hiding-fields-when-querying-laravel-eloquent-models

In your Order Eloquent model:

protected $hidden = array('hide_this_field', 'and_that_field');

Edit: You want to filter based on role like Admin or User, next time please write that down in your question as well. Well a solution for that is to capture the DB query result, and walk that array, then unset properties of the model if the user is not an admin.

Edit2: I also see a discussion here which might help. Some user suggested using middle ware: https://laracasts.com/discuss/channels/laravel/hide-eloquent-fields-based-on-user-role-or-any-model

Upvotes: 0

Related Questions