sort by relation laravel - php

I need sort products by certain attribute id and his value. I have model Product with relation:
public function attribute()
{
return $this->hasMany('App\Models\ProductAttribute');
}
ProductAttribute model have:
public function attribute()
{
return $this->belongsTo('App\Models\AttributeValue', 'attribute_value_id');
}
I need sort products where attribute_id = 5 and with all values of this attribute. I try do this:
$products = Product::active()->where(function($query) {
$query->whereHas('attribute.attribute', function($q) {
$q->where('attribute_id', 5)->orderBy('value', 'desc');
});
})->get();
But this is not working.
Structure table of model Product Attribute:
id
attribute_value_id
product_id
Structure table of model AttributeValue:
id
attribute_id
value
In value can be numeric values.
Please help me resolve this problem.

You should use joins:
$products = Product::active()
->select('products.*')
->leftJoin('product_attribute', 'product_attribute.product_id', '=', 'products.id')
->leftJoin('attribute_values', function($query){
$query
->on('attribute_values.id', '=', 'product_attribute.attribute_value_id')
->where('attribute_id', '5');
})
->groupBy('products.id')
->orderByDesc('attribute_values.value');
Not sure about table names.

Related

Return data from pivot table with whereIn

So I have Status class which has pivot table relationship with roles:
public function roles():
{
return $this->belongsToMany(Role::class, 'status_role', 'status_id', 'role_id');
}
This is how Status db table looks:
id title
1 status1
2 status2
3 status3
And then my pivot table which looks like this:
status_id role_id
1 2
2 2
And now I want to write query which returns statuses with role_id=2.
Basically it should return data like this: status1, status2 and not include status3.
What I have tryed:
$statuses = Status::query()
->leftJoin('status_role', function ($join) {
$join->on('statuses.id', '=', 'status_role.status_id')
->whereIn('status_role.role_id',[2]);
})
->get();
But now it returns all statuses (status1, status2, status3) it should be only (status1 and status2). How I need to change it?
This query will return all statuses attached to roles with id 2:
Status::query()->whereHas('roles', function($q){
$q->where('id', 2);
})->get();
It uses the whereHas method that can be useful when you need to query relationships.
It can do a lot more, you should check the documentation on this topic: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence
Quick note: whereHas is the "Laravel preferred way" of doing what you are trying to achieve.
However, you should be able to also do it with this query, which is closer to your current code:
$statuses = Status::query()
->join('status_role', function ($join) {
$join
->on('statuses.id', '=', 'status_role.status_id')
->where('status_role.role_id',2);
})
->get();
// I replaced the leftJoin by join, which will exclude all results without roles (e.g. status id 3)
// or even simpler:
$statuses = Status::query()
->join('status_role', 'statuses.id', '=', 'status_role.status_id')
->where('status_role.role_id',2)
->get();

laravel 8 Eloquent query builder

I'm making an attempt to write Eloquent join query but i didn't get the result i wanted.
i have 2 table
products which contains all information about products
category_product contains product_id and category_id
i just want to select all information about products which their category_id is equal to 2
After you have belongsToMany relation between categories and products.
Product::whereHas('categories', function($query){
$query->where('id',2);
})->with('categories')->get();
I can offer you a solution like this
class Product extends Model
{
public function category()
{
return $this->morphToMany(Category::class, 'category_product table');
}
}
class Category extends Model
{
public function product()
{
return $this->morphedByMany(Product::class, 'category_product table');
}
}
in Controller
$products = DB::table('products')
->join('category_product', 'products.id', '=', 'category_product.products_id')
->select('products.*')
->where('category_product.category_id','=',2)
->get();

How to get data from the foreign key in joined table in laravel 5.8

I want to get the details of products in the products table by calling it in the purchase_orders table in laravel5.8.
I try to use inner join but as its result its just values of numbers
$POs = DB::table('purchase_orders')
->join('products', 'purchase_orders.prod_id', '=', 'products.id')
->select('purchase_orders.id as id', 'products.name as name', 'products.cat_id as cat', 'products.size_id as size', 'products.price as price', 'purchase_orders.quant as quant', 'purchase_orders.total as total', 'purchase_orders.created_at as req_date')
->orderBy('purchase_orders.id','DESC')
->get();
Here are the 2 table and the result.
products table
purchase_orders
result
Create a relationship in PurchaseOrders Model:
public function products()
{
return $this->hasMany('App\Models\Product','id','prod_id');
}
You can call the result by:
$res = PurchaseOrder::find($id);
foreach($res->products as $product)
{
echo $product->name;
}
Using join:
$POs = DB::table('purchase_orders')
->join('products', 'purchase_orders.prod_id', '=', 'products.id')
->select('products.*','purchase_orders.id as purchase_id','purchase_orders.total','purchase_orders.status')
->orderBy('purchase_orders.id','DESC')
->get();
if you want categories table too, add another join function.
Try this for a relationship
public function products()
{
return $this->hasMany('App\Models\Product','prod_id','id');
}
public function products()
{
return $this->hasMany('App\Models\Product','prod_id','id');
}
To out put relationship data is like this
$variable->product->name
or
$variable->product['name']

How can I fetch Laravel models by matching a value on a relationship?

I have a User model with attributes like login, ID, age, etc. Another table is user_data with a residence column, for example.
How can I get all users with a specific residence? I have this:
User model:
public function user_data()
{
return $this->hasMany('App\Models\UserData');
}
public function FilterUser($request)
{
if ($request->has('city'))
{
$users = User::with('user_data')->where('residence', 'Warsaw')->get();
}
dd($users);
}
UserData model:
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
Now I get this error:
Column not found: 1054 Unknown column 'residence' in 'where clause' (SQL: select * from `users` where `residence` = warsaw and `users`.`deleted_at` is null)
And another question:
If User is my main model, should I connect it with relationships like above? hasMany() or belongsTo()?
Use the whereHas() query builder method:
$users = User::with('user_data')
->whereHas('user_data', function($query) {
$query->where('residence', 'Warsaw');
})
->get();
Edit - To use the value from $request you need to import the variable to the closure for whereHas():
...
->whereHas('user_data', function($query) use ($request) {
$query->where('residence', $request->city);
})
...
Edit - A query scope may be a better approach. In the User model, add this method:
function scopeInCity($query, $city)
{
return $query->whereHas('user_data', function($q) use ($city) {
$q->where('residence', $city);
});
}
Then you can filter all users by city (outside the model):
User::inCity($request->city)->get();
Use whereHas if you want to get all users that have a relationship with a specific attribute like so:
$users = User::whereHas('user_data', function($q) {
$q->where('residence', 'Warsaw');})->get();

Laravel Eloquent: how to filter reviews of products by product category and/or product brand?

I will describe this situation with more details:
I have a list of products where every product belongs to a certain category and to a certain brand. Some of the products can get reviewed by users.
On /reviews/ page in my Laravel application, I have a list of reviews and select boxes for category and brand along with search button of course.
If user doesn't choose category or brand, all reviews get displayed, paginated, and that's good.
The problem arises when user chooses either category or brand or both and tries to get all the reviews filtered that way.
Reviews table fields: ID, user_id(foreign key users.ID), product_id(foreign key products.ID), text
Products table fields: ID, category_id(foreign key categories.ID), brand_id(foreign key brands.ID), name
Categories table fields: ID, name
Brands table fields: ID, name
Users table fields: ID, username
When I'm listing reviews, I'm simply using:
$reviews = Review::orderBy('id', 'DESC')->paginate(5);
If I would like to filter reviews by user_id, that would be easy as the reviews table contains user_id column,
but, how to filter them by product category and/or product brand?
Here are Review, Product and Category models:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model {
protected $fillable = [];
public function product() {
return $this->belongsTo('App\Product');
}
public function user() {
return $this->belongsTo('App\User');
}
}
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
protected $fillable = [];
public function user() {
return $this->belongsTo('App\User');
}
public function reviews() {
return $this->hasMany('App\Review');
}
public function category() {
return $this->belongsTo('App\Category');
}
}
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model {
protected $fillable = [];
public function products() {
return $this->hasMany('App\Product');
}
}
If I use joins, then $review->user->id, $review->user->username, $review->id are not correct, I'm getting reviews.product_id as $review->id, and products.user_id as $review->user->id in blade template.
I was trying this join variant:
$reviews_query = Review::orderBy('reviews.id', 'DESC')
->Join('products', 'reviews.product_id', '=', 'products.id')
->Join('categories', 'products.category_id', '=', 'categories.id')
->Join('brands', 'products.brand_id', '=', 'brands.id')
->Join('users', 'reviews.user_id', '=', 'users.id')
->where('reviews.active', '=', 1)
->GroupBy('reviews.id')->paginate(5);
And this for filtering by category_id:
if (Input::has('category_id')){
$category_id = Input::get('category_id');
$reviews_query->where('categories.id', $category_id);
}
I'm not sure how to correctly address ambiguous ids such us product_id, review_id, user_id in blade template ($review->id, $review->user->id, all are messed up mutually)
Add hasManyThrough relationship in your category model
public function reviews() {
return $this->hasManyThrough('App\Review', 'App\Product');
}
now you can have all reviews by a category like this
$category->reviews();
you can add other query clauses to it like
$category->reviews()->orderBy('id', 'DESC')->paginate(5);
Try this,
$reviews = DB::table('review')
->join('product', 'product.id', '=', 'review.product_id')
->Join('category', 'product.category_id', '=', 'category.id')
->orderBy('id', 'DESC')->paginate(5);
for more you can visit-
Laravel join with 3 Tables
This may work for you.....
filter all reviews by a specific CategoryID then simply use ->
$categoryID = 1;
Categories::with(['products' => function($product){
$product->with('reviews');
}])->where('id', '=', $categoryID)->get();
also filter all reviews by a specific BrandID then
$brandID = 1;
Brands::with(['products' => function($product){
$product->with('reviews');
}])->where('id', '=', $brandID)->get();

Categories