Laravel Eloquent belongsToMany multiple "primary" keys - php

In laravel I'm connecting events to users like this:
class User extends Model
{
public function events()
{
return $this->belongsToMany('App\Event', EventUser::TABLE_NAME, 'user_id', 'event_id');
}
}
which works great, but now I'm implementing repeat feature so I'm inserting repeating events for 2 years in the future in the database, and I don't want to make 1000 inserts, so I decided that I'll have parent event, and subevents will have parent_id in the database. Now the problem is that I can't get those events with belongsToMany, since I need to watch for 2 keys... id and parent_id.
Any idea how I can do that? I want to get events connected with user and events that have parent event connected with user.

public function parentEvents()
{
return $this->belongsToMany('App\Event', EventUser::TABLE_NAME, 'user_id', 'event_id');
}
public function childEvents()
{
return $this->belongsToMany('App\Event', EventUser::TABLE_NAME, 'user_id', 'parent_id');
}
public function events()
{
$parentEvents = $this->parentEvents;
$childEvent = $this->childEvents;
// Merge collections and return single collection.
return $parentEvents->merge($childEvents);
}

Related

Laravel Many to many to many sync

I've got a problem since several days in Laravel.
My database is like attached picture.database
User<->Role many-to-many-relationship works correctly.
In addition, I would like to add another many-to-many relationship in role_user pivot table. So I did:
user.php:
public function roles()
{
return $this->belongsToMany(Role::class);
}
public function role_users()
{
return $this->hasMany(RoleUser::class);
}
role.php:
public function users()
{
return $this->belongsToMany(User::class);
}
public function role_users()
{
return $this->hasMany(RoleUser::class);
}
And pivot roleUser.php:
public function user()
{
return $this->belongsTo(User::class);
}
public function role()
{
return $this->belongsTo(Role::class);
}
public function tags()
{
return $this->belongsToMany(Tag::class);
}
When I populate tables, I can get data: relations work.
Now I want to save data and let Laravel to populate tables automatically. At this moment and time, I save roles data in users.php with:
$this->Roles()->sync($roles);
($roles is an json array data from a form request..).
Pivot table get the user_id and role_id. Ok, cool.
Now, what should I write to get role_user_id and tag_id in role_user pivot table when I add a roles?
Thank you in advance!
I think you should use
$this->Roles()->attach($roles);
Rather than
$this->Roles()->sync($roles);
Because if I'm not wrong, sync will remove the pivot data. And you should pass the primary_key and foreign_key to your belongsToMany function. If you wanted to add data to the pivot column in your pivot table, try to add ->withPivot('column name');

Laravel pivot consultation

I need advice about my model relationships,
Logic
Group has many users
Group has many admins
User has many groups (as user)
User has many groups (as admin)
Database Structure
Group Table
User Table
Group_Users table (save id of user and id of group)
Group_Admins table (save id of user and id of group)
Relationship Code
User model
public function groupsUser() {
return $this->hasMany(GroupUser::class);
}
public function groupsAdmin() {
return $this->hasMany(GroupAdmin::class);
}
Group model
public function users() {
return $this->hasMany(GroupUser::class);
}
public function admins() {
return $this->hasMany(GroupAdmin::class);
}
GroupUser model
public function group() {
return $this->belongsTo(Group::class);
}
public function user() {
return $this->belongsTo(User::class);
}
GroupAdmin model
public function group() {
return $this->belongsTo(Group::class);
}
public function user() {
return $this->belongsTo(User::class);
}
Help wanted
Basically as the relationships between users and groups is many to many normally I shouldn't need models of GroupUser and GroupAdmin and then just using sync() function in order to add/remove users and group id's from those tables.
What is my concerns then?
Normally I use that type of connection when I want input bulk ids into database (let say adding tags to posts, suddenly relate 10 tags id to 1 post) that moment using sync() and removing GroupUser and GroupAdmin models makes sense but in my case as users joins/adds to groups one by one, what do you suggest for this relationships?
Is my current approach makes sense?
Is is better if I remove those GroupUser and GroupAdmin models and add them to user, group model like:
public function users()
{
return $this->hasMany(User::class, 'group_users', 'user_id', 'id');
}
and such so?
What do you think is the best practice?
users and groups is many to many
your tables like this?
users, user_group , groups ?
How about use 'belongsToMany' relation?
Laravel many to many relation
// User model
public function groups() {
return $this->belognsToMany(Group::class);
}
// Group model
public function users() {
return $this->belognsToMany(User::class);
}
And use like.
User::find(1)->groups; // return user 1 groups
User::find(1)->groups()->sync($groupIds); // relate user and groups
Group::find(1)->users; // return group 1 users
If you have role column in your users table, you cold add relation like.
// Group model
public function users() {
return $this->belognsToMany(User::class)->where('role', 'the role of normal user');
}
public function admins() {
return $this->belognsToMany(User::class)->where('role', 'the role of admin user');
}
Hope it helps you.

Laravel nested eager load specific columns

I am working with nested eager loading is there a way you can pick out certain columns from the middle relation in account.user.location ?
User Model
public function account(): HasMany
{
return $this->hasMany(Account::class);
}
public function location(): BelongsTo
{
return $this->belongsTo(Location::class);
}
Account model
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
Location model
public function user(): HasMany
{
return $this->hasMany(User::class);
}
Controller method that works
This method returns the nested relation but i want certain columns from the user relation instead of listing them all.
public function show(string $id)
{
$film = Film::with([
'account.user.location'
])->findOrFail($id);
}
Controller method that doesn't work
This is my sample code i've tried to pick out the name column from users then display the location relation.
public function show(string $id)
{
$film = Film::with([
'account.user:id,name',
'account.user.location:id',city
])->findOrFail($id);
}
Response
This is the response which is returned its returning the location as null from the not working method
+"account": {#2061
+"id": "191067a6-4c38-423d-a972-bb3a842ca89e"
+"user": {#2064
+"id": "d9f381c1-3899-367c-8d60-6d2bc3db6d23"
+"name": "Domenick"
+"location": null
Im unsure on how i pick out specific columns from the middle relation and then joining the location. Can i get some assistance on where i am going wrong?
Laravel is loading each level of relationships after another. In other words, if you use A::with('b.c')->get(), then Eloquent will first load all As, then all of their referenced Bs and finally all of the Cs referenced by the loaded Bs. The ORM uses navigation properties, i.e. foreign keys, to do so. If you omit these foreign keys on intermediate models, the framework is not able to load the referenced models anymore.
If you'd do it manually, you would use the following queries (used IDs and foreign keys are examples):
SELECT * FROM a; // returns As with ids 1, 2, 3
SELECT * FROM b WHERE a_id IN (1, 2, 3); // returns Bs with ids 4, 5, 6
SELECT * FROM c WHERE b_id IN (4, 5, 6);
In your case, it should be sufficient to use the following code:
public function show(string $id)
{
$film = Film::with([
'account.user:id,account_id,location_id,name',
'account.user.location:id,city'
])->findOrFail($id);
}
Update your User Model
public function account()
{
return $this->hasMany(Account::class, 'user_id');
}
public function location()
{
return $this->belongsTo(Location::class);
}
Update you Account class to
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
In your controller method try this
public function show($id)
{
$film = Film::where('id', $id)
->with([
'account.user:id,name',
'account.user.location:id',city
])->get();
}

Displaying data from different tables in laravel

Have researched extensively eloquent relationships and laravel all afternoon and can't seem to find a solution.
I have a transaction table displaying User IDs in the From and To columns. I want to show the users emails that correspond to their IDs.
Here is my relationships:
Transaction model:
public function user()
{
return $this->belongsTo('App\User', 'id', 'email');
}
User model:
public function transaction()
{
return $this->hasMany(App\Transaction);
}
And heres the code from the controller. However I KNOW this just returns ALL the transactions. But I really can't find how I would display the emails instead of the IDs:
public function index()
{
$table = Table::create(Transaction::get());
return view('table', compact('table'));
}
Maybe you should try to get transactions with related model (user) or with join to users table?
$transactions = Transaction::query()->with(['user'])->get();
$table = Table::create(Transaction::get());
$table->addColumn('email', 'E-mail', function($model) {
return $model->user->email;
});
return view('table', compact('table'));

Laravel HasManyThrough doesn't work in this situation how to do it?

I have 3 models
User
id
Event
id
end_time
EventUser (this represents a user who's joined an event with a comment)
user_id
event_id
comment
We want to do $user->events
(to list the event details for all events user has joined)
But, as you can see, the intermediate table is a pivot table... therefore the events table does not reference it (which is the fourth parameter of the hasManyThrough function).
For example, I may want to get event details for all events a user has joined that has ended.
For now I am doing this in the User model
private function eventQuery() {
return Event::join('event_user', 'events.id', '=', 'event_user.event_id')
->where('user_id', $this->id); // event_user.user_id
}
public function events() {
return $this->eventQuery()->get();
}
public function pastEvents() {
return $this->eventQuery()
->where('end_time', '<', new \DateTime()) // events.end_time
->get();
}
But is there a laravel way to do it like the hasManyThrough in this situation?
The laravel way is:
User Model:
public function events()
{
return $this->belongsToMany('App\Event')->withPivot('comment');
}
Event Model:
public function users()
{
return $this->belongsToMany('App\User')->withPivot('comment');
}
When you do a call to:
$user = App\User::whereId($id)->where('end_time','<=',$now)->with('events')->get();
The events relation will be retrieved with the comment field of the pivot table, as you want it to be.

Categories