How to combine three many to many relationship results in a single collection in Laravel? - laravel

I have a many to many relationship between the following:
actor <-> theater_play, actor <-> musical, actor <-> ballet_play
How can I make a single array to display all the results from these relationships in Laravel?
I have now:
$actor->theaterPlays, $actor->musicals, $actor->balletPlays
And I need to have something like this:
$actor->allPerformances
EDIT:
And I have to order theym by name, or by date of the performance etc.

Untested, however you should be able to create a new accessor within your Actor model which is responsible for merging all types together:
public function getAllPerformancesAttribute()
{
return $this->theaterPlays()
->get()
->merge($this->musicals()->get())
->merge($this->balletPlays()->get())
->all();
}

Related

ManyToMany with and whereIn

I have a ManyToMany relationship between AdInterest and AdInterestGroup models, with a belongsToMany() method in each model so I can use dynamic properties:
AdInterest->groups
AdInterestGroup->interests
I can find all the "interests" in a single group like this:
$interests = AdInterestGroup::find(1)->interests->pluck('foo');
What I need is a merged, deduplicated array of the related 'foo' field from multiple groups.
I imagine I can deduplicate with ->unique(), but first, as you'd expect, this:
AdInterestGroup::whereIn('id',[1,2])->interests->get();
throws:
Property [interests] does not exist on the Eloquent builder instance.
The advice seems to be to use eager loading via with():
AdInterestGroup::with('interests')->whereIn('id',[1,2])->get();
Firstly, as you'd expect that's giving me an array of two values though (one for each ID).
Also, if I try and pluck('foo') again, it's looking in the wrong database table: from the AdInterestGroup table, rather than the relationship (AdInterest).
Is there a nice, neat Collection method / pipeline I can use to combine the data and get access to the relationship fields?
Use pluck() and flatten():
$groups = AdInterestGroup::with('interests')->whereIn('id', [1, 2])->get();
$interests = $groups->pluck('interests')->flatten();
$foos = $interests->pluck('foo')->unique();

Laravel/Eloquent get all appointments from a polymorphic "member_id" through a appointment_members table

I have an appointments table and an appointment_members table and my users need to be able to get a collection of appointments by searching with a "member_id", which could be a Person, Incident or CustomerID. The appointment_members table has member_id and appointment_id columns, so the member_type (also a column) is irrelevant. This all set up by a previous dev and what is missing are the relationships on the Eloquent models. I'm just creating a simple GET route that needs to return any/all appointments by that member_id. Each row has one appointment, so if I were to pass in a member_id that returned 10 results, some could have appts and others not, but at the end of the day I just need a collection of appts that are related to that member_id. Here's a screenshot of the appointment_members table:
If I create a simple hasOne relationship to appointments on appointment_members:
public function appointments()
{
return $this->HasOne(Appointment::class, 'id', 'appointment_id');
}
I can get a collection of appointment_members with it's respective appointment, but not sure how I boil it down to just getting the appointments. One workaround I have is to use that HasOne and then pluck/filter the appointments:
$appointmentMembers = AppointmentMembers::where('member_id', $request->input('memberId'))->get();
$appointments = $appointmentMembers->pluck('appointments')->filter();
Curious if anyone might see a better way to go about this. Thanks!
I'm possibly not understanding, but I would probably take the simplest approach here if the member type is not important.
The table is already set up to handle either a belongsToMany or a morphMany, so create the relationship on the Member class (or if you don't have a parent member class, stick it on each of the types Person, Incident, etc. You can also do this via poly, of course, but this is a simple example to get what you need):
public function appointments()
{
return $this->belongsToMany(Appointment::class)->withPivot('member_type');
}
And then just query on the member object you need appointments for (having poly would make this one step):
$allAppointmentsForID = $member->appointments();
$appointments = $allAppointmentsForID->wherePivot('member_type', $whateverClassThisIS);
The above takes member_type into account. If this doesn't matter, you can just use the top line.
Your original db is setup to handle polymorphic relations, so if you wanted more than the appointment you can set it up this way as well. For now, you'll need to add the TYPE to the query to cover the different classes.
If the member type is important, polymorphic might be something like this on the Member class:
public function appointments()
{
return $this->morphMany(Appointment::class, 'memberableOrmember_typeOrWhatever');
}
Then you can query on the member object with just one line
$appointments = $member->appointments();

Laravel how many relationship can be chained

I have a database composed by users, users_child, child.
I create a ONE to MANY relationship between Users and users_child, then i create a relationship between users_child and child. Now the below code work:
$test = users::find(1)->users_child
$test1= users_child::find(1)->child
Now i want to know if is possible to create a single row that link the three table like this:
$test = users::find(1)->users_child->child
I create the relationship in the model but in the db i don't create Foreign Key, it's a problem? on the model i specify the field for link table.
http://laravel.com/docs/5.1/eloquent-relationships#querying-relations
You can chain relationships like this:
$user = Users::with("users_child.child")->where("id",1)->first();
Each point will mean a relation stored in the first.
Out of users users_child will be taken and out of users_child child will be taken. (Relations)
foreach($user->users_child as $user_child) {
$user_child->child;
}
will get you the data you need.

return separate result for each relation in many to many

Hi i have a many to many relationship with the following structure:
services
apps
service_app
I would like to have an eloquent query to return a separate result for each relationship(basically the pivot table). I have the following :
$all = App::with('services')->get();
this will return an app with nested services, I would like to have this return a separate result for each app-service combination along with data from the pivot table. how is this possible using eloquent?
It's a bit strange, but it can easily be done if you don't think of the pivot table as a pivot table, but as an AppService.
So what you can do is create a model for it, probably named AppService. In that model, you would then have 2 belongsTo() relationships. One for App and one for Service.
Then you can query your pivot table directly and use those relationships to get what you need.
$appServices = AppService::all();
foreach($appServices as $appService) {
echo $appService->app->description;
echo $appService->service->description;
}

Eloquent ORM Eager-loading Distinct Records in Many to Many Relationship

Background
I have a List model which belongs to and has many Subscriber. And of course a Subscriber which belongs to and has many List.
Problem
I want to eager-load all subscribers from multiple lists. BUT, I am only interested in distinct subscribers, since a subscriber can have and indeed belong to multiple lists.
My attempt
I have used the distinct() method but this hasn't yielded any joy. And I can also loop through the result set to manually slice out duplicates. Just wondering if there is a way of letting Laravel do the dirty job for me?
Code
$lists = Input::get('listsarray');
$addresses = Addressbook::with(array('subscribers' => function($query)
{
$query->where('active', '=', 1);
// $query->distinct(); //This didn't work
}))->whereIn('id', $lists)->get();
Retrieving unique subscribers through join
I'll try my best to explain it using Lists instead of Adressbook, because I couldn't really understand your model and that may introduce further confusion.
If I understood your comments correctly, you are trying to retrieve all unique subscribers that have associations with lists of id IN listarray. In that case, Eager Loading is not the proper way of doing that. Eager loading serves the purpose of pre-loading associations for a model, in order to use them later on. In your case, you are not retrieving Lists and their Subscribers, but rather the unique Subscribers themselves.
$lists = Input::get('listsarray');
$subscribers = Subscriber::join('list_subscriber', 'list_subscriber.subscriber_id', '=', 'subscribers.id')
->whereIn('list_subscriber.list_id', $lists)
->groupBy('list_subscriber.subscriber_id')
->get(array('subscribers.*'));
If you also wish to retrieve all lists associated with such subscribers, you can do so:
// Simply include a with('lists') and Eloquent will eager load them
$subscribers = Subscriber::with('lists')
->join('list_subscriber', 'list_subscriber.subscriber_id', '=', 'subscribers.id')
->whereIn('list_subscriber.list_id', $lists)
->groupBy('list_subscriber.subscriber_id')
->get(array('subscribers.*'));
Eager Loading
If it's a matter of simply improving performance, you don't need to use distinct, Laravel already does it. Eloquent behaves like this:
Fetchs all lists.
Iterates through lists building an array of unique list_ids
Fetchs all list_subscribers using WHERE list_id IN (X, Y, Z)
Iterates through all list_subscribers building an array of unique subscriber_id
Fetchs all subscribers using WHERE id IN (X, Y, Z)

Resources