How to get products based on a count on a field in this table with Laravel - php

I'm working on Laravel 5.8
Let's say we have a table products like this:
id | product_type_id |...
1 |______1_______|...
2 |______2_______|...
3 |______2_______|...
4 |______3_______|...
I would like to know how to get the all the products which "share" a product type.
In other words, I would like to get all the products except those whose product_type_id is unique in the table.
I know who to do it in a foreach loop but I would like to take advantage of the resources of using Laravel.
Thanks in advance.

The Laravel way of doing it would be using Eloquent relationships along with has() and whereHas(), like this:
$products = Product::whereHas('type', function ($builder) {
$builder->whereKey(Type::has('products', '>=', 2)->pluck('id'));
})->get();
I'm assuming you have defined Product and Type models and connected them together:
Product belongsTo Type
Type hasMany Product

If I'm understanding your question correctly you could do something like this.
First, make sure your ProductType model has a products relationship defined.
(I assume it does based on your Products table.)
Then you can query based on a relationship count using the Eloquent model method has.
Example:
ProductType::with('products')->has('products', '>', 1)->get();
The with('products') is optional. It simply grabs the Products at the same time to avoid additional queries. The whereHas method also works but is really only necessary if you need to filter the relationship based on more complex parameters.
You could also use the has/whereHas method inside the Product model using an inverse (ie belongsTo) relationship to get the same thing but inverted. It really depends on how you want the data presented to you.
Example:
Product::whereIn(
'product_type_id',
ProductType::has('products', '>', 1)->pluck('id')
)->get();
To sum it all up the first way will give you:
ProductType => Product
While the second example will give you:
Product => ProductType
See the related Laravel documentation for more info.
Hope that helps!

Related

How can I filter my model on Laravel builder based on the number of relationship that exists on the database

Let's say hypothetically I have 3 tables products, product_images, and variants, a product can have multiple images or variants. I have a requirement, for a product to be viewable by another user you need to have at least 4 product images and 3 variants, and then they are considered valid. I want to be able to query all the products that are considered valid without pulling out a collection and having to use a model method to filter, How can I do this?
You can use has query builder method.
Product::has('images', '>=', 4)->has('variants', '>=', 3)->get();

Query More than one relationship from a model with() in Laravel

I need help to query a model base on its relationship:
I have a model called StoreStock, this model is related to a Product model, which has two model relationships, MasterList and Price.
I want to get all storeStock with two Product relationships.
I know i can do something like
StoreStock::all()->with('product.price')
->get()
With this, i can only pick either price or masterlist
Pass array of relationship to with method
StoreStock::with(['product.price','product.masterlist']) ->get()
A little bit explanation here, many of the Laravel methods which support string, also support arrays. You can hover over the specific method and get the intellisense. In your case, it can be written like:
StoreStock::with(['product.price','product.masterlist'])->get()
If you want to run a specific action over any specific relation, you can also write it like this:
StoreStock::with(['product.price' => function(Builder $query) {
// your action required with the query
},'product.masterlist']) ->get()
Hope someone finds this helpful

Laravel model object retrieving relation model with where condition without "get" method

I'm working on octoberCMS(laravel framework), I have a doubt on retrieving relation model on where clause.
I have fetched a clothing_type record from "clothing type" model based on its primary key "id".
$clothing_type = ClothingType::where('id',post('clothingtype_id'))->where('status','Active')->first();
This "clothing type" model is related with "products" model, the relation is => each clothing type hasMany products.
Every thing works fine; Now my business logic has two cases, one is to get all the products of the clothing type and another is to get the first product of the clothing type. So I have used the $clothing_type->products to get all the products and $clothing_type->products->first() to get the first product.
Now I have to apply a condition for both the cases. The condition is that only the product whose status is "Active" should be fetched, hence
$products = $clothing_type->products->where('status','Active'); and$first_product_detail = $products->first();.
Every thing works as expected but how come the products are fetched without "get()" method. $clothing_type->products->where('status','Active')->get(); Since I'm new to relation I want to know how this works or is this a bad way to get records or improper assumption. But every thing works good.
$clothing_type = ClothingType::where('id',post('clothingtype_id'))->where('status','Active')->first();
if(count($clothing_type->products))
{
$products = $clothing_type->products->where('status','Active');
$first_product_detail = $products->first();
}
You are doing it the correct way. When you access the relationship as an attribute Eloquent automatically retrieves the records.
However, if you access the relationship as a method, you get the query itself, to which you can add your filters:
if(count($clothing_type->products))
{
$products = $clothing_type->products()->where('status','Active')->get();
$first_product_detail = $products->first();
}
This would solve your problems
(documentation is over here (see the first item))
Edit: Also note that the first method is not a method of Eloquent, but from Collection, which is pretty powerful!
Edit2:
I misread the part of your question where you want to know HOW this is possible. Both Eloquent and Collections have a where method. I assume you understand the working of the Eloquent one, but the one from Collection is pretty much the same (see documentation on the Collection where here)
I prefer the Eloquent one myself, because that limits the amount of records that is retrieved from the database. But if you need all the products (even the inactive ones) later on in your code, just use the Collection method to filter the active ones out
There is nothing to be afraid of...
first() and where()
are functions of both Illuminate\Database\Query\Builder as well as Illuminate\Support\Collection and all first does is limit the records to take 1 and then give you the first record. When you use Builder a query is made to get 1 record and 1 you use it on a collection, all records are first get() and then the first of those records is returned.
Here,
When you do,
$clothing_type->products, Laravel gives you a collection of products...
So...
$products is an object of Illuminate\Support\Collection
and
$products->first() calls for the first() function in that class.
Documentation on where and first methods of a collection...

How to return a record with its relation only if the relation has not been deelted

I am using Laravel 5.2 and have some relationships between my models setup.
I have a Product model and a Customer model (a product has a customer).
I am using the following to get a list of customers, however I am also using soft deletes. If the customer has been soft deleted (the relation), I don't want to return the product.
How do I achieve this in Laravel?
$products = Product::with('customer')->get(); --want to say "where customer.deleted_at is null"
You have to call has on the query:
$products = Product::with('customer')->has('customer')->get();
As #Lock put it, use
$products = Product::with('customer')->has('customer')->get();
TIP: For the opposite - i.e to get only the products with deleted customers (doesn't make much sense here but you may find this handy in future), use below
$deleted=Product::with(['customer' => function ($q) {
$q->withTrashed();
}])->onlyTrashed()->get();

Laravel 5.1 eloquent belongsTo relationship joining on multiple columns

I am connecting to a remote database that has been designed poorly but I can't amend it in any way I only have read access to the get the data I need. It has the following structure:
Products
- id
- style_id
- department_id
Brands
- id
- Name
- style_id
- department_id
So as you can see rather than a product just having a brand_id field it has a style_id and department_id that you have to join on in order to find out what brand a product is.
So how would I set up my belongsTo relationship in my Product model in order to achieve this?
I made a scope in the end to do this for me.
public function scopeWithBrand($query)
{
$query->join('Brands', function($q) {
$q->on('Products.department_id', '=', 'Brands.department_id')
->on('Products.style_id', '=', 'Brand.style_id');
})->addSelect(['Brands.id AS brand_id', 'Products.*']);
}
As far as I know Laravel does not support composite keys, there is
an issue opened on the laravel repo where the devs have answered that they don't have intentions of implementing that.
I think you can only query Product-Brand queries like for example Products by Brand combining wheres like this:
Product::where('style_id',$brand->style_id)->where('department_id',$brand->department_id)

Categories