Home > Enterprise >  Laravel BelongsTo relation - where on instance attribute
Laravel BelongsTo relation - where on instance attribute

Time:11-25

I have the following model:

class Order extends Model
{
  public function user(): BelongsTo
  {
    return $this->belongsTo(User::class, 'shipping_email_address', 'email_address')
                ->where('customer_id', $this->customer_id);
  }
}

Now when I call Order::with('user')->get(), it doesn't load the users.

I can access the user just fine when using Order::first()->user.

Is it possible to eager load a relationship with a where clause on a model instance attribute (like $this->customer_id)? Or is there another way to make a relationship based on two columns?

CodePudding user response:

You can do this :

Your relation :

 public function user()
  {
    return $this->belongsTo(User::class);
  }

Then you can make query like this :

$userId = 5;
$result = Order::whereHas('user',function($q) use ($userId){
  return $q->where('id',$userId);
});

Reply to your comment:

Having this relation :

 public function user()
  {
    return $this->belongsTo(User::class);
  }

Use this :

Order::with('user')->get()

This will retrieve all orders with its users. If you have some problem on that query then you have a wrong relationship. Make sure you have a foregin key in Orders table, if you dont espcify some foreign key on eloquent relationship, eloquent will understand than foreign key is : user_id, if not, especify putting more arguments to this function :

$this->belongsTo(User::class,...,...);

With function make join according to relationship configuration, just make sure the relation is ok. And all work fine !

CodePudding user response:

If you want to keep your current flow, i would do it like so. Thou the josanangel solution is most optimal.

When getting orders include them using with. All these are now eager loaded.

$orders = Order::with('user');

Now utilize eloquent getters to filter the user by customer_id. This is not done in queries, as that would produce one query per attribute access.

public function getUserByCustomerAttribute() {
    if ($this->user->customer_id === $this->customer_id) {
        return $this->user;
    }

    return null;
}

Simply accessing the eloquent getter, would trigger your custom logic and make what you are trying to do possible.

$orders = Order::with('user');

foreach ($orders as $order) {
    $order->user_by_customer; // return user if customer id is same
}

CodePudding user response:

Your wrong decleration of the relationship here is what is making this not function correctly. From the laravel's documentation:

Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the parent model's primary key column. So, in this example, Eloquent will assume the Post model's foreign key on the comments table is post_id.

in your case the problem is that laravel is searching for the User using user_id column so the correct way to declare the relation is

public function user()
  {
    return $this->belongsTo(User::class, 'customer_id'); // tell laravel to search the user using this column in the Order's table.
  }

Everthing should work as intended after that.
Source: documentation

  • Related