belongsToMany on not primary field - php

For example i have 4 tables:
buildings
id, title, ...
rooms
id, building_id, title, ...
companies
id, title, ...
companies_to_buildings
company_id, building_id
and i want to get companies from the room model.
From building model i can do something like
class Building extends Model
{
public function companies(){
return $this->belongsToMany('App\Company', 'company_building');
}
}
or
class Building extends Model
{
public function companies(){
return $this->belongsToMany('App\Company', 'company_building', 'building_id', 'company_id');
}
}
but if i do this in room model, it would not work. it will try to find rows in companies_to_buildings table where companies_to_buildings.building_id=room.id. how can i get companies from the room model?

You can make use of hasManyThrough
Example:
public function series()
{
return $this->hasManyThrough('Series', 'Product');
}

Related

Many to Many Relation with custom pivot table

I have 4 tables in project's database:
users (id, name)
teams (id, name)
team_members (id, user_id, team_id)
team_member_permissions (team_member_id, team_id)
I need to get user's teams. My current solution is to create teamMembers relationship in User model:
public function teamMembers()
{
return $this->hasMany(TeamMember::class);
}
members relationship in Team model:
public function members()
{
return $this->hasMany(TeamMember::class);
}
permissions relationship in TeamMember model:
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
But how can I optimise it? For example, to get all teams for users I need to use
Team::whereHas('teamMember', function($query) use ($user){
$query->where('user_id', $user->id);
})->paginate();
But how can I implement a relationship that will contains all user's teams to get user's teams in one string of code, like $user->teams?
I suggest you use many to many relation in regards to your team_members tables to explicitly mention as pivot.
User model:
public function teams()
{
return $this->belongsToMany(Team::class, 'team_members');
}
Team model:
public function users()
{
return $this->belongsToMany(User::class, 'team_members');
}
Since you want to use whereHas clause on teamMember table, I believe that you want to extract teams based on the fact that all teams belonging to that user based on team_members table.
So, You can specify the table name on many to many relation as above.
Now you can use
$user->teams

Laravel relationship between three tables

I have 3 tables:
Events
Ages
Books
Which I was relating them in the following way:
ages
id
name
books
id
title
age_book
id
age_id
book_id
events
id
name
event_age
id
event_id
age_id
event_age_book
event_age_id
book_id
Basically, a book can have many ages, an age can have many books, an event can have many ages, an event age can have many books.
My Event Model looks like this and works fine to get all event ages
class Event extends Model
{
public function ages()
{
return $this->belongsToMany(Age::class, 'event_age');
}
}
Age Model:
class Age extends Model
{
public function books(): BelongsToMany
{
return $this
->belongsToMany(Book::class)
->withTimestamps();
}
}
Book Model
class Book extends Model
{
public function ages(): BelongsToMany
{
return $this
->belongsToMany(Age::class, 'book_age', 'book_id','age_id')
->withTimestamps();
}
}
Im having trouble figuring out how to get all edition age books, is it possible to do it on the Event model?
Let's Review The Relationships
Seems you should only need 3 models, and 5 tables.
Books Belong to Ages
Events Belong to Ages
Ages Belongs to Books
Ages Belongs to Events
Your other models are alright, but your age model is missing a relationship to Event:
class Age extends Model
{
public function books(): BelongsToMany
{
return $this->belongsToMany(Book::class)
->withTimestamps();
}
public function events(): BelongsToMany
{
return $this->belongsToMany(Events::class,'event_age')
->withTimestamps();
}
}
That would allow:
$books->ages;
$events->ages;
$ages->book;
$ages->events;
And chaining...
$books = collect();
foreach($event->ages as $age){
$books->merge($ages->books);
}
$books->unique();
Books and Events
So, I gon't think you want age_event_books. I think what you really want is:
Events belong to Books
Books belong to Events
such that
book_events
- id
- book_id
- event_id
- age_id
And you'd have in book:
public function events()
{
return $this->BelongsToMany('App\Event')
->withTimestamps()
->withPivot('age_id');
}
And in event:
public function books()
{
return $this->belongsToMany('App\Book')->withTimestamps()
->withPiviot('age_id')->groupBy('age_id');
}
Giving you:
$event->books
$book->events
On the Front End
[O]n the frontend i'll need to get the most recent event and group books by age and books can belong to more than one age
$event = Event::latest();
$books = $event->books();
Then on the blade
#foreach($books as $age_id => $books)
<h4>{{Age::find($age_id)->name}}</h4>
#foreach($books as $book)
<div>$book->name</div>
#endforeach
#endforeach
Helpful Tip
You are supplying the relation table, which you have to do because you didn't follow the naming convention for joining tables. The convention is that the classes being joined should be listed alphabetically. So age_event instead of event_age.

Relation with pivot table

I've three tables and I would like to use pivot table data when getting results.
These tables are products, store, store_products, cart_items and their fields are below:
products (id, name, price)
store (id, name etc.)
store_products (store_id, product_id, store_price, store_slug)
cart_items (id, user_id, product_id, store_id, quantity)
My CartItem model is like
class CartItem extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
public function store()
{
return $this->belongsTo('App\Store');
}
}
When I call CartItem::with('product')->get(), I would like it to return product data (from product table and store_price, store_slug from store_products) with matching cart_items.store_id and cart_items.product_id from pivot table "store_products".
How can I create this relation by on my CartItem model? If possible, by just using Eloquent ORM functions instead of query builder or raw queries.
In products Model add,
public function stores(){
return $this->belongsToMany(Store::class)->withPivot('store_price', 'store_slug');
}
In Store Model add,
public function products(){
return $this->belongsToMany(Products::class)->withPivot('store_price', 'store_slug');
}
Then call,
CartItem::with(['product.stores'])->get();
For more explanation read this article:
http://laraveldaily.com/pivot-tables-and-many-to-many-relationships/

Laravel eloquent relationship fetch records upto third level of relationship

I have users table which has a hasOne relationship with vendordetails table.
class User extends Authenticatable
{
public function vendor_details() {
return $this->hasOne('App\Vendordetail');
}
}
On the other side vendordetails table contains country_id, state_id and city_id and has relationship of belongsTo with Country, State and City model.
Vendordetail.php model is:-
class Vendordetail extends Model
{
public $timestamps = false;
public function this_country(){
return $this->belongsTo('App\Country', 'country_id');
}
public function this_state(){
return $this->belongsTo('App\Country', 'state_id');
}
public function this_city(){
return $this->belongsTo('App\Country', 'city_id');
}
}
How can i fetch records of country, state and city if i query on users table.
$user = User::with('vendor_details')->first();
In this query it only finds the result of vendordetails table, i also wants country, state and city.
Thanks
To access nested relationship
$user = User::with(['vendor_details.this_state','vendor_details.this_country','vendor_details.this_city'])->first();

Laravel 5 eloquent include the row of the other table from the foreign key of the 2nd joined table

I have 3 sample models
customer
id
order
id
customer_id
deliver_address_id
customer_address
id
customer_id
street
country
A customer can save many addresses on his profile but he can only choose one address per order.
I would like to get all customer orders including the address in one query using laravel 5 eloquent. I'm new in laravel so having difficulty to query complex relationship tables.
class Customer extends Model {
$table = 'customers';
function addresses(){
return $this->hasMany(Address::class, 'customer_id');
}
function orders(){
return $this->hasMany(Order::class, 'customer_id');
}
}
class Order extends Model {
$table = 'orders';
function address(){
return $this->belongsTo(Address::class, 'address_id');
}
function customer() {
return $this->belongsTo(Customer::class, 'customer_id');
}
}
class Address extends Model{
$table = 'customer_addresses';
function customer(){
return $this->belongsTo(Customer::class, 'customer_id');
}
}
TABLES :
1 customers
id
2 orders
id
customer_id
address_id
3 customer_addresses
id
customer_id
street
country

Categories