Laravel query a model in a nested query? - php

I have an Appointment model that has a relation to Employee and an Employee to a User. I am trying to query a list of appointments between specific dates ($weekStart and $weekEnd) and retrieve the appointments as well as the related Employees and Users.
So far this works, it returns all my Clients with all appointments and the assigned Employees/Users (Employees belong to User).
'clients' => Client::with('careType','appointments.employees.user')->get(),
However I wish to specify between dates on the appointments model. So I have this:
$data = [
'clients' => Client::with(['appointments' => function ($query) use ($weekStart, $weekEnd) {
$query->whereBetween('starts_at', [$weekStart, $weekEnd]);
}])->get(),
];
In the above what is the syntax to also retrieve the employees and user models when I have a sub query?

You just add your other models in your Client's with() array.
$data = [
'clients' => Client::with(['appointments' => function ($query) use ($weekStart, $weekEnd) {
$query->whereBetween('starts_at', [$weekStart, $weekEnd]);
}, 'appointments.employees.user'])->get(),
];

Related

How to groupBy() Eloquent collection by column?

I have a program table that refers to location, major, grade, type table. I want to group programs based on their location to major and type collection. I can group them by garde_id, but I want to have a grade name instead of grade id.
$programs = Program::whereLocation_id($location->id)
->with('location', 'department', 'major', 'grade')
->latest()->get();
$programs->groupBy('grade_id');
Result
[
1 => ['department-name','major-name','title'],
2 => ['department-name','major-name','title']
]
Expected
[
'phd' => ['department-name','major-name','title'],
'M.S' => ['department-name','major-name','title']
]
What is the best query to accomplish this in Eloquent?
Another solution for your case would be:
$grouped = $programs->groupBy(function ($item, $key) {
return $item['grade']->name; // Setting grade name as key
});
You can retrieve programs from grades and you'll have the expected result.
I guess the relationship name in Grade model is called 'programs'
$locationId = $location->id;
$grades = Grade::whereHas('programs', function($query) use ($locationId) {
$query->where('location_id', $locationId);
})->with(['programs' => function ($query) use ($locationId) {
$query->where('location_id', $locationId);
$query->with('location','department','major');
return $query;
}])->get();
You will have a collection of grades which each have their programs in it.
You can also group by grades name:
$grades->groupBy('name');

Problem with fetching data from database in one to many polymorphic relations in Laravel

I have one to many polymorphic relationship in Laravel and I am trying to fetch data using eloquent query. I have Favorite model with favorites table
id user_id favoritable_id favoritable_type
1 17 1 App\Models\ProfileImage
2 10 1 App\Models\PostVideo this is some other model
and profile_images table with
id user_profile_id title path
1 17 etc etc
I need to fetch all profile_images from profile_images table that correspond to data in favorites table. So id from profile_images to match favoritable_id, user_profile_id to matches user_id and favoritable_type to match App\Models\ProfileImage from favorites table. Any help is appreciated. Here is my code.
Controller
public function getProfileImages()
{
$profileimage = ProfileImage::whereColumn('id', 'favoritable_id')->first();
// I AM BASICALLY STUCK HERE WITH $profileimage !!!
$favoriteProfileImages = $profileimage->favorites()->where([
'user_id' => auth()->id(),
'favoritable_id' => $profileimage->id,
'favoritable_type' => ProfileImage::class
])->get();
return $favoriteProfileImages;
}
Option 1
Assuming that there is no relation between User and Favorite models, get all the PostImage records which have an entry in favorites table for the currently logged in user.
$profileImages = Favorite::where('user_id', auth()->id())
->with([
'favoritable' => fn($query) => $query->where('favoritable_type', ProfileImage::class)
])
->get()
->pluck('favoritable')
->flatten()
->all();
Option 2
Assuming that User hasMany Favorite records - hasMany relationship exists
class User extends Model
{
public function favorites()
{
return $this->hasMany(Favorite::class);
}
// ...rest of the class code
}
Get the results via the User model
$profileImages = User::with([
'favorites' =>
fn($query) => $query->where('favoritable_type', ProfileImage::class)->with('favoritable')
])
->where('id', auth()->id())
->first()
->favorites
->pluck('favoritable')
->flatten()
->all();

Laravel - Displaying fields with many to many relationship according field in pivot table

I have this database structure
table users table office_user table offices
----------- ----------------- -------------
id * id * id *
full_name user_id name
office_id
joined_at
So in my project every office has many users and user can be joined to many offices in date (joined_at)
User.php model
public function offices()
{
return $this->belongsToMany('App\Office)->withPivot('joined_at');
}
Office.php model
public function users()
{
return $this->belongsToMany('App\User)->withPivot('joined_at');
}
OfficeController.php
public function show(Office $office)
{
$users = User::with(array('phones', 'offices' , function($query)
{
$query->orderBy('joined_at', 'desc');
}))->get();
return view('dashboard.offices.show', compact(['office', 'users']));
}
I need two things :
1- Get current users list for every office
2- Count of current users in every office
I already achieve this:
<h3>{{ $office->name }}</h3><span>{{ $office->users->count() }}</span>
#foreach ($office->users as $user)
<li>{{ $user->full_name }}</li>
#endforeach
But the result is not as expected it gives me all users in certain office and count of them regardless there joined date
I want the list of last joined users to this office and count of them according joined_at field in pivot table
Thank you and Sorry for my english
But the result is not as expected it gives me all users in certain office and count of them regardless there joined date
When you do $office->users->count() that is the expected behavior because you are retrieve all the associated users of every office at any time, so given that you returned all this users, the count() executed in the collection will count all of them.
Your pivot attribute is just a timestamp, so how would you reduce the number of users returned? users that joined the office today/in the last hour/in the last 15 min maybe?
If so, you can add constrains to your count() method to get the results you want.
As an example, in the following lines we are gonna constraint the associated offices that has a joined_at that belongs to today:
public function show(Office $office)
{
$users = User::with([
'phones',
'offices' => function ($offices) {
$offices->whereDate('joined_at', '>', now()->startOfDay());
},
])->get();
return view('dashboard.offices.show', compact([office, 'users']));
}
Check this section of the documentation:
Constraining Eager Loads
Sometimes you may wish to eager load a relationship, but also specify
additional query conditions for the eager loading query. Here's an
example:
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
In this example, Eloquent will only eager load posts where the post's
title column contains the word first. You may call other query
builder methods to further customize the eager loading operation:
$users = App\User::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc');
}])->get();

CakePhp3 select() in query more than one tier

Is it possible to get columns of tables which are two or more tables remote by using select()?
$rooms = TableRegistry::get('Rooms')
->find()
->contain(['Levels.Buildings'])
->toArray();
... this works, but returns ervery column of the three tables
$rooms = TableRegistry::get('Rooms')
->find()
->select(['Buildings.name'])
->contain(['Levels.Buildings'])
->toArray();
... this returns nothing, althought the generated select statement seems to be correct
You can only select fields in the primary query if you are handling a one-to-one relationship (i.e. hasOne or belongsTo). This is presumably your issue. In which case you need to specify the fields to include from your has-many relationship in the contain itself:-
$rooms = TableRegistry::get('Rooms')
->find()
->contain([
'Levels' => [
'Buildings' => [
'fields' => 'name'
]
]
])
->toArray();
This is because CakePHP will perform a second separate query to retrieve the has-many associated model data for which you need to specify the query conditions within the contain.

Condition for related table ORM Kohana

For example I have 3 tables:
songs(id, song_name)
song_category(id, song_id, category_id)
categories(id, name)
I want to get songs which have categories with id higher than 5. I want to do it using ORM, not with simple SQL query. Is it possible to do it with one query like this:
$songs = ORM::factory("songs")->where("category.id > 5")
No, you cannot do this with a single Kohana ORM call.
The best way I have found to do it is something like this, which makes a modification to the SQL query that the ORM will generate:
// Get the basic "song" model
$songs = ORM::factory("songs");
// Get the information about how it is connected to
// the "category" model using the `through` model
$song_relations = $results->has_many();
$category_relation = $song_relations['categories'];
$through = $category_relation['through'];
// Join on `through` model's target foreign key (far_key) and `target` model's primary key
$join_col1 = $through.'.'.$category_relation['foreign_key'];
$join_col2 = $songs->object_name().'.'.$songs->primary_key();
$songs->join($through)->on($join_col1, '=', $join_col2);
// Now, filter on the
$songs->where($through.'.'.$category_relation['far_key'], '>', 5);
$arr = $results->find_all()->as_array();
You could save some code by hardcoding the values in the join method call, but this way leverages the ORM relation definitions that you already have.
This assumes that your Song model has the following code in it:
protected $_has_many = [
'categories' => [
'model' => 'category',
'through' => 'song_category',
'foreign_key' => 'song_id',
'far_key' => 'category_id',
]
];

Categories