rst630
rst630

Reputation: 89

How to create relationship between 3 models in laravel?

SQL scheme:

bulletins

  id increment

deals

  id increment
  seller_id
  buyer_id

deals_items - items = bulletins

  id increment
  title
  desc
  bulletin_id
  deal_id

How can I get deal row by bulletin id? In raw SQL it looks like:

select `deals`.* from `deals` inner join `deals_items` on `deals_items`.`deal_id` = `deals`.`id` where `deals_items`.`bulletin_id` = 10572

I tried:

public function deals()
{
    return $this->hasManyThrough(DealItem::class,Deal::class, 'bulletin_id','dealid','id');
}

But it seems a wrong way. Can't find right way in laravel doc about relation.

@HCK shows right way.

but when I doing $bulletin->deals() in blade template I got empty collection of deals.

When just $bulletin->deal - all is fine, we have collection of deals.

I using protected $with = ['deals'] in my bulletin model, but what is different call method or property? Why with method empty result?

Upvotes: 0

Views: 88

Answers (3)

Jyoti Rani
Jyoti Rani

Reputation: 11

deals model -

public function bulletins()
    return $this->belongsToMany(Bulletin::class, 'deals_items ', 'bulletin_id', 'deal_id');
}

bulletin model:-

public function deals()
{
    return $this
        ->belongsToMany(Deal::class, 'deals_items',  'deal_id', 'bulletin_id',);
}

Upvotes: 1

Kenny Horna
Kenny Horna

Reputation: 14241

@Amarnasan was close, but the order of the foreign keys was wrong. Try this:

Deal.php

public function bulletins()
{
    return $this
        ->belongsToMany(Bulletin::class, 'deals_items', 'deal_id', 'bulletin_id')
        ->withPivot('title','desc');
}

Bulletin.php

public function deals()
{
    return $this
        ->belongsToMany(Deal::class, 'deals_items', 'bulletin_id', 'deal_id')
        ->withPivot('title','desc');
}

From the docs:

As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the belongsToMany method:

return $this->belongsToMany('App\Role', 'role_user');

In addition to customizing the name of the joining table, you may also customize the column names of the keys on the table by passing additional arguments to the belongsToMany method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to:

return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');

Update

When you access the relationship as a method: $bulletin->deals() you are accessing the relationship itself. This will return an instance of \Illuminate\Database\Eloquent\Relations\BelongsToMany (in your case). Here the query is not executed yet, so you could keep adding constrains to your query, for example:

$bulletin
    ->deals()
    ->where('seller_id', 45) // <---
    ->skip(5) // <---
    -> ... (And so on)

When you access it as a dynamic property, you are already executing the query, so this will return a Collection instance. Is the same as calling the relationship as a method and then attach the ->get() at the end, so this two are equivalent:

$bulletin->deals()->get()
// equals to:
$bulletin->deals

Check this other answer, it answers your question.

Upvotes: 1

Amarnasan
Amarnasan

Reputation: 15529

DealClass:

public function bulletins()
    return $this->belongsToMany('App\Bulletin', 'deals_items ', 'bulletin_id', 'deal_id')->withPivot('title','desc');
}

BulletinClass:

public function deals()
    return $this->belongsToMany('App\Deal', 'deals_items ', 'deal_id', 'bulletin_id')->withPivot('title','desc');
}

Upvotes: 1

Related Questions