Laravel order by function for 3-level relation - laravel

I have this function for ordening a column in a 2-level relation.
public function sortByRegionUp(Request $request)
{
$hotels = Hotel::with('region')
->orderBy(Region::select('name')
->whereColumn('id', 'hotels.region_id'), 'asc')
->paginate(10);
return view('hotel.index', compact('hotels'));
}
How do i convert this code for use in a 3-level relation (hasManyTrough)? I want to order hotels by country->name.
Hotel
id
region_id
name
...
Region
id
country_id
name
...
Country
id
name
...

public function sortByRegionUp(Request $request)
{
$hotels = Hotel::with('region')
->withCount(['region as region_name_for_order_by' => function($query) {
$query->select('name');
}])->orderBy('region_name_for_order_by', 'ASC')->paginate(10);
return view('hotel.index', compact('hotels'));
}

Add belongsTo relation in Region Model
public function country(){
return $this->belongsTo(Country::class, 'country_id');
}
public function sortByRegionUp(Request $request)
{
$hotels = Hotel::with('region')
->withCount(['region.contry as contry_name_for_order_by' => function($query) {
$query->select('name');
}])->orderBy('contry_name_for_order_by', 'ASC')->paginate(10);
return view('hotel.index', compact('hotels'));
}

Related

Sort eloquent model with relationships Laravel

I have a model that I want to sort based on a relationship property.
First model "DeviceType":
public function make()
{
return $this->hasMany(DeviceMake::class);
}
Second model: "DeviceMake":
public function type()
{
return $this->hasOne(DeviceType::class, 'id', 'device_type_id');
}
public function model()
{
return $this->hasMany(DeviceModel::class);
}
Controller:
$type = DeviceType::with(['make'])->where('id', '=', $device_type_id)->first();
Table name is device_makes and I want to sort it by name. How can I do this?
And what about?
$type = DeviceType::with(['make' => function ($query) {
$query->orderBy('name', 'asc');
}])->where('id', '=', $device_type_id)->first();
Please note that first() will only return the first model that matches your query whereas get() will return all of them.
Maybe you could try this instead in your Model:
public function make() {
return $this->hasMany(DeviceMake::class)->orderBy('name', 'asc');
}

Laravel : Search Query Within Relationship

When I am adding a new post in my app there is a 7 tables to affect when I add single post. To fetch all posts with all post data my simple query look like:
$userPost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->offset($offset)
->limit($limit)
->whereStatus("Active")
->whereIn('product_id', $userApprovalProductIDs)
->orderBy('id','desc')
->get();
So it is retrun all data which I want. Now I want to implement search query within all tables, currently I am able to search only posts table.
If I am doing search on category table with categoryTitle I am trying to code like
where('category.title','=', $serachTitle)
But it is not working in my case.
POST model relationship :
public function user() {
return $this->belongsTo(User::class);
}
public function product() {
return $this->belongsTo(Product::class);
}
public function postattribute() {
return $this->hasMany(PostAttribute::class);
}
POSTATTRIBUTES model relationship :
public function post() {
return $this->belongsTo(Post::class);
}
public function attribute() {
return $this->belongsTo(Attribute::class);
}
ATTRIBUTES model relationship :
public function category() {
return $this->belongsTo(Category::class);
}
public function attributes() {
return $this->belongsTo(Attribute::class);
}
How can I do this ?
To apply filter on your nested relations you could use whereHas
$userPost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->offset($offset)
->limit($limit)
->whereStatus("Active")
->whereIn('product_id', $userApprovalProductIDs)
->whereHas('postattribute.attribute.category', function ($query) use($serachTitle) {
$query->where('title', '=', $searchTitle);
})
->orderBy('id','desc')
->get();
Querying Relationship Existence
From comments what i understood is you want to know how to search within each relation for a post , I already added an example to search with category title
->whereHas('postattribute.attribute', function ($query) use($var) {
$query->where('some_field_of_attribute_table', '=', $var);
})
->whereHas('postattribute', function ($query) use($var) {
$query->where('some_field_of_postattribute_table', '=', $var);
})

Relationships in Laravel Models

How can I write this without a join for a scope in a Laravel model as the 'id' field becomes ambiguous
/**
* Return events that social category name
*/
public function scopeWithSocialEvents($query)
{
return $query->join('categories', 'events.event_type_id', '=', 'categories.id')
->where('categories.name', 'social');
}
Use this:
public function eventType()
{
return $this->belongsTo(Category::class);
}
public function scopeWithSocialEvents($query)
{
return $query->whereHas('eventType', function($query) {
$query->where('name', 'social');
});
}

Laravel Eloquent how to get all products in a category with slug

My Productcategory.php has
public function products()
{
return $this->hasMany('App\Models\Product');
}
And Product.php has
public function productcategory()
{
return $this->belongsTo('App\Models\Productcategory', 'category_id');
}
Now my route is
Route::get('gallery/{slug}', 'GalleryController#index');
When URL is something like gallery/print-pattern-client-work, how can I get all products with the same category? I have the following but category_id is an integer and not a slug. So I am not so sure how to do it.
public function index()
{
$categoryslug = Request::segment(2);
$products = Productcategory::with('products')->where('category_id',$categoryslug)->get();
...
}
This assumes you have a column named "slug" in your product_categories table. And that your described relations work well.
You could make an accessor in Product.php
public function scopeFindByCategorySlug($query, $categorySlug)
{
return $query->whereHas('productcategory', function ($query) use ($categorySlug) {
$query->where('slug', $categorySlug);
});
}
Then in your controller you call this:
public function index(Request $request, $slug)
{
$products = Product::findByCategorySlug($slug)->get();
}
Edit:
As mentioned in comments there is no actual need for an accessor. This is basically all you need (in controller):
public function index(Request $request, $slug)
{
$products = Product::whereHas('productcategory', function ($query) use ($categorySlug) {
$query->where('slug', $categorySlug);
})->get();
}
Don't
$categoryslug = Request::segment(2);
Use $slug
public function index($slug)
{
$products = Productcategory::with('products')->where('category_id',$slug)->get();
...
}
As you're using Laravel, you should use Laravel's Many to Many Relationships like this:
Your table structure would be like:
- products
- id
- name
- ...
- categories
- id
- name
- slug
- ...
- category_product
- id
- category_id
- product_id
- ...
Your models should be like this:
class Product extends Model {
public function categories() {
$this->belongsToMany(Category::class, 'category_product');
}
}
class Category extends Model {
public function products() {
$this->belongsToMany(Product::class, 'category_product');
}
}
and you can fetch all the products for a particular $category_slug like this:
$category = Category::where('slug', $category_slug)->first();
if($category) {
$products = $category->products;
}

Records where value is not equal to current value

I have 7 Departments and an Employee that is assigned to 2 of them through a polymorphic join model called DepartmentItem. When I run the following I expect to get 5 records that the employee does not belong to, but instead I get all 7.
$employee = \App\Employee::find(1);
$departments = \App\Department::join('department_items', 'department_items.department_id', '=', 'departments.id')
->select('departments.*')
->groupBy('departments.id')
->where('company_id', $employee->company_id)
->where('department_items.item_id', '!=', $employee->id)
->where('department_items.item_type', 'employee')
->get();
dd($departments);
This returns 7 departments when it should only return 5. When I change '!=' to '=' it returns the 2 departments that the employee is assigned to.
Here are the model relations:
// Company
public function departments() {
return $this->hasMany(Department::class);
}
public function employees() {
return $this->hasMany(Employee::class);
}
// Department
public function company() {
return $this->belongsTo(Company::class);
}
public function employees() {
return $this->morphedByMany(Employee::class, 'item', 'department_items');
}
// DepartmentItem
public function department() {
return $this->belongsTo(Department::class);
}
public function item() {
return $this->morphTo();
}
// Employee
public function company() {
return $this->belongsTo(Company::class);
}
You should use <> instead of != as where clause method takes mysql operators.
So your code should be like this:
$departments = \App\Department::join('department_items', 'department_items.department_id', '=', 'departments.id')
->select('departments.*')
->groupBy('departments.id')
->where('company_id', $employee->company_id)
->where('department_items.item_id', '<>', $employee->id)
->where('department_items.item_type', 'employee')
->get();
Hope this helps!

Resources