How can I write this complex query in Laravel? - php

I have a query working perfect but I need it in ORM Laravel.
I just need this query in eloquent Query builder.
SELECT * FROM product where vendor_id in (
SELECT vendor_id from vendor where is_block = 0
);
Scenario : There are two tables. One for Product and other for Vendor.
I want to select product from Product table. Each product belong to a vendor. If vendor is blocked then don't select product.
If is_block attribute is 0 then its mean that vendor is not block. If is_blocked=1 then vendor is blocked. I need to select only products of a vendor whose is_block = 0.

Use the whereHas() method:
Product::whereHas('vendor', function($q) {
$q->where('is_block', 0);
})->get();
Or the whereDoesntHave() method:
Product::whereDoesntHave('vendor', function($q) {
$q->where('is_block', 1);
})->get();
Make sure you've defined the relationship in the Product model:
public function vendor()
{
return $this->belongsTo(Vendor::class);
}

Related

Laravel Relationship Query to load hasMany + BelongsToMany

I need to get brands data in specific collection page but only has more than 1 product.
Here are relations between models.
Brand -> HasMany -> Product
Product <= BelongsToMany => Collection
I was able to get brands data that have more than 1 products for all collections as following:
$brands = Brand::has("products")->get(); //this will return all brands that have more than 1 product.
Now I need to add collection limitation here.
I can get collection from $slug for specific page.
$collection = Collection::where("slug", $slug)->first();
Can anyone please help me how to get brands for specific collection page?
Try this:
$brands = Brand::has("products")
->whereHas('products.collections',function($q) use ($slug){ // your relation to product model
$q->where("slug", $slug);
})
->get();

Laravel 5 / Eloquent - query filtering on belongs-to-many relation

Let's suppose I have these relations in my DB:
Product
id | name
Category
id | name
Product-Category
id | product_id | category_id
I can easily build it using Eloquent's Models using "belongsToMany" relations:
Product has a "categories" public function called "categories" and Category has a "products" public function.
Now, I have a page where the user wants to filter all the products for a given category by clicking on the category name.
The program will pass the category_id to my Controller and now begins the problem.
I can easily do it "by hand" writing this code:
$products = Product::query()
->leftJoin('product_category', 'product.id', '=', 'product_category.product_id')
->leftJoin('category', 'product_category.category_id', '=', 'category.id')
->where('category_id', '=', 2);
But this would make the process of defining the relation in the Model class almost useless.
Is there a better way of making it, maybe using the ORM stuff?
Thank you so much!
Use whereHas:
$products = Product::whereHas('categories', function ($q) {
$q->where('id', request()->input('category_id'));
})->get();
See Querying Relationship Existence.

Laravel get sum of related table's columns with eloquent

I'm having some trouble calculating the price of my carts with eloquent,
here are my tables:
cart_products:
- cart_id
- product_id
- quantity
products:
- price
One cart can have multiple cart_products, and each cart_products have one product associated
I'm making the request from the Cart Model, I'm trying to get the total price of the cart (cart_products.quantity * products.price).
Here is my query:
Cart::select('cart.*', \DB::raw('IFNULL(SUM(products.price*cart_products.quantity), 0) AS cart_price'))
->leftJoin('cart_products', 'cart.id', '=', 'cart_products.cart_id')
->join('products', 'cart_products.product_id', '=', 'products.id');
When I'm doing that, I do get the expected result but all the carts that doesn't contains product are excluded, I would like them to be included.
How could I include them ? Or is there a better way to do it (I saw withCount method but I couldn't make it work properly) ?
Another way would be to setup a virtual relation in your cart model and calculate your cart price like
class Cart extends Model
{
public function price()
{
return $this->hasOne(CartProducts::class, 'cart_id')
->join('products as p', 'product_id', '=', 'p.id')
->groupBy('cart_id')
->selectRaw('cart_id,IFNULL(SUM(products.price*cart_products.quantity), 0) as cart_price');
}
}
To get price data for your carts your can query as
Cart::with('price')->get()->sortByDesc('price.cart_price');
I finally managed to do it another way using raw SQL:
Cart::select('cart.*', \DB::raw('(SELECT IFNULL(SUM(products.price*cart_products.quantity), 0) from cart_products join products on products.id = cart_products.product_id where cart_products.cart_id = cart.id) AS cart_price'));
Thanks to you all for your help !

How to get parents data that only has a child data in laravel

I'm trying to get all the data from the parent that only has a child. Please see my code below.
$customers = Customer::with(['items' => function($query){
return $query->where('status', 2);
}])->get();
dd($customers);
But the code above returns all the customer. By the way, I'm using laravel 4.2.
Items Table:
Customer Table:
with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.
has() is to filter the selecting model based on a relationship. So it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.
e.g :
$users = Customer::has('items')->get();
// only Customer that have at least one item are contained in the collection
whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.
e.g
$users = Customer::whereHas('items', function($q){
$q->where('status', 2);
})->get();
// only customer that have item status 2
Adding group by to calculating sum
this is another example from my code :
Customer::select(['customer.name', DB::raw('sum(sale.amount_to_pay) AS total_amount'), 'customer.id'])
->where('customer.store_id', User::storeId())
->join('sale', 'sale.customer_id', '=', 'customer.id')
->groupBy('customer.id', 'customer.name')
->orderBy('total_amount', 'desc')
->take($i)
->get()
in your case :
Customer::select(['customer_id', DB::raw('sum(quantity) AS total')])
->whereHas('items', function ($q) {
$q->where('status', 2);
})
->groupBy('customer_id')
->get();
whereHas() allow you to filter data or query for the related model in your case
those customer that have items and it status is 2
afetr getting data we are perform ->groupBy('customer_id')
The GROUP BY statement is often used with aggregate functions (COUNT, MAX, MIN, SUM, AVG) to group the result-set by one or more columns.
select(['customer_id', DB::raw('sum(quantity) AS total')]) this will select customer id and calculate the sum of quantity column
You should use whereHas not with to check child existence.
$customers = Customer::whereHas('items', function($query){
return $query->where('status', 2);
})->get();
dd($customers);
I assume you already defined proper relationship between Customer and Item.
You should try this:
$customers = Customer::whereHas('items', function($query){
$query->where('status', 2);
})->get();
dd($customers);
Customer::select(['items.customer_id',DB::raw('count(items.id) AS total_qty')])
->join('items', 'items.user_id', '=', 'customer.customer_id')
->groupBy('items.customer_id')
->havingRaw('total_qty > 2')
->get();
OR
$data=DB::select("select `items`.`customer_id`, count(items.id) AS total_qty
from `customers`
inner join `items`
on `items`.`customer_id` = `customers`.`customer_id`
group by `items`.`customer_id` having total_qty >= 2");
correct table name and column name.

Getting id of products that belong to category

I have model many-to-many (including pivot table). I need to pull out only the products that belongs to a certain category. I'm trying this but it gives me all the products:
$products = User::whereHas('category', function ($query) {
$query->where('id','1');
})->get();
1 in where is just for testing because when I put $id that was defined outside query it doesn't recognize it.
Try this.
$products= User::whereHas('category', function ($query) use ($id) {
$query->where('id', $id);
})->get();
Maybe the fetchProducts method here will shed some light: Getting product brands, their categories and associated products

Categories