Vladislav Dimitrov
Vladislav Dimitrov

Reputation: 127

Laravel 5 Eager Loading with parameters

I'm working on a project with a bit of a complex model that has joins in its relations and also requires a parameter. It all works pretty well, except for when I need to eager load the relationship, as I couldn't figure out if there is a way to pass a parameter/variable to it.

The Controller

$template = Template::find($request->input('id'));
$this->output = $template->zones()->with('widgets_with_selected')->get();

The Model

public function widgets_with_selected($banner_id)
{
return $this->belongsToMany('App\Models\Widget', 'zone_has_widgets')
    ->leftJoin('banner_has_widgets', function($join) use($banner_id) {
        $join->on('widgets.id', '=', 'banner_has_widgets.widget_id')
            ->where('banner_has_widgets.banner_id', '=', $banner_id);
    })
    ->select('widgets.*', 'banner_has_widgets.banner_id');
}

This is returning a Missing argument error as the variable is not being passed.

I have resolved the issue by moving the logic to the controller, but I want to know if there is a way to keep the relationship in the model and just call it with a parameter.

Upvotes: 2

Views: 1745

Answers (1)

Cor Bosman
Cor Bosman

Reputation: 336

Looking at the laravel code I dont think this is possible as you'd like to do it. You simply cant pass parameters to a with() call.

A possible workaround is to have an attribute on your model for $banner_id.

$template = Template::find($request->input('id'));
$template->banner_id = 1;
$this->output = $template->zones()->with('widgets_with_selected')->get();

Then change your relationship

public function widgets_with_selected()
{
    return $this>belongsToMany('App\Models\Widget','zone_has_widgets')
          ->leftJoin('banner_has_widgets', function($join) use($this->banner_id) {
               $join->on('widgets.id', '=', 'banner_has_widgets.widget_id')
              ->where('banner_has_widgets.banner_id', '=', $banner_id);
            })
          ->select('widgets.*', 'banner_has_widgets.banner_id');

}

You could perhaps alter it a bit by passing the banner_id through a method. Sortof like this in your model:

public function setBanner($id) {
    $this->banner_id = $id;
    return $this;
}

Then you can do:

$template->setBanner($banner_id)->zones()->with('widgets_with_selected')->get();

Not sure if this works, and it's not really a clean solution but a hack.

Upvotes: 3

Related Questions