Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

tayyabshahzad1's avatar

Relationships

Hi,

I have a product table and product-status table.

Both tables are related to each other using Belong to and hasmany.

Actually, what I want, I have many products and many franchises, every product is for every franchise but the requirement is the user can inactive product status for specfic franchise if this functionality will apply then that specfic product can't be list in all products for that,

I have a Product Status Model

poduct_status->hasMany(Product::class)

And Product Model

 public function productStatus(){
        return $this->hasMany(ProductStatus::class);
   }

Product ProductStatus Model is

  public function product(){
        return $this->belongsTo(Product::class);
    }

Product Status Table

id  franchise_id    product_id  status
1   2               3           inactive
2   2               4           active
3   1               3           active 
4   1               4           active    

Now I am getting all my products using below code in my api call.

    $fracnhise_id = 2 
    $products = Product::with('productStatus')->get(); 

And the result is

"id": 3,
        "name": "1/2 Gallo",
        "description": null,
        "sell_on_its_own": "yes",
        "price": 70,
        "product_status": [
            {
                "id": 1,
                "franchise_id": 2,
                "product_id": 3,
                "status": "inactive",
                "created_at": "2022-06-29T06:22:06.000000Z",
                "updated_at": "2022-06-29T07:15:25.000000Z"
            }
        ]

No, I want if product 1/2 Gallo status is inactive then this product will not load in my collection

0 likes
7 replies
Sinnbeck's avatar

Ok you can use whereHas to filter by a relation

    $products = Product::with('productStatus')->whereHas('productStatus', function($query) {
       $query->where('status', '<>', 'inactive');
])->get(); 
tayyabshahzad1's avatar

@Sinnbeck Sir thanks for the help This query works for me but the problem is in my case by default product-status table is empty. if no record in the product-status table this query is returning me an empty collection. I want all my products which are coming from the products table. But if the admin marks any product as inactive then that product will not show in my collection. Your given solution is working if the product status table has data. I hope you got my point.

tayyabshahzad1's avatar

@sinnbeck the product status table will empty by default if the admin marks the product as inactive then the record will be inserted in product-status table

Sinnbeck's avatar

@tayyabshahzad1 Why not have the status directly on the product then?

I would probably have 2 columns. disabled_at and disabled_by. First being a date/time, and the second pointing to the user that disabled it.

tayyabshahzad1's avatar

@Sinnbeck I have a product status column in the products table but that status is only for the main product, actually, I want to disable the product for any franchise for that I have created product-status table

Sinnbeck's avatar

@tayyabshahzad1 Then it sounds like the status is very important, and you should look into ensuring that it gets created whenever a product is created?

Or can it only ever be added if you want to disable ? If its only for disabling, I would do this instead

$products = Product::with('productStatus')->whereDoesntHave('productStatus', function($query) (use $franId) {
       $query->where('franchise_id', $franId);
])->get(); 
achatzi's avatar
achatzi
Best Answer
Level 5

@tayyabshahzad1 You have a table products and a table franchises and their respected models (Product & Franchise) correct?

I also remember another question you had about products and franchises https://laracasts.com/discuss/channels/laravel/relationship-11.

My suggestion is to create a many-to-many relationship for franchises and products and add the columns you need there.

Create a franchises_products table, have the columns franchise_id, product_id, special_price, is_active.

Define the relationships

//in the Franchise model
public function products()
{
	return $this->belongsToMany(Product::class, 'franchises_products')
		->withPivot([
			'special_price',
			'is_active',
		]);
}

public function active_products()
{
	return $this->belongsToMany(Product::class, 'franchises_products')
		->withPivot([
			'special_price',
			'is_active',
		])
         ->wherePivot('is_active', 1);
}
//in theProduct model
public function franchises()
{
	return $this->belongsToMany(Franchise::class, 'franchises_products')
		->withPivot([
			'special_price',
			'is_active',
		]);
}

Make sure that whenever a new franchise is created, the table is filled with all the products

//in the franchise controller
public function store()
{
    //pseudo code to create the franchise
    $franchise->save();

    $products = Product::all()->pluck('id');

	$franchise->products()->syncWithPivotValues($products , ['is_active' => 1]);

Also, make sure that when a product is created, it is attached to all franchises

//in the product controller
public function store()
{
    //pseudo code to create the product
    $product->save();

    $franchises = Franchise::all()->keyBy('id')->transform(fn($franchise) => [
        'is_active' => 1
    ]);

	$product->franchises()->attach($franchises);

Now, when you want to show the active products of a franchise, you can do this

$franchise = Franchise::with('active_products')->find($franchise_id);

$data = []
foreach ($franchise->products as $product) {
	$data[] = [
		'id' => $product->id,
		'title' => $product->title,
		'price' => $product->pivot->special_price ?? $product->price
	];
}

return response()->json([
	'success' => true,
    'product' =>  $data,
]);
1 like

Please or to participate in this conversation.