Eloquent Inheritance Storage
, (*1)
Introduction
Eloquent Inheritance Storage is extending Eloquent ORM in order to provide support for models extending other models. It allows you to store and retrieve parent and child models easily., (*2)
This package is an extension of the single table inheritance pattern. It uses views to combine data coming from several tables of a class hierarchy. By doing this we are avoiding tables with many NULL values., (*3)
Installation
PHP 5.4+ and Laravel 4.2+ are required., (*4)
To get the latest version of Eloquent Inheritance Storage, simply require "thibaud-dauce/eloquent-inheritance-storage": "0.*" in your composer.json file. You'll then need to run composer install or composer update to download it and have the autoloader updated., (*5)
Once Eloquent Inheritance Storage is installed, you need to register the service provider. Open up app/config/app.php and add the following to the providers key., (*6)
'ThibaudDauce\EloquentInheritanceStorage\EloquentInheritanceStorageServiceProvider'
You can register the InheritanceStorage facade in the aliases key of your app/config/app.php file if you like., (*7)
'InheritanceStorage' => 'ThibaudDauce\EloquentInheritanceStorage\Facades\InheritanceStorage'
Model configuration example
Presentation
Let's imagine that I'm currently developing a video game with different kind of characters. I will have some basic characters and some specialized ones:
* A warrior will be a character with a rage attribute.
* A wizard will be a character with a magic attribute., (*8)
My class hierarchy will be the following:
* Character: id, name.
* Warrior extends Character: id, name, rage.
* Wizard extends Character: id, name, magic., (*9)
Models
Apply the ThibaudDauce\EloquentInheritanceStorage\ParentTrait to the Character model (the parent class)., (*10)
<?php
use ThibaudDauce\EloquentInheritanceStorage\ParentTrait;
class Character extends Eloquent {
use ParentTrait;
protected $table = 'characters';
protected $primaryKey = 'name';
}
Don't do anything to the Warrior and Wizard models (the child classes)., (*11)
<?php
class Warrior extends Character {
protected $table = 'warriors';
}
class Wizard extends Character {
protected $table = 'wizards';
}
Database
We are going to create 3 tables and a view:
* a table named characters_storage that will contain only basic characters (from the parent class).
* a table named warriors that will contain only warriors (from a child class).
* a table named wizards that will contain only wizards (from a child class).
* a view named characters that will contain characters, warriors and wizards., (*12)
Let's create our tables. Pay attention to the different tables' name!, (*13)
<?php
// Table for our parent class
Schema::create('characters_storage', function(Blueprint $table)
{
$table->increments('id');
$table->string('name')->unique();
});
// Tables for our child classes
Schema::create('warriors', function(Blueprint $table)
{
$table->increments('id');
$table->string('name')->unique();
$table->integer('rage');
});
Schema::create('wizards', function(Blueprint $table)
{
$table->increments('id');
$table->string('name')->unique();
$table->integer('magic');
});
And finally, let's create the characters view that will contain our characters, warriors and wizards. Don't forget to the add a class_name field to your view., (*14)
<?php
DB::statement("
CREATE VIEW `characters` AS
SELECT
`characters_storage`.`id` AS `id` ,
'Character' AS `class_name` ,
`characters_storage`.`name` AS `name` ,
NULL AS `rage` ,
NULL AS `magic` ,
FROM `characters_storage`
UNION
SELECT
`warriors`.`id` AS `id` ,
'Warrior' AS `class_name` ,
`warriors`.`name` AS `name` ,
`warriors`.`rage` AS `rage` ,
NULL AS `magic` ,
FROM `warriors`
UNION
SELECT
`wizards`.`id` AS `id` ,
'Wizard' AS `class_name` ,
`wizards`.`name` AS `name` ,
`wizards`.`magic` AS `magic` ,
NULL AS `rage` ,
FROM `wizards` ;
");
Usage
Get a model
Character::all() will return a collection containing Character, Warrior and Wizard models., (*15)
Character::find($characterName) will return a Character., (*16)
Character::find($warriorName) will return a Warrior., (*17)
Warrior::find($warriorName) will return a Warrior., (*18)
Warrior::find($characterName) or Warrior::find($wizardName) will throw an error., (*19)
Save a model
Character::create(array('name' => 'Thibaud')) will store a character in the characters_storage table., (*20)
Warrior::create(array('name' => 'Thibaud', 'rage' => 10)) will add a line in the warriors table., (*21)
Extending the package
Storage name
You can use a different storage table name by defining $inheritanceStorageName in your parent model., (*22)
Example: for a view named characters and a storage table named characters-table, (*23)
<?php
use ThibaudDauce\EloquentInheritanceStorage\ParentTrait;
class Character extends Eloquent {
use ParentTrait;
protected $table = 'characters';
protected $inheritanceStorageName = 'characters-table';
protected $primaryKey = 'name';
}