laravel orderby nested related model - php

I have model with name "Date" which has relationship (one-to-one) with "Tour" and "Tour" Model has relationship (many-to-many) with "Type" Model.
I want to order my Date Records Based on "Type" name. Unfortunately I don't have any clue to do it with eloquent.
Date model:
public function Tour()
{
return $this->belongsTo('\App\Tour');
}
Tour model:
public function Date()
{
return $this->hasOne('\App\Date','tour_id');
}
public function Types()
{
return $this->belongsToMany('\App\Type');
}
Type model:
public function Tours()
{
return $this->belongsToMany('\App\Tour');
}
and my controller for output:
public function tourList()
{
$dates = new Date();
$dates = $dates->orderBy('id','asc')
->paginate(6)
->appends([
'sort_price' => request('sort_price'),
'minmax' => request('minmax'),
'type' => request('type')
]);
return view('primary.Tour.list', compact(['dates']));
}

$dateRes = Date::join('type_tour as TT', 'TT.tour_id', '=', 'date.tour_id')
->join('type as T','TT.type_id','=','T.id')
->orderBy('T.name')
->get();
See if it is work for you.

if you want to order the result based on nested relation column, you must use a chain of joins:
$result= Date::join('tours','tours.id','=','dates.tour_id')
->leftJoin('type_tour','type_tour.tour_id','=','tours.id')
->leftJoin('types','types.id','type_tour.type_id')
->orderBy('types.name')->get();
make sure the relation middle table between tours & types table is type_tour
it might be tour_type or something else ...
please note that if you want to order by multiple columns you could add 'orderBy' clause as much as you want:
->orderBy('Types.id', 'DESC')->orderby('Types.name', 'ASC') //... ext
check my answer here:
https://stackoverflow.com/a/61194625/10573560

Related

Order data by pivot table when try to use With

I have tables Polfzms <- Genes
Polfzm model have next relation
public function gene()
{
return $this->belongsTo('App\Gene');
}
I need get all data from Polfzms table with data from Genes table and order it by name from pivot table (Genes). I try next
$data = Polfzm::with([
'gene' => function ($query) {
$query->orderBy('name', 'asc');
},
])->get();
but it not order data by name. How can I do it?
You could try to set this in the relationship definition:
Polfzm.php
public function gene()
{
return $this->belongsTo('App\Gene')->orderBy('name', 'asc');
}
Then in your controller:
$data = Polfzm::with('gene')->get();
If I understand correctly, you could use a collection sortBy helper for this one.
An example could be:
$data = Polfzm::with('gene')
->get()
->sortBy(function ($polfzm) {
return $polfzm->gene->name;
});

How OrderBy afterwards HasMany and BelongsTo Relationships

I created a relationship between the "Review, Games and Info" tables, unfortunately, though, the main table is Games, and he orders me all for Games, While I would like to order the ID of "review" table.
Models: Review
public function games()
{
return $this->hasMany('App\Models\Giochi', 'id_gioco', 'id');
}
Models: Giochi
public function review()
{
return $this->belongsTo('App\Models\Review', 'id', 'id_gioco');
}
public function infogiochi()
{
return $this->belongsTo('App\Models\InfoGiochi', 'id', 'id_gioco');
}
Models: InfoGiochi
public function games()
{
return $this->hasMany('App\Models\Giochi', 'id', 'id_gioco');
}
Controller:
$review = Giochi::with('Review','InfoGiochi')->orderBy('id','DESC')->get();
Here is a screenshot of my json:
How do I order content for review table IDs?
You have 2 options. You use a join and order in the sql statement or you order it after retrieving the results in the collection.
Using Join
Giochi::select('giocos.*')
->with('Review','InfoGiochi')
->leftJoin('reviews', 'reviews.id', '=', 'giocos.id_gioco')
->orderBy('reviews.id','DESC')
->get();
Sorting Collection
Giochi::with('Review','InfoGiochi')
->get()
->sortByDesc(function($giochi) {
return $giochi->review->id;
});
This would be the shortest version to sort on the collection:
Giochi::with('review')
->get()
->sortByDesc('review.id');
You can modify your relationship query when you fire it:
Giochi::with([
'Review' => function ($query) { return $query->orderBy('id','DESC'); },
'InfoGiochi'
])->orderBy('id','DESC');
You can try with a raw query or you can use ->orderBy() directly on review function.

Laravel eloquent get relation count

I use Laravel 5.3.
I have 2 tables :
Articles
---------
id
cat_id
title
And
Category
---------
id
parent_id
title
I have defined my relations in my models :
// Article model
public function category()
{
return $this->belongsTo(Category::class);
}
// Category model
public function children()
{
return $this->hasMany(Category::class, 'parent_id', 'id');
}
Is there an easy way using Eloquent to have a list a categories with count of articles. The difficulty is that I want to group categories where id_parent = 0, i.e. I want to display only parent categories with count of articles in children.
I tried something like that :
$category = new \App\Models\Category();
$categoryTable = $category->getTable();
return $category->leftJoin('article', 'article.cat_id', '=', 'category.id')
->whereIn('article.cat_id', function($query)
{
$query->select('cat_id')
->from('categories')
->where('categories.parent_id', ???)
->orWhere($this->tableName .'.cat_id', $id);
})
->groupBy('cat_id');
But I am lost...
you can use withCount(). It is available from 5.3 version
for more info about eloquent visit : https://laravel.com/docs/5.3/eloquent-relationships
Define a articles() relation in your Category model as:
public function articles()
{
return $this->hasMany(Article::class, 'cat_id');
}
Then you can try it as:
Category::where('parent_id', 0)->withCount('articles')->get();
You can use the hasManyThrough() Eloquent method to fetch all of the childrens' Articles, then add the article counts together in a nice little getter. I added the getter to the $appends array on the model to help illustrate it in the Tinker output.
class Category extends Model
{
protected $appends = [
'articleCount'
];
public function articles()
{
return $this->hasMany(Article::class);
}
public function children()
{
return $this->hasMany(Category::class, 'parent_id');
}
public function childrenArticles()
{
return $this->hasManyThrough(Article::class, Category::class, 'parent_id');
}
public function getArticleCountAttribute()
{
return $this->articles()->count() + $this->childrenArticles()->count();
}
}
Here's the Tinker output:
Psy Shell v0.8.0 (PHP 7.0.6 — cli) by Justin Hileman
>>> $cat = App\Category::first();
=> App\Category {#677
id: "1",
name: "Cooking",
parent_id: null,
created_at: "2016-12-15 18:31:57",
updated_at: "2016-12-15 18:31:57",
}
>>> $cat->toArray();
=> [
"id" => 1,
"name" => "Cooking",
"parent_id" => null,
"created_at" => "2016-12-15 18:31:57",
"updated_at" => "2016-12-15 18:31:57",
"articleCount" => 79,
]
>>>
If you want to restrict your Category query to ones that have children that have articles, you could do that using the has() method:
Category::has('children.articles')->get();
Here's more on the has() method:
https://laravel.com/docs/5.3/eloquent-relationships#querying-relationship-existence
And the hasManyThrough() method:
https://laravel.com/docs/5.3/eloquent-relationships#has-many-through
This should work:
$category
->where('categories.parent_id', 0)
->leftJoin('article', 'article.cat_id', '=', 'categories.id')
->select('categories.id', \DB::raw('COUNT(article.id)'))
->groupBy('categories.id')
->get();
The above query will get you category IDs and count of all articles that belong to the category.
After reading your question and comments again, if I understand correctly you want to get the count of all articles that belong to those categories (with parent_id = 0) + the count of articles that belong to sub categories (those with parent_id = (id of some category)).
Now I have no way of testing this easily, but I think something along these lines should work for that.
$category
->where('categories.parent_id', 0)
->leftJoin('article', 'article.cat_id', '=', 'categories.id')
->leftJoin('categories as c2', 'c2.parent_id', '=', 'categories.id')
->leftJoin('article as a2', 'a2.cat_id', '=', 'c2.id')
->select('categories.id', \DB::raw('(COUNT(article.id)) + (COUNT(a2.id)) as count'))
->groupBy('categories.id')
->get();
That beign said, I think you're better of having a column named count in categories and update it each time a new article gets added. For performance.
public function NoOfStudent()
{
return $this->hasMany(UserAssignment::class,'assignment_id','id');
}
$assignment = Assignment::select('id','batch_id','title','description','attachment','last_submission_date',DB::raw('(CASE WHEN type = 9 THEN "Quiz Type" ELSE "Descriptive" END) AS assignment_type'),DB::raw('(CASE WHEN status = 1 THEN "Assigned" ELSE "Not Assigned" END) AS status'))
->with('assignmentBatch:id,batch_number')
->where('assignments.instructor_id',auth('api')->user()->id)
->orderBy('created_at','DESC');
if(!$request->user_id){
$assignment =$assignment->withCount('NoOfStudent');
}
In regards to Carlos_E.'s answer.
You can improve the query by using whereHas instead of using whereIn:
$agents = Agents::whereHas('schedule')
)->with('schedules')->get();
I am sure somebody is still going through this, I was able to solve it the following way, suppose I have an Agent model and a Schedule model, i.e. one agent may have many schedules:
class Schedule extends Model {
public function agent() {
return $this->belongsTo(Agent::class, 'agent_id');
}
}
class Agent extends Model {
public function user(){
return $this->belongsTo(User::class);
}
public function schedules(){
return $this->hasMany(Schedule::class);
}
}
Well some agents may not necessarily have schedules assigned, thus, I filtered those before calling the with() method, like this:
$agents = Agents::whereIn(
'id',
Schedule::distinct()->pluck('agent_id')
)->with('schedules')->get();
Hope this helps!.

Laravel Datatables Sorting Appended Fields

My Model Items is related to Rooms, which is related to Buildings, which is related to Locations.
Short: Items belongsTo Rooms belongsTo Buildings belongsTo Locations
At the index function of the ItemController I want to show a table of Items. I use Laravel Datatables. It works for 'simple' tables, but I ran into the problem of sorting/searching custom/appended fields, because they are not in the table of course.
Basically I want to join the Room, Building and Location Name for each Item in the displaying table.
This is my Items Model:
protected $appends = [
'building_title',
'location_title',
'room_title',
];
public function getLocationTitleAttribute() {
return $this->room->building->location->title;
}
public function getBuildingTitleAttribute() {
return $this->room->building->title;
}
public function getRoomTitleAttribute() {
return $this->room->title;
}
This is my Controller:
public function anyData()
{
return Datatables::of(Item::query())->make(true);
}
What is the best approach to enable sorting/filtering for appended fields?
Thank you for reading.
This is my solution (no appended fields were used):
public function anyData()
{
$items = Item::join('rooms', 'items.room_id', '=', 'rooms.id')
->join('buildings', 'rooms.building_id', '=', 'buildings.id')
->join('locations', 'buildings.location_id', '=', 'locations.id')
->select([
'items.id',
'items.title',
'items.label_number',
'items.fibu_number',
'rooms.title as room_title',
'buildings.title as building_title',
'locations.title as location_title'
]);
return Datatables::of($items)->make(true);
}

Creating a query in Laravel by using `with` and `where`

I'm wondering it would be possible to add a where condition to a with.
Such as:
Comment::with('Users')->where('allowed', 'Y')->get();
I was trying to find a more simple way to make queries avoiding the whereHas method which looks quite verbose:
$users = Comment::whereHas('users', function($q)
{
$q->where('allowed', 'Y');
})->get();
The raw query I want internally to generate should be like so:
select * from comments, users
where users.id = comments.user_id and
users.allowed = 'Y'
I'm used to work with CakePHP in which this queries look very simple:
$this->Comments->find('all', array('Users.allowed' => 'Y'));
The relationships I have defined are:
//Comments.php
public function Users()
{
return $this->belongsTo('Users');
}
//Users.php
public function Comments(){
return $this->hasMany('Comments');
}
You may try this
$users = User::with(array('comments' => function($q)
{
$q->where('attachment', 1);
}))->get();
Update : Alternatively you may use a where clause in your relationship in your User model
// Relation for comments with attachment value 1
// and if hasMany relation is used
public function commentsWithAttachment()
{
return $this->hasMany('Comment')->where('attachment', 1);
}
// Relation for all comments
// and if hasMany relation is used
public function comments()
{
return $this->hasMany('Comment');
}
So, you can just use
// Comments with attachment value 1
User::with('commentsWithAttachment')->get();
// All comments
User::with('comments')->get();
Update : I think you want all comments with users where attachment is 1, if this what you want then it should be Comment not User
Comment::with('user')->where('attachment', 1)->get();
In this case your relation should be
public function user()
{
return $this->belongsTo('User'); // if model name is User
}
Because one comment belongs to only one user.

Categories