Querying Many to Many polymorphic relationship in laravel - php

I've following tables:
contacts(id, name, email, phone_no),
events(id, title, start_date, end_date),
addresses(id, city, state, country, zip_code),
addressables(id, address_id, addressable_id, addressable_type)
Here addressables have many to many polymorphic relation for contacts events. addressables could also hold other polymorphic model class.
Addres Model
public function addressable()
{
return $this->morphTo();
}
Event/Contact Model
public function addresses()
{
return $this->morphToMany(Address::class, 'addressable');
}
I wanted to fetch addresses along with their associated models. I would appreciate if anyone could help me to
List addresses with associated models
List addresses for specific model type
List addresses group by model type
UPDATED
Expected Outcomes:
addresses
id | address
1 | New York, USA
2 | California, USA
3 | Nevada, USA
contacts
id | name
1 | Albert King
2 | Michelle Johnson
3 | Sujit Baniya
events
id | title
1 | Event 1
2 | Event 2
3 | Event 3
addressables
id | address_id | addressable_id | addressable_type
1 | 1 | 1 | Contact
2 | 2 | 1 | Event
3 | 3 | 2 | Contact
EXCEPTED RESULT for Address::with('addressables')
Address - ID 1
----Details (New York, USA)
----Contact (Albert King)
Address - ID 2
----Details (California, USA)
----Event (Event 1)
Address - ID 3
----Details (Nevada, USA)
----Contact (Michelle Johnson)
Thank you in advance!

According to Laravel's Documentation for many to many polymorphic relations,
you have to edit your address model and add methods for events and contacts like so:
//Get all the contacts that are assigned this address
public function contacts()
{
return $this->morphedByMany('App\Contact', 'addressable');
}
//Get all the events that are assigned this address
public function events()
{
return $this->morphedByMany('App\Event', 'addressable');
}
To answer your question
Then to get all addresses for a contact, you can use the addresses dynamic property like so:
$contact = App\Contact::find(1);
foreach ($contact->addresses as $address) {
//
}
And for events:
$event = App\Events::find(1);
foreach ($event->addresses as $address) {
//
}
Lastly, you can retrieve Address events, contacts like so:
$address = App\Address::find(1);
foreach ($address->events as $event) {
//
}
foreach ($address->contacts as $contact) {
//
}

Related

Eloquent Relationships hasMany use loop

I have a database with multiple address records of a user. When I do "pluck()" and "join()" in the foreach path, I get results. But when I type $user->getAddress->address in structures like hasOne, I get the result I want. In short, can I return the loop in hasMany more practically?
Following my code:
user Table
id | name | lastname |
--- -------------- ----------
1 | Rahuel | lastnameRahuel
2 | Dalton Miller | lastnameDalton
adress Table
user_id | address
-------- ---------
1 | 740 Brown Greens Suite
1 | 9906 Cleora Wall Apt.
2 | 53977 Kip Center Apt
UserModel
public function getAddress()
{
return $this->hasMany(Address::class);
}
Controller
$users = User::with('getAddress')->get();
foreach ($users as $user){
echo $user->name;
echo $user->lastname;
echo $user->getAdress->pluck('address')->join(',');
}
You can use the Collection 's implode method to make it look a bit less verbose.
echo $user->getAdress->implode('address', ',');

Get data from pivot table

I have two tables with a pivot table
Table user
id | name | email
Table drinks
id | name | price
Pivot Table user_drinks
id | user_id | drink_id | quantity | price | status
Drink Model
public function users()
{
return $this->belongsToMany('App\User', 'user_drinks', 'drink_id', 'user_id')->withPivot('price', 'quantity')->withTimestamps();
}
User Model
public function drinks()
{
return $this->belongsToMany('App\Drink', 'user_drinks', 'drink_id', 'user_id')->withPivot('price', 'quantity')->withTimestamps();
}
I want to get the latest users that have bought drinks and the price and quantity from pivot table e.g
User 1 with name John has bought 2 cups of coffee at $50 dollars
User 2 with name Jane has bought 3 cups of coffee at $75 dollars
use this relation to the User model
public function drinks()
{
return $this->belongsToMany(Drink::class, 'user_drinks')->withPivot(['quantity', 'price','status'])->withTimestamps();
}
to get it:
$user = User::with(['drinks' => function ($q) {
$q->orderBy('created_at', 'desc');
}])->orderByDesc('drinks.created_at')->get();

Laravel 5.6 - How to fetch last X guest names for room deal?

I can't figure out how to structure an efficient Eloquent query for the following scenario.
Users can stay in many locations like rooms, apartments, homes, so we have a polymorphic stayable_locations table, but we're only focusing on the room stayable_type of this table. When the staff clicks a room, we want to display all available room deals (if any are available from the room_deals table) and also the last 3 guests for each room deal (if any).
Trying to get this output from the following tables via eloquent:
Room 111 (desired output for room deals and guests below)
- Room Deal #1 -> Able, Kane, Eve
- Room Deal #2 -> Eve, Adam
------------------------------------------
$room = Room::where('id',111)->first(); // room 111
// Eloquent query, not sure how to setup model relations correctly
// To get last 3 guest names per room deal [if any] in an efficient query
$room->roomDeals()->withSpecificRoomDealLast3RoomGuestNamesIfAny()->get();
Here is the table structure:
stayable_locations table [polymorphic]:
id | stayable_id | stayable_type | room_deal_id | room_guest_id
----------------------------------------------------------------
1 | 111 | room | 0 | 3 (Steve no room deal)
2 | 111 | room | 1 | 1 (Adam room deal)
3 | 111 | room | 1 | 2 (Eve room deal)
4 | 111 | room | 1 | 4 (Kane room deal)
5 | 111 | room | 1 | 5 (Able room deal)
6 | 111 | room | 2 | 1 (Adam room deal)
7 | 111 | room | 2 | 2 (Eve room deal)
room_deals table:
id | room_id | room_deal
-----------------------
1 | 111 | Deal A
2 | 111 | Deal B
users table:
id | name
------------
1 | Adam
2 | Eve
3 | Steve
4 | Kane
5 | Able
UPDATE: Showing respective models
User Model:
class User extends Authenticatable {
public function stayableLocations() {
return $this->morphMany('App\StayableLocation', 'stayable');
}
}
RoomDeal Model:
class RoomDeal extends Model {
public function room() {
return $this->belongsTo('App\Room');
}
public function guests() {
return $this->belongsToMany('App\User', 'stayable_locations', 'room_deal_id', 'room_guest_id');
}
}
StayableLocation Model:
class StayableLocation extends Model {
public function stayable() {
return $this->morphTo();
}
public function room() {
return $this->belongsTo('App\Room', 'stayable_id');
}
}
Room Model:
class Room extends Model {
public function stayableLocations() {
return $this->morphMany('App\StayableLocation', 'stayable');
}
public function roomDeals() {
return $this->hasMany('App\RoomDeal');
}
}
Any idea how to get the desired output via an efficient eloquent query?
I figured it out from the helping comments in my question. Here we go:
Laravel does not have this out of the box (see here) so we'll have to use a third party package.
Install the staudenmeir/eloquent-eager-limit package per link directions and follow usage example.
This is what needed to change above [still used same defined relationship above for below ...], just added the use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;:
class User extends Authenticatable {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
...
}
class RoomDeal extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
...
}
Working query with nested limit via eloquent, thanks to the commenters and package help:
$room = Room::find(111);
$deals3Guests = $room->roomDeals() // query deals
->with(['guests' => function($query) { // eager load guests
$query->orderBy('stayable_locations.id', 'desc') // get latest guests
->limit(3); // limit to 3
}])
->get();

How to fetch data from multiple tables using Join and where clause

I have written a simple symfony controller where I have two table known as specialtyarea and physician.
this is the basic structure of the table
specialtyarea
-----------------
id | name |
-----------------
1 | dentist |
2 | physician |
Physician table is related to specialtyarea as shown:
Physician
--------------------
id | name | specfk |
--------------------
1 | John | 1 |
2 | Doe | 2 |
3 | Ann | 2 |
I am trying to fetch all the physician where specialty area is 2
This is my snippet of code
public function getAllPhysicianAction($specId)
{
$id = $this->getDoctrine()->getRepository('Bundle:SpecArea')
->find($specId); //assuming that this returns all the id from the specialty table
$allPhysician = $id->getPhysician()->... //kind of lost here
}
How can I retrieve all the records from the physician table using the specialty Id?
I believe that you can just call findBy on your physician repository.
/**
* #Route("/physicians/{specId}", name="getAllPhysician")
*/
public function getAllPhysicianAction($specId)
{
$allPhysician = $this->getDoctrine()
//call the repository of your physician table
->getRepository('Bundle:physician')
->findBy(['specfk' => $specId]);
var_dump($allPhysician);
}
Use the findBy() method of the "physician" repository:
(You didn't post your actual entities so I'm guessing the field/entity names.)
$spec = $this->getDoctrine()->getRepository('Bundle:SpecArea')->find($specId);
$physicians = $this->getDoctrine()->getRepository('Bundle:Physician')->findBy(['spec' => $spec]);
You can also use $specId ID directly instead of fetching the entire entity from database:
$physicians = $this->getDoctrine()->getRepository('Bundle:Physician')->findBy(['spec' => $specId]);
See: Working with Objects - Querying - By Simple Conditions

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
}

Categories