Eloquent resolve distant relationship - php

let's say I've this kind of structure.
| lines | | products | | orders |
|------------| |----------| |--------|
| id | | id | | id |
| product_id | |----------| |--------|
| order_id |
|------------|
Is there a way in Laravel Eloquent to load related products given an order? I've tried with hasManyThrough(Product::class, Line::class) with no luck, because on products table there's no reference to the order. Is there a method that can resolve this relationship or should I write a raw query?

You can create a many-to-many relationship in Order model:
class Order extends Model
{
public function products()
{
return $this->belongsToMany('App\Product','lines', 'order_id', 'product_id');
}
}
Then you can get products related to an order:
$order_id = 12;
$order = Order::find($order_id);
$order_products = $order->products;

Related

Laravel Relationship - Additional fields in pivot table linking to additional models

I have simplified the problem to get to the point. I have three tables, users, roles, account.
Normally I would set up the User model to have a many to many relationships with roles but I want those roles to be specific to each account. So I have added an additional field to the pivot table. Here are the tables and fields that I have;
‘users’ table
|—————————
| id | name |
|—————————
| 1 | Bob |
| 2 | Jim |
| 3 | Fred |
|—————————
‘roles’ table
|—————————
| id | title |
|—————————
| 1 | Administrator |
| 2 | Manager |
| 3 | Approver |
|—————————
‘accounts’ table
|—————————
| id | name |
|—————————
| 1 | ABC Company |
| 2 | XYZ Shipping |
| 3 | KLM Transport |
|—————————
I then have the pivot table role_user with an additional pivot field for the account;
|—————————
| role_id | user_id | account_id
|—————————
| 1 | 3 | 1
| 2 | 2 | 1
| 3 | 2 | 3
| 3 | 1 | 2
|—————————
I have used the withPivot function on the belongsToMany function when setting up the many to many relationships. This allows me to get the information using $user->roles->pivot->account_id but what I need is to be able to get the name of that company. All it’s passing to the blade template is the id from the pivot table and not linking that to an actual Account model.
Is there a way with Eloquent to get this entire model in the same way as the original relationship?
Create a Custom Pivot Model
use Illuminate\Database\Eloquent\Relations\Pivot;
class RoleUserAccountPivot extends Pivot
{
public function user()
{
return $this->belongsTo(User::class);
}
public function role()
{
return $this->belongsTo(Role::class);
}
public function account()
{
return $this->belongsTo(Account::class);
}
}
Update your belongsToMany relationships
Bellow is an example with the User::roles relationship
class User //extends...
{
public function roles()
{
return $this->belongsToMany(Role::class, /*other parameters*/)->using(RoleUserAccountPivot::class)->withPivot('account_id');
}
}
Usage
$user->roles->first()->pivot->account // returns Account model
Hope it helps.
Reference links:
Laravel doc on custom pivots

Laravel ORM many to many relationship acts like one to many

My problem is I am trying to establish a many to many relationship between posts and genre. Here is what I have done so far.
class Post extends Model
{
public function genres()
{
return $this->belongsToMany('App\Genre');
}
}
class Genre extends Model
{
public function posts()
{
return $this->hasMany('App\Post');
}
}
genre Table
+----+--------+
| id | name |
+----+--------+
| 1 | News |
| 2 | Sports |
+----+--------+
post table
+----+----------------+
| id | title |
+----+----------------+
| 1 | Political News |
| 2 | Sport Update |
+----+----------------+
genre_post table
+----+---------+----------+
| id | post_id | genre_id |
+----+---------+----------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
+----+---------+----------+
When I am trying to acess genre list of a post, everything works fine.
Post::where('slug', '=', $id)->with("genres")->first(); // no problem
But when I tried the opposite it's not working.
$posts = Genre::where( "slug", "=", $id )->with("posts")->first();
I am getting the following error.
Column not found: 1054 Unknown column 'post.genre_id' in 'where
clause' (SQL: select * from post where post.genre_id
I understand the laravel is trying to aceess genre_id column from post table which doesn't exists since it's a many to many relation which means one post can contain more than one genre and one genre can contain more than one post.
Any idea how can I resolve this?
This is expected since hasMany itself an one to many relationship. Use belongsToMany instead.
class Genre extends Model
{
public function posts()
{
return $this->belongsToMany('App\Post');
}
}

How can I make a relation between tables in Laravel?

I have three tables like these:
// users
+----+-----------+
| id | user_name |
+----+-----------+
| 1 | Jack |
| 2 | Peter |
| 3 | John |
+----+-----------+
// skills
+----+------------+
| id | skill_name |
+----+------------+
| 1 | PHP |
| 2 | HTML |
| 3 | Laravel |
| 4 | MySQL |
| 5 | jQuery |
+----+------------+
// skill_user
+----------+---------+
| skill_id | user_id |
+----------+---------+
| 2 | 1 |
| 5 | 1 |
| 1 | 2 |
| 2 | 2 |
| 4 | 2 |
+----------+---------+
Now I want to get all skills of one specific user. I can do that by using a join clause in a raw sql query:
SELECT s.skill_name
FROM skills s
JOIN skill_user su ON s.id = su.skill_id
WHERE su.user_id = :user_id
/* output (assuming :user_id is 1)
+------------+
| HTML |
| jQuery |
+------------+
Ok All fine. Now I want to know, how can I do that by adding a method in the model of Laravel framework? All I'm trying to do is using belongsTo(), hasOne(), hasMany() etc ..
To do in Eloquent way, you need to add the relationship. In your case, it is many-to-many relationship so in User.php, add this function to declare the relationship:
public function skills() {
$this->belongsToMany(\App\Skill::class, 'skill_user', 'user_id', 'skill_id');
}
Then,
Access it like this to eager load it:
$users = \App\User::with('skills')->get();
OR
Say you have a single user,
$user = User::where('id', 1)->first(); // Get the user with id = 1
and to get the skill for that user:
$user->skills;
OR
If you don't want to do using Eloquent way, you can use Query Builder. Note that, using this method, you basically join it manually so you don;t need to add any method to the Model:
\DB::table('users')
->join('skill_user', 'skill_user.user_id','=', 'users.id')
->join('skills', 'skill_user.skill_id', '=', 'skills.id')
->select('*')
->where('users.id', 1)
->get();
You have to use belongsToMany relationships. Assuming you will create SkillUser model for skill_user table. Add the following code to User Model
public function skills() {
$this->belongsToMany('App\SkillUser', 'skill_user', 'user_id', 'skill_id');
}
Now you can access it by
$users->skills();
I assume you are talking about Many to Many relationship between Users and skills, then the example given in Laravel many-to-many speaks about it.

Laravel count Eloquent belongsToMany related model

I'm new to Laravel, and I got stuck with the following issue:
I have a table for the users, and groups, and a table for connecting them. The general task any user can join any group.
----------------------------------------------
| users | groups | user_groups |
|--------------------------------------------|
| id - int pk | id - pk | id - pk |
| name text | name | user_id - fk |
| email | | group_id - fk |
| phone | | any_attr |
----------------------------------------------
I have the following models:
class User
{
...
public function groups()
{
return $this->belongsToMany(Group::class, 'user_groups')->withPivot(['is_notification_requested']);
}
...
}
class Group
{
...
public function users()
{
return $this->belongsToMany(User::class, 'user_groups');
}
...
}
How do I get all of the groups, with a count of the members? I need the Group model, and a count of the users in the group.
If you're using Laravel 5.3, you can simply add withCount('relationship') as documented here: https://laravel.com/docs/5.3/eloquent-relationships#counting-related-models
Here's an example following your code:
$groups = Group::withCount('users')->get();
Now you can do this:
foreach($groups as $group) {
echo $group->user_count
}

Laravel relationships - 3-way table

I have 3 models: Basket, Product and Asset.
A Basket can contain many Assets, and one asset can appear in multiple Baskets.
A Product can have many Assets, but an Asset can also be assigned to more than one Product.
The aim is to get Assets into a Basket while still knowing which Product it was added from.
The table structure I envision having is this:
-------------------------------------
| basket_id | asset_id | product_id |
-------------------------------------
| 1 | 1 | 1 |
| 1 | 3 | 1 |
| 1 | 15 | 2 |
| 2 | 23 | 1 |
| 2 | 3 | 1 |
| 3 | 79 | 3 |
-------------------------------------
I also envision a model setup of something like this:
class Basket extends Eloquent {
public function assets() {
return $this->belongsToMany('Asset');
}
}
class Product extends Eloquent {
public function assets() {
return $this->belongsToMany('Asset');
}
}
class Asset extends Eloquent {
public function products() {
return $this->belongsToMany('Product');
}
public function product() {
// This should return the product from the product_id column
}
}
I'm not sure how to go about writing Asset::product() so that it returns the corresponding Product.
I'd like to call something like Basket::find(1)->assets()->first()->product; to get the product that the first asset was added to the basket from.
Here's a small piece that does what you need
https://github.com/jarektkaczyk/Eloquent-triple-pivot
and thanks to your PR a package on packagist:
https://packagist.org/packages/jarektkaczyk/eloquent-triple-pivot

Categories