Laravel self relation many to many

Viewed 949

I have table items(means artefacts).And artefacts (not all of them) can be created using another (one or more) artefact(s).

I can't find any working example in google how to do many to many self relation in laravel.

I wrote something like this:

class Item extends Model
{
    public function items()
    {
        return $this->belongsToMany('App\Item', 'item_id');
    }

    public function components()
    {
        return $this->belongsToMany('App\Item', 'component_id');
    }
}

But I have no idea what to do next.I stuck.Any help would be appreciated.

Here my table structure:

id | name | price | extra_item_slot
------------------------------------

But I can change it if need.For add another column or something like that.

Upd: One Artefact can contain multiple child Artefacts.

2 Answers

As you asked for an example.

This answer is only for giving you an example of a many-to-many relationship with the same table. This is actually known as self-referencing table. So let's do it.

First, we need to create two tables. One is for the artifact names and the other one is an intermediary table which is called the pivot table. Here parent_child table is a pivot table.

Schema::create('artifacts', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->timestamps();
});

Schema::create('parent_child', function (Blueprint $table) {
    $table->unsignedInteger('parent_id');
    $table->foreign('parent_id')
        ->references('id')
        ->on('artifacts');

    $table->unsignedInteger('child_id')->nullable();
    $table->foreign('child_id')
        ->references('id')
        ->on('artifacts');

    $table->timestamps();
});

Now we need to seed those two tables. For the brevity, I'm going to put them into links. Here are ArtifactSeeder.php and ParentChildSeeder.php

Next up, we need to tell the model to build the many-to-many self-referencing relationship. Here is our model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Artifact extends Model
{
    public function children()
    {
        return $this->belongsToMany(
            Artifact::class,
            'parent_child',
            'parent_id',
            'child_id'
        );
    }
}

Now it's time to play with the data. So let's play with that.

$parent = Artifact::where('name', '=', 'D')->first();

// or 

$parent = Artifact::find(2);

foreach ($parent->children as $child) {
    echo $child->name . '<br>';
}

I think there is no need to use a many-to-many relationship in your case. You can get your expected data using one-to-many relationship as @ZhengYu's answer. Nevertheless, you can explore whatever you want. Thanks! :)

You can save child artefacts using parent ID. So child 1 and child 2 can be saved using same parent ID. For example,

id | name | price | extra_item_slot | parent_id
------------------------------------------------
1    parent  10        some              0
2    child1   2        some              1
3    child2   3        some              1

In above example, item 1 has 2 child - item 2 and item 3

In this case, you can define many to many relation in laravel:

class Item extends Model
{
    protected $table = 'item';

    public $fillable = ['name', 'price', 'extra_item_slot', 'parent_id'];

    public function children() {
        return $this->hasMany('App\Models\Item','parent_id','id');
    }
}

Then you can get children items as your mind:

$parentItem = Item::where('name', '=', "someword")->where('parent_id', '=', "0")->first();
$childrenItems = $parentItem->children; // you can get all children here

Hope to helpful!

Related