How can I get all relationship collection? - php

I have 3 model:
Company, Category, Product.
HasMany relationship between Company-Category and Product-Category
How can I get all Product from company?
My code:
$company = Company::findOrFail($id);
if (isset($company->categories)){
$categories = $company->categories;
if (isset($categories->first()->products)){
$products = $categories->first()->products;
}
}
However my code returns only first category's products.

There are couple of things wrong here.
First, you need to eager Load your relationships to avoid the N+1 query problem.
Second, if you want to access all the products belonging to all the categories, you cannot call first() on the categories relationship. Instead, you need to loop over it.
The following should work.
$company = Company::with('categories.products')
->findOrFail($id);
if ($company)) {
foreach ($company->categories as $category) {
foreach ($category->products as $product) {
// Access your Product model here
}
}
}

Maybe you can do this
$company = Company::findOrFail($id);
$categories_ids = $company->category->pluck('id');
$products = Product::whereIn('category_id',$categories_ids')->get();
You maybe can use hasThrouthMany
class Category extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Product',
'App\Company',
'category_id', // Foreign key on company table...
'company_id', // Foreign key on product table...
'id', // Local key on category table...
'id' // Local key on company table...
);
}
}
You can read more info in https://laravel.com/docs/5.7/eloquent-relationships#has-many-through
please try this and let me know how it works :)

Related

Eloquent Laravel Fetch Data from multiple tables

I've spent two days trying to solve this but I can't figure how.
I have five tables
Product
Category
Category_Product
Order
Order_Product
From the view,clicking on a category button I have to fetch all his ordered products with the relative category.
I have the current models:
Product Model
class Product extends Model
{
public function categories() {
return $this->belongsToMany('App\Category');
}
public function orders() {
return $this->belongsTo('App\Order');
}
}
Category Model
public function products() {
return $this->belongsToMany('App\Product');
}
Order Model
public function products() {
return $this->belongsToMany('App\Product');
}
Now the problem is that I can't figure how to fetch the data from the current tables.When I press a button I'm able to fetch the category from the Product Table,but I want to fetch from the Ordered_Products. I really can't figure how.
With this I'm able to fetch all the categories from Product
if (request()->category) {
$products = Product::with('categories')->whereHas('categories', function ($query) {
$query->where('slug', request()->category);
})->get();
}
With this instead,I'm able to fetch the ordered products.
$products = DB::table('order_product')
->join('products', 'order_product.product_id','=', 'products.id')
->where('order_product.user_id','=',$user_id)
->get();
For the latter, there's a better way to do it, that's for sure. I'm sorry if it's a dumb question but I'm rather new with this framework. I am using Laravel 7.2.
Basically Eloquent Model doesn't encourage joining tables to retrieve data. It should be joined only for filtering results (So you need to drop field of other table using ->select('original_table.*'))
In this case, you should simply retrieve categories at first. Then retrieve related data using relation property accessing.
e.g.
$categories = Category::query()
->with('products')
->where('slug', request('category'))
->get();
$products = $categories->flatMap->products;
$pivots = $products->map->pivot;
Solved using whereHas two times:
$products = Product::with('categories')->whereHas('categories',function($query){
$query->where('slug',request()->category);
})->whereHas('orders',function($query){
$query->where('orders.user_id',Auth::id());
})->get();

Laravel - Many-to-many relation, product count by product feature

Trying to get the count of products by its features(many-to-many)
For instance,
Product::with([’features’])->where(category_id, $category_id)->get();
Product A->feature1->id
/feature2->id
/feature3->id
Product B->feature3->id
/feature4->id
/feature6->id
.....
how could i get product count from each feature (after filtered by product category)
I am not good at explain in wording, tried my best.
Final result
feature 1 -> 19 products
feature 2 -> 5 products
...
Try this:
Select product_id from products where category_id = "'.$category_id.'" group by feature_id;
You should Define relation within your Product and Feature Model
class Product extends Model {
public function features(){
return $this->belongsTo(Feature::class);
}
}
class Feature extends Model {
public function products(){
return $this->hasMany(Product::class);
}
}
I presume each Product has an attribute feature_id which hold the id of the Feature to which it's belongsTo.
$products = Product::with([’features’])->where(category_id, $category_id)->get(); // This query will return list of product
foreach($products as $product){
// You can access $feature of product like this
$feature = $product->feature;
}
Because I have already define the reverse relation between the both Model I can access Product from Feature as well.
$feature->products(); // This will return a collection of Product and I can perform any sort of query on that too
// Like count number of Products
$feature->products()->count();
$feature->products()->first(); // get the first product
$feature->products()->last(); // get the last product
And so on and so fourth
Assuming you have products relationship on the Feature model you can try this!
$features = Feature::withCount(['products' => function($query){
$query->where('category_id', $category_id);
}])->get();
You will have a products_count with each record of the collection.
This will do the trick
with(['products' => function($q) use($category_id){
$q->where('category_id',18);
}])
->find($feature_ids)
->groupBy('feature_type_id');

Call to undefined relationship on model laravel using scope

I'm trying to get 5 posts for each category so I did a little search and ends up here Getting n Posts per category
But I'm getting a weird Call to undefined relationship on model when using with scope but it all works fine If I don't use a scope. Here is the Category Model
//Relationship with posts
public function posts(){
return $this->hasMany('App\Post');
}
scopeNPerGroup
public function scopeNPerGroup($query, $group, $n = 10)
{
// queried table
$table = ($this->getTable());
// initialize MySQL variables inline
$query->from( \DB::raw("(SELECT #rank:=0, #group:=0) as vars, {$table}") );
// if no columns already selected, let's select *
if ( ! $query->getQuery()->columns)
{
$query->select("{$table}.*");
}
// make sure column aliases are unique
$groupAlias = 'group_'.md5(time());
$rankAlias = 'rank_'.md5(time());
// apply mysql variables
$query->addSelect(\DB::raw(
"#rank := IF(#group = {$group}, #rank+1, 1) as {$rankAlias}, #group := {$group} as {$groupAlias}"
));
// make sure first order clause is the group order
$query->getQuery()->orders = (array) $query->getQuery()->orders;
array_unshift($query->getQuery()->orders, ['column' => $group, 'direction' => 'asc']);
// prepare subquery
$subQuery = $query->toSql();
// prepare new main base Query\Builder
$newBase = $this->newQuery()
->from(\DB::raw("({$subQuery}) as {$table}"))
->mergeBindings($query->getQuery())
->where($rankAlias, '<=', $n)
->getQuery();
// replace underlying builder to get rid of previous clauses
$query->setQuery($newBase);
}
Calling Npergroup with relation
public function latestposts()
{
return $this->posts()->latest()->nPerGroup('category_id', 5);
}
Post Model Relationship
//Post belongs to Category
public function category(){
return $this->belongsTo('App\Category');
}
In my category controller I'm calling latestposts through
$categories = Category::with('latestposts')->get();
But I'm getting the error: Call to undefined relationship on model
What I want is:
Get the N number of posts per each category but I'm completely lost at this point. Any help would be appreciated
Reference:
Tweaking Eloquent relations – how to get N related models per parent ?
I am giving this answer based on your purpose that you want 5 posts per category.
So you have Category Model and Post Model.
And in Category Model you have relation with Post model like this
//Relationship with posts
public function posts(){
return $this->hasMany('App\Post');
}
And in Post Model you have relation with Category model like this
//Post belongs to Category
public function category(){
return $this->belongsTo('App\Category');
}
I show your question you have done SQL queries.
Instead of that, You can use two approaches
1) Give condition while eagar loading
$categories = Category::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc')->take(5);
}])->get();
Note: This approach will only work when you take only one result of parent child using first() method.
To get n number of posts per category Use this.
First, you can retrieve all categories with
$categories = Category::all();
Then you can use foreach loop and in all $category you have to give assign new attribute in it like here latestposts,
foreach ($categories as $category)
{
$category->latestposts = $category->posts()->orderBy('created_at','desc')->take(5)->get();
}
After this foreach loop you will get latest 5 posts in all categories.
Try this in your code and comment your queries and reviews.

LARAVEL - Show products to related category

I'm trying to show products related to the category. In my menu I have a list of categories if I click this category i want to see related products to this category. I'm just learning laravel can somebody help me out..
DATABASE:
-categories: ID, NAME
-products: has Category_id
View
Route::get('/category' , [
'uses' => 'productController#getCategory',
'as' => 'category.single'
]);
Controller
public function getCategory($category) {
$singleCategory = Category::find($category);
return view('pages.category', ['category' => $singleCategory]);
}
How do I go from here?
in Category.php Model add a relation
public function products()
{
return $this->hasMany('App\Product');
}
then you can call
$singleCategory->products
and you'll get you products by category_id
As per the following lines:
$singleCategory = Category::find($category);
return view('pages.category', ['category' => $singleCategory]);
category list is available on pages.category page under $category. Its a Collection object, you can access its object by using foreach() loop.
How do I go from here?
I don't know.
But for your problem, if you want to get the products of a Category just do:
$singleCategory = Category::find($category);
$products = $singleCategory->products;
(I assume you added a products method in your Category model, if not, read this: https://laravel.com/docs/5.4/eloquent-relationships#one-to-many).
Then you can display your products by looping on your products:
foreach($products as $product) {
echo $product->name;
}

How to get two arrays of obiects by one column

Hi i have on table with categories with foreign key to herself where parent_id is the same that id in this table. I want to get two arrays of objects. First with categories where
parent_id=0
and second with subcategories. But I dont know how can I catch this subcategories. I have this:
$category= Category::where('parent_id', '=', 0)->get();
dd($category[0]['id']);
$subcategory= Category::where('parent_id', '=', (($category[0]['id']??)));
First $category shouild return me array of categories and second array with subcategories i need adjust id of each object of array $category to each subcategory array. Is it possible or there are other ways?
If you define your model relations correctly you can get categories and their subcategories in a much nicer way.
First define the relations:
class Category extends Model {
public function parent() {
return $this->belongsTo(Category::class);
}
public function subcategories() {
} return $this->hasMany(Category::class, 'parent_id');
}
You can now get all parent categories with their subcategories the following way:
$parents = Category::whereParentId(0)->with('subcategories')->get();
This will give you list of all parent categories, each of them will have subcategories property that will store all subcategories. You can traverse them in the following way:
foreach ($parents as $parent) {
printf("Parent category %s\n", $parent->name);
foreach ($parent->subcategories as $subcategory) {
printf("Subcategory %s\n", $subcategory->name);
}
}
Small suggestion: make your parent_id nullable and store NULL for parent categories instead of 0, as 0 is not a correct category ID.

Categories