Skip to content

Example for a kind of "multi-table inheritance" in Laravel by using polymorphic relationships

Notifications You must be signed in to change notification settings

laundy/laravel-mti-morph-example

Repository files navigation

Laravel "Multi-Target Inheritance" by Polymorphic Relationships Example

⚠️ This repository is not maintained anymore. Laravel versions etc. are out of date and contain serious security issues.

NOTE: The Module (moduleable) is called Element (elementable) in this example.

Based on this Stackoverflow thread (props to user sss S for pointing me in the right direction).

Models

class Element extends Model {
  public function elementable() {
    return $this->morphTo();
  }
}

class TextElement extends Model {
  public function element() {
    return $this->morphOne('App\Element', 'elementable');
  }
}

Migrations

Schema::create('elements', function (Blueprint $table) {
  $table->bigIncrements('id');
  $table->float('x');
  // ... other fields mentioned above
  $table->morphs('elementable'); // this creates a "elementable_id" and "elementable_type" field
  $table->timestamps();
});

Schema::create('textElements', function (Blueprint $table) {
  $table->bigIncrements('id');
  // ... only the fields that are exclusive for a TextElement (= not in Element, except "id")
});

Factories

$factory->define(TextElement::class, function (Faker $faker) {
    return [
        // ... fill the "exclusive" fields as usual
    ];
});

$factory->define(Element::class, function (Faker $faker) {
  $elementables = [
    TextElement::class,
    // ... to be extended
  ];

  $elementableType = $faker->randomElement($elementables);
  $elementable = factory($elementableType)->create();

  return [
    // ... the fields exclusive for Element
    // add the foreign key for the created "elementable" (TextElement)
    'elementable_id' => $elementable->id,
    'elementable_type' => $elementableType
    ];
});

Controller

public function index() {
  $all = \App\Element::whereHasMorph('elementable', '*')->with('elementable')->get();
  return response()->json($all);
}

The wildcard * will show any specific Element (e.g. TextElement, ImageElement) that was configured following the steps above. Adding ->with('elementable') directly populates the "specific" attributes for every Element. Have a look at the section "Querying Polymorphic Relationships" in the official Laravel documentation for further information.

Output

[{
   "id":1,
   "x":34.47,
   "y":17.04,
   "elementable_type":"App\\TextElement",
   "elementable_id":1,
   "created_at":"2019-12-02 20:08:01",
   "updated_at":"2019-12-02 20:08:01",
   "elementable":{
      "id":1,
      "font":"Arial",
      "color":"#94d22e",
      "size":12,
      "created_at":"2019-12-02 20:08:00",
      "updated_at":"2019-12-02 20:08:00"
   }
}]

About

Example for a kind of "multi-table inheritance" in Laravel by using polymorphic relationships

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published