How to compact two relationship in one relationship - laravel

I have some issue when I wanna compact two relationships in Laravel.
There were 3 tables with model.
table1: episodes --> model: Episode
relations -- hasMany --> posts
-- belongsToMany --> users
pivot-table2: posts --> model: Post
columns -- episode_id
-- user_id
relations -- belongsTo --> user
-- belongsTo --> episode
table3: users --> model: User
Yes, It was a many-to-many relationship. We could get posts or users relationships on Episode model.
If I have a single model collection
$episode = new App\Episode
How could it eager load like
$episodes = new App\Episode::with('posts.user').
Maybe I could do like below
$episode = new App\Episode::with('posts.user')->where('id','=','targetId')
But It seems like would first join three tables then make a query to get target episode.
Is there any way works like
$episode = new App\Episode::find(targetId)-> with('posts.user')

If you are using posts table just as pivot table, you are doing it wrong.
Episode Model:
public function users()
{
return $this->belongsToMany('App\User', 'posts');
}
// I would name my pivot table different than posts, if you don't pass the second parameter Laravel will look for episode_user table
User Model:
public function episodes()
{
return $this->belongsToMany('App\Episode', 'posts');
}
In your controller:
$user = User::find(1);
$user->episodes();
$episodes = Episode::find(1);
$episodes->users();

Related

How to get data from third table in eloquent relationships eloquent many to many relationship

I am using Eloquent ORM and I have Book model which connect to BookCategory model and BookCategory connect to Category. The l'm problem facing is how to include data from third table in eloquent relationships?
Book
id
name
Category
id
name
type
BookCategory
id
book_id
category_id
Lets say for example you want to get all the books of a certain category:
assuming your pivot table name is Book_Category
in your Category model:
public function books()
{
return $this->belongsToMany('App\Models\Book', 'Book_Category', 'category_id', 'book_id');
}
and you can eager load category books like :
$categories = Category::get()->load('books');
//OR
$categories = Category::with('books')->get();
If I understand you right, you are looking for the pivot attribute. This makes additional columns of the intermediate table available.
https://laravel.com/docs/8.x/eloquent-relationships#retrieving-intermediate-table-columns

Invalid argument supplied for foreach() in laravel when use Eloquent: Relationships

I wanna get the class name of a user via the user ID. When I input the ID of a user so I will wanna get the class name. I have three tables such as users table, classes table, and class_users table. The class_users table is born from two users table and classes table.
A users table has an id, name, email, password.
A classes table has an id, class_code, class_name.
A class_users table has an id, class_id, user_id
And this problem relates to Eloquent Relationships.
Thank you for help.
My Route:
Route::get('/find_classes/{id}','StudentController#find_classes');
My Controller function:
public function find_classes($id)
{
$users = User::find($id);
foreach($users->classes as $class)
{
echo $class->name . '<br';
dd($class);
}
}
My User Model:
public function classes()
{
return $this->belongsTo('App\Classes','class_users','user_id','class_id');
}
Looks like you might have the wrong relationship set up on your User model. You have a one to many set up, but your DB is setup to handle a many to many. I suggest you change your User model relationship:
public function classes()
{
return $this->belongsToMany('App\Classes');
}
Note, you may need to name the FK on that relation, as I see you have class_id on the table, but your actual class is named 'Classes'. Check through your relationships to ensure this is explicit on the FK where it doesn't follow Laravel convention exactly.
With this relationship, your foreach loop should work. It would be a good idea for efficiency, as mare96 noted, to eager load the classes on the $users collection when you query:
$users = User::with('classes')->find($id);

laravel has many through piviot table

I have 3 tables
Products
id, name, image
Offers
id,name
Offer_product
id,offer_id,product_id
I am accessing data of product table with pagination using
$list = Product::query()->paginate(6);
now i want the complete record of products with offer name stored in offers table . id of both product and offers are stored in offer_product table where one products can have many offers
In your DB design you have a Many-to-Many relation, which in Laravel is handle by belongsToMany https://laravel.com/docs/5.7/eloquent-relationships#many-to-many.
hasManyThrough is for cascade 1-to-Many -> 1-to-Many case. Let's say an Artist has many Albums and each Album has many Songs, then an Artist has many Songs through Albums. If you need an Artist Songs, then you may use directly hasManyThrough.
In your case your relation in Product.php model should be :
public function offers() {
return $this->belongsToMany(Offer::class, 'Offer_product')->withPivot('id');
}
In Offer.php model :
public function products() {
return $this->belongsToMany(Product::class, 'Offer_product')->withPivot('id');
}
Now if you want all of them with eager loading https://laravel.com/docs/5.7/eloquent-relationships#eager-loading to avoid N(products)+1 calls to database :
$products = Product::with('offers')->get();
foreach ($products as $product) {
echo 'product : '.$product->name.'<br/>';
foreach($product->offers as $offer) {
echo '<br>---- offer : '.$offer->name;
// once you called the relation, then you can access data on pivot table
echo ' - pivot id :'.$offer->pivot->id;
}
}

laravel one-to-many get data without inner join

I am trying to get a feel around the laravel ORM and I have the following models.
I have a:
user table with- id, firstname, lastname
city table with - id, name
usercity table with - user_id, city_id
The usercity table tracks the cities the user has visited.
I added the following in city model:
public function usercity()
{
return $this->hasMany('App\UserCity');
}
And another function in user model
public function usercity()
{
return $this->hasMany('App\UserCity');
}
I also added a model for UserCity and added following function there.
public function city()
{
return $this->belongsTo('App\City');
}
public function user()
{
return $this->belongsTo('App\User');
}
Now, the goal is to retrieve all the cities a user has visited. I used the following function.
$usercities = User::where('id','=',1)->first()->usercity()->get();
This works in the sense that it retrieves the user_id and city_id.
What would i need to do to get all the fields in the city table also?
Current response:
[[{"user_id":"1","city_id":"1"},{"user_id":"1","city_id":"2"},{"user_id":"1","city_id":"3"},{"user_id":"1","city_id":"4"}]]
I might be able to use inner join but I wanted to see if there was another way to retrieve the data which safely populates the data for me.
What you really have is a many-to-many relationship between users and cities, with the usercity table being the pivot table. Laravel uses the BelongsToMany relationship to implement this. You'll need to make a few changes to get this to work.
In your city model:
public function users() {
return $this->belongsToMany('App\User', 'usercity');
}
In your user model:
public function cities() {
return $this->belongsToMany('App\City', 'usercity');
}
You can get rid of the UserCity model. There is usually no reason to need a model for the pivot table.
The usercity table may need to be updated to add an id field as the primary key. I've not tried it without one, however, so it may work as you have it. Also, if you wanted, you could rename the table to city_user to conform to Laravel conventions, and then you wouldn't need to specify the table name in the relationship definitions.
Once your relationships are setup correctly, you can access a user's cities via the cities relationship on the user, and you can access a city's users via the users relationship on the city. For example:
// all of the cities visited by user 1
$user = User::find(1);
$usercities = $user->cities;
// all of the users that have visited city 1
$city = City::find(1);
$cityusers = $city->users;
You can find more information about the relationships in the documentation here.

Laravel and pivot table to relate different model

I'm wondering how, but it's bit confusing.
I have fine belongs to many relation between users and groups tables as well as appropriate models for all of that.
But i also have table students, where not all users are student so i students table i maintain user_id field.
My question would be: Can i use pivot table "group_user" for relations between student and group model, in students table i have "user_id" field? and how?
I tried something like
public function students()
{
return $this->belongsToMany('Student','group_user','group_id','user_id');
{
but i don't see the way how to tell eloquent not to take students.id but to take students.user_id???
Assuming these relations:
Subject belongsTo Group
Group belongsToMany User
User hasOne Student
you can easily do this:
$subject = Subject::find($someId);
// of course for multiple subject use eager loading:
// $subjects = Subject::with('group.users.student')->get();
$users = $subject->group->users; // related users
foreach ($users as $user)
{
$user->student; // null|student model
}

Resources