Laravel joining table relationship - php

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

Related

laravel withCount of linear nested relations in laravel

I have tables,
ec_products : id | brand_id (id from ec_brands) | store_id (id from mp_stores)
ec_brands: id
mp_stores: id
I am calculating total products belong to each brand and store using relations and withCount of Laravel, Like,
Brand model,
public function products()
{
return $this->hasMany(Product::class, 'brand_id')->where('is_variation', 0);
}
Stores model
public function products()
{
return $this->hasMany(Product::class, 'store_id')->where('is_variation', 0);
}
And in each model,
$data = $data->withCount(‘products’);
Now I introduced categories, One product belongs to multiple categories.
So used separate table to link category and product.
ec_product_category_product: id | category_id (from category table) | product_id (from our products table)
So final question I have, How to join all,
I want to list each of these (brand,store, category) and count products of each based on request parameters.
Like
if any brands selected, then count store and category related to that brand.
if stores selected, then count brands and category related to that store.
if any category selected, then count store and brand related to that category.
structure of UI
Suggestion or solution.
Thanks
You should always start you Eloquent query with the Object you want to manipulate, here, it's Product and THEN constraint your query,
so in your controller :
$product_count = Product::when($request->category_id, function($query) use ($request){
$query->where('category_id', $request->category_id);
})
[...] //do that for each of your constraints
->count();
if you want to do a search on the name of the category for example, use a whereHas :
$product_count = Product::when($request->search, function($query) use ($request){
$query->whereHas('category', function($query) use ($request){
$query->where('name', 'like', "%$request->search%");
});
})
[...] //do that for each of your constraints
->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

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.

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;

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