This package provides joined-table inheritance to Laravel allowing you to store and query hierarchical objects in MySQL.
composer require cvsouth/entities
php artisan migrate
Extend your models from Entity
instead of the usual Model
:
class Animal extends Entity
{
public $table = "animals";
protected $fillable =
[
'name',
'species',
];
}
class Bird extends Animal
{
public $table = "birds";
protected $fillable =
[
'flying',
];
}
And when creating your migrations, include entity_id
. Also insert a new EntityType object:
class CreateAnimalsTable extends Migration
{
public function up()
{
Schema::create('animals', function (Blueprint $table)
{
$table->increments('id');
$table->integer('entity_id')->unsigned();
$table->string('species', 250);
$table->string('name', 250)->nullable();
});
$entity_type = new EntityType(["entity_class" => Animal::class]); $entity_type->save();
}
public function down()
{
Schema::drop('animals');
$entity_type = EntityType::where("entity_class", Animal::class)->first(); if($entity_type) EntityType::destroy([$entity_type->id]);
}
}
class CreateBirdsTable extends Migration
{
public function up()
{
Schema::create('birds', function (Blueprint $table)
{
$table->increments('id');
$table->integer('entity_id')->unsigned();
$table->boolean('flying');
});
$entity_type = new EntityType(["entity_class" => Bird::class]); $entity_type->save();
}
public function down()
{
Schema::drop('birds');
$entity_type = EntityType::where("entity_class", Bird::class)->first(); if($entity_type) EntityType::destroy([$entity_type->id]);
}
}
You can then use your objects just like normal Eloquent objects:
$bird = new Bird
([
"species" => "Aratinga solstitialis", // Note: This attribute is inherited from Animal
"flying" => true,
]);
$bird->save();
echo $bird->species;
// Aratinga solstitialis
Again, you can query the object just like usual for Eloquent:
$bird = Bird::where("species", "=", "Aratinga solstitialis")->first();
echo "This " . strtolower($bird->species) . " can " . ($bird->flying ? "" : "not ") . "fly";
// This aratinga solstitialis can fly
At each level of inheritance the object has an ID. In the example above, the $bird has an Animal ID as well as a Bird ID. In addition to this each entity has a common ID called Entity ID which is consistent throughout it's class hierarchy.
Use the id_as
method to get the id for an entity at a specific level of inheritance:
// The entity's Animal ID
echo $bird->id_as(Animal::class);
// The entity's Bird ID
echo $bird->id_as(Bird::class);
Or use the entity_id
property to get the entities common ID:
// The entity's common ID
echo $bird->entity_id
Relationships work like regular eloquent relationships but bear in mind that you can reference specific levels of inheritance. For example:
class Trainer extends Entity
{
public $table = "trainers";
protected $fillable =
[
'name',
'animal_id',
];
public function animal()
{
return $this->belongsTo(Animal::class);
}
}
class CreateTrainersTable extends Migration
{
public function up()
{
Schema::create('trainers', function (Blueprint $table)
{
$table->increments('id');
$table->integer('entity_id')->unsigned();
$table->string('name', 250)->nullable();
$table->integer('animal_id')->unsigned();
});
Schema::table('trainers', function ($table)
{
$table->foreign('animal_id')->references('id')->on('animals')->onDelete('cascade');
});
$entity_type = new EntityType(["entity_class" => Trainer::class]); $entity_type->save();
}
public function down()
{
Schema::drop('trainers');
$entity_type = EntityType::where("entity_class", Trainer::class)->first(); if($entity_type) EntityType::destroy([$entity_type->id]);
}
}
$bird = Bird::where("species", "=", "Aratinga solstitialis")->first();
$trainer = new Trainer
([
"name" => "Trainer 1",
"animal_id" => $bird->id_as(Animal::class), // Reference the bird's Animal ID
]);
$trainer->save();
echo gettype($trainer->animal); // Bird
echo $trainer->animal->species; // Aratinga solstitialis