Laravel Get Result Ordred By For an eager Loaded Relation - laravel

I have:
'cards' table
-id
-name
'card_categories' Table
id
card_id
category_id
'categories' Table
id
name
index
I'am Loading The Card then Eager load the Relation, what i would like to do is when doing this :
Card::with('ctrCategories.category').......;
I would like that all loaded category from categories will be sorted by Index just the categories.
I spent the hole day doing everything , but no solution:
I tried this:
$card = Card::findOrFail($id);
return $card->with('cardCategories')
->with('ctrCategories.category')
->with('ctrCategories.arguments')
->orderBy('ctrCategories.category.index')->get();
I also tried this approach:
$data = $this->card
->with([
'roles' => function ($q) {
$q->with(['tabs' => function ($q) {
$q->with(['department' => function ($q) {
$q->with(['panel' => function ($q) {
$q->orderBy('position', 'asc');
}])->orderBy('position', 'asc');
}])->orderBy('position', 'asc');
}])->orderBy('position', 'asc');
}
])
->findOrFail($id);
=====EDIT=====
I writed the SQL query and i got the result i want Now i want to transform it to Laravel Eloquent or DB query:
select cards.id,
cards.name,categories.name,categories.id,categories.index
from cards
inner join card_categories on cards.id = card_categories.card_id inner join categories on categories.id = card_categories.category_id
where cards.id = 120
AND cards.support_id= categories.support_id
order by categories.index asc
any help ? I can't figure it out after couple of hours of testing

Related

how to write where condition in relation table in Laravel in query

I have 3 table that is Resort, Booking, Expense, these tables are join with relation. the code is given below,
$resorts = Resort::where('status',1)->with('bookings')->withSum('bookings', 'amount')
->with('expenses')->withSum('expenses', 'amount')->get();
I want to sort this table using the date field. how could I use the wherebetween in this query for bookings and expense?
you can pass array in with() like this
$resorts = Resort::where('status', 1)
->with(
['bookings' => function ($q) {
$q->wherebetween('colName', ['startDate','endDate']);
}]
)->withSum('bookings', 'amount')
->with(
['expenses' => function ($q) {
$q->wherebetween('colName', ['startDate','endDate']);
}]
)->withSum('expenses', 'amount')
->get();
ref link https://laravel.com/docs/8.x/eloquent-relationships#constraining-eager-loads

Laravel order by eagerly loaded column

I am using laravel eager loading to load data on the jquery datatables. My code looks like:
$columns = array(
0 => 'company_name',
1 => 'property_name',
2 => 'amenity_review',
3 => 'pricing_review',
4 => 'sqft_offset_review',
5 => 'created_at',
6 => 'last_uploaded_at'
);
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company','notices']);
$company_search = $request->columns[0]['search']['value'];
if(!empty($company_search)){
$query->whereHas('company', function ($query) use($company_search) {
$query->where('name','like',$company_search.'%');
});
}
$property_search = $request->columns[1]['search']['value'];
if(!empty($property_search)){
$query->where('properties.property_name','like',$property_search.'%');
}
if(!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id',Auth::user()->company_id);
}
$query->orderBy($order,$dir);
if($limit != '-1'){
$records = $query->offset($start)->limit($limit);
}
$records = $query->get();
With this method I received error: Column not found: 1054 Unknown column 'company_name' in 'order clause' .
Next, I tried with following order condition:
if($order == 'company_name'){
$query->orderBy('company.name',$dir);
}else{
$query->orderBy($order,$dir);
}
However, it also returns similar error: Column not found: 1054 Unknown column 'company.name' in 'order clause'
Next, I tried with whereHas condition:
if($order == 'company_name'){
$order = 'name';
$query->whereHas('company', function ($query) use($order,$dir) {
$query->orderBy($order,$dir);
});
}else{
$query->orderBy($order,$dir);
}
But, in this case also, same issue.
For other table, I have handled this type of situation using DB query, however, in this particular case I need the notices as the nested results because I have looped it on the frontend. So, I need to go through eloquent.
Also, I have seen other's answer where people have suggested to order directly in model like:
public function company()
{
return $this->belongsTo('App\Models\Company')->orderBy('name');
}
But, I don't want to order direclty on model because I don't want it to be ordered by name everytime. I want to leave it to default.
Also, on some other scenario, I saw people using join combining with, but I am not really impressed with using both join and with to load the same model.
What is the best way to solve my problem?
I have table like: companies: id, name, properties: id, property_name, company_id, notices: title, slug, body, property_id
The issue here is that the Property::with(['company','notices']); will not join the companies or notices tables, but only fetch the data and attach it to the resulting Collection. Therefore, neither of the tables are part of the SQL query issued and so you cannot order it by any field in those tables.
What Property::with(['company', 'notices'])->get() does is basically issue three queries (depending on your relation setup and scopes, it might be different queries):
SELECT * FROM properties ...
SELECT * FROM companies WHERE properties.id in (...)
SELECT * FROM notices WHERE properties.id in (...)
What you tried in the sample code above is to add an ORDER BY company_name or later an ORDER BY companies.name to the first query. The query scope knows no company_name column within the properties table of course and no companies table to look for the name column. company.name will not work either because there is no company table, and even if there was one, it would not have been joined in the first query either.
The best solution for you from my point of view would be to sort the result Collection instead of ordering via SQL by replacing $records = $query->get(); with $records = $query->get()->sortBy($order, $dir);, which is the most flexible way for your task.
For that to work, you would have to replace 'company_name' with 'company.name' in your $columns array.
The only other option I see is to ->join('companies', 'companies.id', 'properties.company_id'), which will join the companies table to the first query.
Putting it all together
So, given that the rest of your code works as it should, this should do it:
$columns = [
'company.name',
'property_name',
'amenity_review',
'pricing_review',
'sqft_offset_review',
'created_at',
'last_uploaded_at',
];
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company', 'notices']);
$company_search = $request->columns[0]['search']['value'];
$property_search = $request->columns[1]['search']['value'];
if (!empty($company_search)) {
$query->whereHas(
'company', function ($query) use ($company_search) {
$query->where('name', 'like', $company_search . '%');
});
}
if (!empty($property_search)) {
$query->where('properties.property_name', 'like', $property_search . '%');
}
if (!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id', Auth::user()->company_id);
}
if ($limit != '-1') {
$records = $query->offset($start)->limit($limit);
}
$records = $query->get()->sortBy($order, $dir);

Laravel Eloquent with() selecting specific column doesn't return results

Say I have 2 models, Category and POI where 1 Category can have many POIs.
$categoryDetails = Category::with([
'pois' => function ($query) {
$query->where('is_poi_enabled', true);
},
])->findOrFail($id);
The above query returns results from the specific Category as well as its POIs.
However, with the query below:
$query->select('id', 'name')->where('is_poi_enabled', true);
The POIs become empty in the collection.
Any idea why this is happening? When added a select clause to the Eloquent ORM?
While doing a select it's required to fetch the Relationship local or Primary key.
For an example POIs table contains category_id then it's required to select it
Try this:
$categoryDetails = Category::with([
'pois' => function ($query) {
$query->select(['id', 'category_id', 'is_poi_enabled'])
->where('is_poi_enabled', true);
},
])->findOrFail($id);
Good luck!

Laravel Relationships with 3 tables and two pivot tables

Hi I used Laravel relationships with many to many pivot tables without problems but i can't get around the logic i need to write to create a relation between 3 models using 2 pivot tables to execute a query like the one below:
select * from product
left join product_to_category on product_to_category.product_id = product.product_id
left join category on product_to_category.category_id = category.category_id
left join category_to_brand on category_to_brand.category_id = category.category_id
left join brand on brand.brand_id = category_to_brand.brand_id
where brand.key = 'furniture-hire-uk'
and category.slug = 'chair-hire'
the table structure is as follows:
product
product id
some more feilds
category
category id
some more feilds
brand
brand_id
key
some more feilds
product_to_category
product_id
category_id
category_to_brand
category_id
brand_id
Using relationships:
// assuming relations:
categories: Product belongsToMany Category
brands: Category belongsToMany Brand
// and tables according to your question:
product, category, brand
$slug = 'chair-hire';
$key = 'furniture-hire-uk';
Product::whereHas('categories', function ($q) use ($slug, $key) {
$q->where('category.slug', $slug)
->whereHas('brands', function ($q) use ($key) {
$q->where('brand.key', $key);
});
})->get();
Or manual joins:
Product::join('product_to_category as pc', 'product.id', '=', 'pc.product_id')
->join('category', function ($j) use ($slug) {
$j->on('category.id', '=', 'pc.category_id')
->where('category.slug', '=', $slug);
})
->join('category_to_brand as cb', 'category.id', '=', 'cb.category_id')
->join('brand', function ($j) use ($key) {
$j->on('brand.id', '=', 'cb.brand_id')
->where('brand.key', '=', $key);
})
->get(['product.*'])

How to select field in another table join by eager loading in Laravel

I got category_to_news and news_main table
category_to_news
news_id int
name varchar
title timestamp
news_main
id int
title varchar
image varchar
created_at timestamp
how to return by news_main's field and category_news's field ? I've tried this method and it's not work
$posts = Categorytonews::with(array(
'Newsmain' => function($query)
{
$query->orderBy('id', 'DESC')->select(array('title', 'id', 'created_at', 'image'));
}
))
->get( );
You need join for this because with() runs another query, so ordering there won't do the job:
$posts = Categorytonews::with('Newsmain') // get all fields from Newsmain
->join('news_main', 'category_to_news.news_id', '=', 'news_main.id') // join for ordering
->orderBy('news_main.id','desc') // order by joined field
->get('category_to_news.*'); // select only main table, you don't need joined fields
// on Categorytonews model - they will be loaded by with()
$posts = Categorytonews::with(array('Newsmain' => function($query)
{
$query->select(array('title', 'id', 'created_at', 'image'))->orderBy('id', 'DESC');
}))->get();

Resources