count query using eloquent relation laravel - php

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.

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();

Get results from joined tables

In my laravel app I track lesson enrollment and active subscriptions in different tables.
A lesson is defined by lesson_types table which has columns like this:
lesson_types
id | name | sub_plan
Enrollemnts are defined in enrolls table with columns like this:
enrolls
id | user_id | lesson_type_id
and my subscriptions table has columns like this:
subscriptions
id | name | sub_plan | user_id
Tables are connect like this:
enrolls has 'lesson_type_id' which is 'id' of lesson_types table
sub_plan column in lesson_types is the same as sub_plan in subscriptions
Sample database data in tables:
ennrolls
id user_id lesson_type_id
1 1 1
2 1 2
3 2 1
lesson_types
id name sub_plan
1 Lesson 1 plan_1337
2 Lesson 2 plan_1338
3 Lesson 3 plan_1339
subscriptions
id name sub_plan user_id
1 Sub 1 plan_1337 1
I tried to get all enrollments like this:
$enrolled = DB::table('enrolls')->where('user_id', $userId)
->leftJoin('lesson_types', 'id', '=', 'lesson_type_id')
->select('name');
But I need to get them without subscriptions...
What i want to achieve is:
Get all 'lesson_types' names where user is subscribed
Get all 'lesson_types' names where user has enrolled but not subscribed
Get all 'lesson_types' where user is not enrolled
You can Achieve the above scenario using Laravel Eloquent. Laravel has facilitated a lot of more in-built ORM methods. So We don't need to write manual SQL codes. Don't reinvent the wheel
Enrolls Model
namespace App;
use App\User;
use App\LessonType;
use App\Subscription;
use Illuminate\Database\Eloquent\Model;
/**
*
*/
class Enroll extends Model
{
public function lessonType()
{
return $this->belongsTo(LessonType::class);
}
public function users()
{
return $this->hasMany(User::class);
}
}
Lesson Types Model
namespace App;
use App\Enroll;
use App\Subscription;
use Illuminate\Database\Eloquent\Model;
/**
*
*/
class LessonType extends Model
{
public function enrolls()
{
return $this->hasMany(Enroll::class);
}
public function subscription()
{
return $this->belongsTo(Subscription::class, 'sub_plan','sub_plan');
}
}
Subscriptions Model
namespace App;
use App\User;
use App\LessonType;
use Illuminate\Database\Eloquent\Model;
/**
*
*/
class Subscription extends Model
{
public function lessonType()
{
return $this->hasMany(LessonType::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
In Constroller or Repository
LessonType::select('name')->has('subscription.user');
LessonType::select('name')->doesntHave('subscription.user');
LessonType::select('name')->doesntHave('enrolls.users');
FYI :
Laravel Eloquent Relationships
Follow this approaches. Take it as Best Practice

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

belongsToMany with parent-child relationship in Laravel 5

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;

Categories