Many to many Laravel Eloquent relationship with multiple intermediate tables - laravel

I'm using Laravel 5.4 and have a model and table structure as follows:
users
-----
id
accounts
--------
id
holdings
--------
id
account_id (foreign key to account)
user_accounts
-------------
id
user_id
account_id
A user can have multiple accounts
An account can be shared by multiple users
Each account has multiple holdings
A user therefore indirectly has many holdings through their many accounts.
I need help to define a relation on the User model called "holdings" to get me all the holdings applicable to the user (based on the accounts they are linked to).
I've tried lots of different things and spent ages on google. I can get close with both belongsToMany and hasManyThrough, but they only seem to work for 3 table relationships where the intermediate table stores primary keys from the other tables. I can reduce my relationship to 3 tables (rather than 4) if I make use of the account_id foreign key on the holdings table to remove the need to join through the accounts table, however I can't seem to get this to work.
belongsToMany - holdings.id needs to be holdings.account_id:
select * from `holdings`
inner join `user_accounts` on `holdings`.`id` = `user_accounts`.`account_id`
where `user_accounts`.`user_id` = ?
hasManyThrough - user_accounts.id needs to be user_accounts.account_id:
select * from `holdings`
inner join `user_accounts` on `user_accounts`.`id` = `holdings`.`account_id`
where `user_accounts`.`user_id` = ?"

Well it's not strictly an answer as I was asking about laravel 5.4, but it is a possible solution.
It turns out I'm in luck as I came across this Laravel belongsToMany relationship defining local key on both tables which indicates the belongsToMany relationship has been enhanced in Laravel 5.5 to support this type of scenario.
I have upgraded my project to L5.5 and replaced my hack with the relation:
return $this->belongsToMany(Holding::class, 'user_accounts', 'user_id', 'account_id', null, 'account_id');
And am happy to say it seems to work perfectly - at least for basic gets which is my use case, I haven't tried any updates etc.
Thanks to #cyberfly and those who posted the answer above

Related

How to define and use a foreign key as primary key in Laravel?

I have a Users table that can store 8 different types of users. Depending on the user type, I have some other tables with the specific data set for it. So, I would like to use the ID from the Users table as a foreign key and primary key at the same time for those tables. But I am new at Laravel and I don't know how to do that to fit the conventions or, if it is not possible, how to do that when defining my models and one to one relations. Can someone help me? Thanks!
EDIT: Sorry, I think my explanation is not clear enough. Let's say I have 4 tables: users, user_types, customer_organzations, partners, and customers. I would like to use ID, that is PK of users, as a foreign key and primary key for tables customer_organizations, partners and customers, that have different information since they are different type of users in my application but all them login against users table. I don't care user_types table. I think I know how to deal with it.
You haven't given us much in terms of your table structure, so assuming you have a simple one-to-one relationship between a users table and a user_types table, the following would create the required relationship.
In your user_types table migration
$table->foreignId('user_id')->constrained();
The above will add your foreign key to the table and create the relationship back to the users table (this is done 'magically' using conventions so naming is important).
Then in your eloquent models, add the relationships between the models:
User.php
public function type()
{
return $this->hasOne(UserType::class);
}
UserType.php
public function user()
{
return $this->belongsTo(User::class);
}

laravel relationships - 3 way pivot - eloquent

I am following a tutorial on Laravel ACL, that takes into consideration Users and Roles (https://github.com/laracasts/laravel-5-roles-and-permissions-demo). However, I have an additional level of complexity whereby I need to take into consideration a company model also. So a user may belong to many companies and each instance of a company user may have many roles.
I think the best way to acheive this would use a pivot that has 3 fields:
company_id
role_id
user_id
Esentially, I want to achive something like this:
$user->companyRoles; //return the user's company roles
$user->company->assignRole('admin');
$user->assignRole($companyId, 'admin');
Can you advise on the relationships I require to do this?
Many thanks

How to create a pivot table with related field other than id on Laravel 5.2

I want to create (on Laravel 5.2) a pivot between two entities, let's assume that we have the entities User and Phone. In our world, a user can have several phones, and te phones can have several owners.
For a reason, I must target the user's phone by it's serial number and the build year (let's assume that serials can't be identical on a same year).
So I have my tables users, phones andusers_phones.
===== Table users =====
id
username
...
===== Table phones ====
id
serial_numer
build_year
===== Table users_phones ====
user_id
phone_serial
phone_build_year
I have my relation on my model Phone :
public function users()
{
return $this->belongsToMany(
User::class,
'users_phones',
'user_id',
'phone_serial'
)->withPivot('phone_build_year');
}
When I wan't to add some entries like that :
$phone->users()->attach([$user->id => [
'phone_build_year' => $phone->build_year
]]);
The SQL request generated is the following one :
insert into `users_phones` (`user_id`, `phone_serial`, `phone_build_year`) values (1, 5, 2016)
My problem is that the 5 in the sql request is the phone id and not its serial. I didn't find how to precise to Laravel to use the field we chose (here the serial) rather than the id.
Is it possible to do that, or am I condemned to create a model to manipulate my special pivot table ? I admit that I would appreciate if I could avoid that way.
So, as Jarek says, it seems that there is no way to customize the Laravel pivot relations as I would like to do. I will create a model dedicated to this particular case.
Anyway, if someone has a better and elegant way to do this kind of custom pivot relation on Laravel, please share your knowledge !

Laravel - Eloquent Models Relations, polymorphic or not?

I have this schema
All the relations here must be one-to-zero/one.
A user can be either an employee or a customer. The user_type ENUM gives me the type so I know where to go from there.
Then an employee can be either basic or a manager. The employee_type discriminator let's me know that.
How am I supposed to build the Eloquent Model relations?
Let's say I have a user that is an employee. I need to get it's common fields from the users table but also need to get common fields from employees table. Do I need to hard code, and know that when user_type=emp I need to select from the employees table? What if I need to add another user type later?
UPDATE
Would it make sense to change my schema into something simpler?
My problem is that by using, as suggested, polymorphic relations I would end up to something like this:
$user = new User::userable()->employable()->...
Would a schema in which I drop the employees table and have employee_managers and employee_basics linked straight to the users table?
this is an polymorphic relationship. but if you want to be easy, you need to fix some things.
in the table employees
- user_id
- employable_id
- employable_type enum(Manager, Basic) # References to the target model
.... this last two are for the polymorphic relation, this is the nomenclature
in the basics and managers table you could delete the user_id field, but you need an id field as increments type
and now in the model Employee you need to make this function
public function employable(){
return $this->morphTo();
}
I hope this works :)

laravel 4 polymorphic relationships

I'm trying to get my head around using polymorphic relationships in Laravel 4, but I can't work out how to do the following:
I have a users table, customers, suppliers and partners tables and a userhistories table which has a one to many with users and morph many (called historable) with customers, suppliers and partners.
I want to get the latest 10 userhistories for the (Auth::user) logged in user that are linked to the customers table without including those for the other two tables, but I can't work out the Fluent query(s) to let me do this. Help! Thanks.

Resources