belongsToMany with parent-child relationship in Laravel 5 - php

I have two models that are related to each other with a belongsToMany relationship. The models are Game and Category. Of course, the tables for both are games and categories. The Category model, has its own parent-child relationship.
Basically this is my "simplified" structure:
Table game:
id unsigned integer
name string
Table categories:
id unsigned integer
name string
parent_id unsigned integer nullable
The parent_id column is null when the category has no parent, but it has an existing id referencing a row in the same table if it is a children of some other category.
Table category_game
category_id unsigned integer
game_id unsigned integer
The category_id column, references id on categories table. It should reference only the top category that a game belongs to. A game can belong to many different categories, but in the pivot table, there should only be a reference to the parents categories. For example if I had this structure of categories:
Category 1
Category 2
Category 4
Category 3
Category 9
Category 5
Category 6
Category 7
Category 8
I would like to have the following information for my games 1 and 2:
category_id game_id
3 1
5 1
1 2
And that should mean that my game 1 has categories: 3, 9, 5, 6, 7 and 8.
While my game 2 has categories: 1, 2, 4, 3 and 9
I understand that my Laravel models should have this:
class Game {
public function categories(){
return $this->belongsToMany( Category::class );
}
}
class Category{
public function games(){
return $this->belongsToMany( Game::class );
}
}
But I don't know how to retrieve the children categories using Eloquent. I know the belongsToMany method has more parameters that might help with my problem, but I don't know how to use them.

Model categoryGame for table category_game
class CategoryGame{
public function childCategories() {
return $this->hasMany(Category::class, 'parent_id','category_id');
}
}
You can access
$games = App\CategoryGame::all();
foreach ($games as $game ) {
foreach ($game->childCategories as $category) {
echo $category->name;
}
}
Let me know if not works

Extend your models:
class Category {
public function children() {
return $this->hasMany(Category::class, 'parent_id');
}
}
class Game {
public function getAllCategoriesAttribute() {
$result = collect();
$children = function($categories) use(&$result, &$children) {
if($categories->isEmpty()) return;
$result = $result->merge($categories);
$children($categories->pluck('children')->collapse());
};
$children($this->categories);
return $result;
}
}
Then you can access the categories like this:
Game::find($id)->allCategories;

Related

Get products count of all nested categories in parent category

categories
id
name
parent_id ?
products
id
name
category_id
In the category there can be both children and products
i need the count of products within the categories even it has children . Let's say categories have 2 products and 2 subcategories. both categories have 2 products each without subcategories. per category parent the count of products will be 6.categories can be parent->sub->sub 3 max.
class Category extends Model
{
public function activeChildren(): HasMany
{
return $this->hasMany(self::class, 'parent_id')
->active()
->with('activeChildren');
}
public function activeProducts(): HasMany
{
return $this->hasMany(Product::class)->where('is_active', true);
}

Laravel total products count from childs in parent category

I have eloquent relationships with category child
In category Model
public function products()
{
return $this->hasMany(Products::class, 'category', 'id');
}
public function sub() {
return $this->hasMany(SELF::class, 'parent_id')->withCount(['products'])->with('sub');
}
I would like to get in each category and child category has products count
Example
Category A is the parent
Category B and C are child of A category
Category B has 3 products and category C 2 products
How to get product_count 5 (total of B and C category product count) in the A parent category when I call withCount()?
At the moment there is 0 count but child categories have product count.
Thank you so much for any idea!
One way to get the count of all products for a category including products under it's sub categories can be via two separate queries.
Assume:
Category A has id of 5
Category B and Category C are sub categories of A
//Get the Category record with sub categories
//Select only id column from category
//Select id & parent_id (required as it links the relation) from sub (categories)
$category = Category::with('sub:id,parent_id')
->select('id')
->findOrFail(5);
//Prepare a collection of just the id's
$categoryIds = $category->sub->pluck('id')->push($category->id);
//Get the product count
$count = Products::whereIn('category', $categoryIds)->count();
I appreciate that! It's only got products count from 2 next child, not whole nested categories.
Define a method to get all ids from the subcategories
class Category extends Model
{
public function getSubcategoryIds()
{
$ids = $this->sub->pluck('id');
$this->sub->each(function($sub) use(&$ids){
if($sub->sub->count()) {
$ids->push($sub->getSubcategoryIds());
}
});
return $ids->flatten();
}
//... rest of the class code
}
Then
$category = Category::findOrFail(5);
//Get the subcategory ids deeply nested and add category id to it
$categoryIds = $category->getSubcategoryIds()->push($category->id);
//Get the product count
$count = Products::whereIn('category', $categoryIds)->count();

Laravel joining table relationship

I'm wanting to do a joining table but I'm not sure how to set up the relationship in laravel.
I have 3 tables, products, categories, and product_categories. product_categories will consist of the product ID and the category ID. How would I join theses up in a relationship in laravel so I can just call $product->categories() like a normal relationship?
Your relationship will be belongsToMany.
Your products table would be
id | name
Your categories table would be
id | name
your product_categories table would be
id | product_id | category_id
As per relationship in Laravel
Product Model
class Product extends Model
{
protected $table = 'products';
public function categories()
{
return $this->belongsToMany('App\Category','product_categories','product_id','category_id');
}
}
Category Model
class Category extends Model
{
protected $table = 'categories';
public function products()
{
return $this->belongsToMany('App\Product','product_categories','category_id','product_id');
}
}
In controller now
Product::with('categories')->get();
This is a many-to-many relationship.
You can use belongsToMany on both products and categories and it would work. However you also should rename product_categories to follow the rule
use singular table names in alphabetical order
this would be category_product

How to setup Eloquent Models ManyToMany for self-joins

I have two tables, products and pack_product
`product` table: product_id, model, price;
`pack_product` table: product_id, pack_id;
`product` table data:
product_id model price
1 model1 100
2 model2 150
3 model3 200
4 Pack1 300
5 Pack2 400
`pack_product` table data:
product_id pack_id
1 4
2 4
3 5
I registered all relationships in the Products model class and I would like to fetch all product data from the pivot table, but I getting empty array.
Products model:
/**
* Products can belong to many packs
*/
public function packs(){
return $this->belongsToMany(static::class, 'pack_product', 'products_id', 'pack_id');
}
/**
* Pack can have many products
*/
public function products(){
return $this->belongsToMany(static::class, 'pack_product', 'pack_id', 'products_id');
}
Controller
$products = new Products;
$products->products()->get();
// or
$product = Products::find(1);
$product->packs;
// getting [] output
UPDATE
The relations are connected right, but I cannot to print them.

count query using eloquent relation laravel

I have three tables called category, subcategory and product .
category has
id category_name
subcategory has
id category_id sucategory_name
and product table has
id category_id subcategory_id productname
now what i want is, i want to get the total number of product that belongs to the subcategory.
my categorymodel looks like
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use App\Subcategory;
class Category extends Model
{
protected $table = 'category';
public $timestamps = false;
public function subCategory(){
return $this->hasMany('App\Subcategory', 'category_id');
}
}
and my subcategory model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Subcategory extends Model
{
protected $table = 'subcategory';
public $timestamps = false;
public function products(){
return $this->hasMany('App\Products', 'subcategory_id');
}
}
and finally my product model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Products extends Model
{
protected $table = 'products';
}
however I have displayed all the sub-category names that belongs to the category by doing like this in my controller
$categories = Category::with('subCategory')->get();
I have already achieved below result in my view.
category 1
subcategory 1
subcategory 2
subcategory 3
category 2
subcategory 1
subcategory 2
subcategory 3
Now i just want to count the number of products that belongs to the subcategory like for exampole
category 1
subcategory 1 (20)
subcategory 2 (2)
subcategory 3 (3)
category 2
subcategory 1 (12)
subcategory 2 (11)
subcategory 3 (2)
How can I achieve such result?
$categories = Category::with('subCategory')->get();
foreach ($categories as $category)
{
echo "{$category->category_name}\n";
foreach ($category->subCategory as $subcategory)
{
echo "\t{$subcategory->subcategory_name} ({$subcategory->products()->count()})\n";
}
}
Just an idea. Adapt with your view code.
By the way, I think your product should not contain category_id because it already indirectly refer to its category via subcategory_id.

Categories