Skip to content
Advertisement

The most efficient way to do eagerload in Laravel Policy for yajra-datatable use

I need to eager load relationship within laravel policy The problem is i use the laravel policy inside yajra-datatable which will load it (the policies) line by line

Here’s the code looks like :

public function create(User $user)
{
    $user->load('sections');
    $sections = collect($user->sections->toArray())->pluck('name');
    
    return
        in_array($user->role_id,[3,4])
        && in_array('Produksi', $sections->toArray())
        && Session::get('productionPlans-branch') !== 'all'
        && Session::get('productionPlans-period') !== 'all';
}

and i use it in my yajra-datatable like so :

public function table(Request $request)
{
    $query = ProductionPlan::with(['branch','product.category','period'])->orderBy('created_at');

    return YajraDataTablesDataTables::of($query)
        ->addIndexColumn()
        ->addColumn('action', function($row) {
            if ($request->user->can('create', $row)) {
                return '<a href="javascript:void(0)" onclick="show('. $row->id .')">Add</a>';
            }
        })
        ->rawColumns(['action'])
        ->make(true);
}

so every line will load the relation again and again

I’m expecting more efficient way to load them just once instead of load the relation line by line How can i achieve this ?

Update :

I tried to use accessor on User model to append the relations with sections table

protected $appends = ['sections'];

public function getSectionsAttribute ()
{
    return $this->attributes['sections'] = $this->sections()->first();
}

This was success for only the FIRST relation only, i tried to remove the first() method but got the error PDO serialization instead

Serialization of 'PDO' is not allowed

Advertisement

Answer

I think Laravel policies uses the exact object it is called on. So $this->user->can(…) actually is the same object that is being passed as first parameter to the create(User $user) policy method.

In that case, I would try to load it before you call the ->can method inside the closure.

The code could look like this:

public function table(Request $request)
{
    $query = ProductionPlan::with(['branch','product.category','period'])->orderBy('created_at');
    $user = $request->user;
    $user->load('sections');

    return YajraDataTablesDataTables::of($query)
        ->addIndexColumn()
        ->addColumn('action', function($row) use ($user) {
            if ($user->can('create', $row)) {
                return '<a href="javascript:void(0)" onclick="show('. $row->id .')">Add</a>';
            }
        })
        ->rawColumns(['action'])
        ->make(true);
}

And then you also have to remember to remove the $user->load('sections'); from inside the create() method in the policy. This is very important 🙂

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement