5

I have variants table as following:

+-------------------+------------------+------+-----+---------------------+----------------+
| Field             | Type             | Null | Key | Default             | Extra          |
+-------------------+------------------+------+-----+---------------------+----------------+
| id                | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| parent_product_id | int(10) unsigned | NO   | MUL | NULL                |                |
| child_product_id  | int(10) unsigned | NO   | MUL | NULL                |                |
+-------------------+------------------+------+-----+---------------------+----------------+

with constraints:

CONSTRAINT `variant_products_child_product_id_foreign` FOREIGN KEY (`child_product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
CONSTRAINT `variant_products_parent_product_id_foreign` FOREIGN KEY (`parent_product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE

Let's say that it is filled with:

| id | parent_product_id | child_product_id | 
|----+-------------------+------------------| 
| 28 | 9                 | 11               | 
| 29 | 17                | 30               | 
| 30 | 9                 | 59               | 
| 31 | 9                 | 60               | 
| 32 | 17                | 25               | 

At first, business requirements was that one (parent) product can have multiple children. In my Product model I have

public function variants()
{
    return $this->hasMany(\App\Variant::class, 'parent_product_id', 'id');
}

And in Variant model:

public function child()
{
    return $this->belongsTo(\App\Product::class, 'child_product_id');
}

When I am querying Product (id:9) using:

$query->with([
    'variants.child'  => function ($query) {
        $query->select(['products.id', 'products.name'])
    },
]);

I am getting nice response:

{
  "id": 9,
  "name": "Foo",
  "description": "Ipsam minus provident cum accusantium id asperiores.",
  "variants": [
    {
      "id": 11,
      "name": "Bar"
    },
    {
      "id": 59,
      "name": "Fizz"
    },
    {
      "id": 60,
      "name": "Buzz"
    }
  ]
}

When asking about product 59, there are not any variants.

Now, I need to redefine my relationships so that products and variants will become rather siblings than descendants.

For example, after asking about product 59, desired response is:

{
  "id": 59,
  "name": "Fizz",
  "description": "Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
  "variants": [
    {
      "id": 9,
      "name": "Foo"
    },
    {
      "id": 11,
      "name": "Bar"
    },
    {
      "id": 60,
      "name": "Buzz"
    }
  ]
}

How can I achieve it without changing database structure. Any help and tips are much appreciated.

Edit: Two notes:

  • Every child can have only one parent. (There is a unique key on child_product_id column in database.)
  • There can only be one level of "nesting". Which means, that if one product already is a child - it cannot be a parent to another.
user1292810
  • 1,702
  • 7
  • 19
  • 38
  • What if product 59 would have its own children? Would they also appear in the last result. If so, would they also have to appear when querying product 9? Or what if 9 has its own parent, would it not have to also appear as a sibling? I have the impression this definition siblings (which includes parents as well) is ambiguous, and if applied consistently will result in large sets of "siblings". – trincot Dec 21 '15 at 14:37
  • Every child can have only one parent. (There is a unique key on `child_product_id` column in database.) There can only be one level of nesting. Which means, that if one product already is a child - it cannot be a parent to antoher. – user1292810 Dec 21 '15 at 14:43
  • I see. So no grandchildren :-). Shouldn't product 11 also appear in your results? – trincot Dec 21 '15 at 14:50
  • Yes, definitely it should :) My mistake. I have edited the example responses in my question. – user1292810 Dec 21 '15 at 14:54
  • 1
    @user1292810 Why for asking for product 59, you get also 9 in variants? It's parent od 59, isn't it? Do you need to use relationships or maybe you can use any method to get such JSON response? – Marcin Nabiałek Dec 25 '15 at 14:10
  • As I see your expected response for 59, 9 is parent and 11 & 60 are siblings. So can you clear actually, what are you trying to get? Initially it seemed to me that you only want siblings. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Dec 28 '15 at 02:36
  • @MarcinNabiałek @TareqMahmoodI I want all the products to be related on one level. So, initially there was relationship like parent <-> child. Now, I would like to get all realted products from `variants` table. When asking about 59, I would like to get 9, 11, 60 as variants. When asking about 30, I would like to get 17, 25 as variants. When asking about 9, I would like to get 11,59, 60 as variants. – user1292810 Dec 28 '15 at 08:57
  • I understand now, what you are trying to do, but I think it is still better to keep some type of parent to better manage the sibling relationships. For example if you want 59, 9, 11, 60 to be siblings, you can keep a common parent id for them all, like 999, which will keep them as siblings. If you agree with this approach, I can write an answer for you. – Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ Dec 28 '15 at 09:25
  • @TareqMahmood OK, please do, Thank you. – user1292810 Dec 28 '15 at 10:52

1 Answers1

1

As I said in the comment, I think it is still better to keep some type of parent to better manage the sibling relationships. For example if you want 59, 9, 11, 60 to be siblings, you can keep a common parent id for them all, like 999, which will keep them as siblings.

The other thing is that, if you have only one parent_product_id for each item, you don't need to keep it in a separate table. You can keep the parent_product_id in the same table products and set variants in \App\Product like this:

public function variants()
{
    return $this->hasMany(\App\Product::class, 'parent_product_id', 'parent_product_id');
}

Now, you can get the list of siblings with this little modification to your query part :

$query->with([
    'variants'  => function ($query) {
        $query->select(['products.id', 'products.name'])
    },
]);