Extend eloquent facilities to map one class Hierarchy branch to one table in database.
If you have one table on database (let say a Person
table with fields person_id
, name
and gender
) and you want to map it with your class hierarchy (let say a parent class Person
and 2 childs Man extends Person
and Woman extends Person
), then you can use this package to make the mapping automatically.
In parent class, define the Model as usual :
class Person extends Model {
protected $table = 'Person';
protected $primaryKey = 'person_id';
}
Define empty children classes :
class Man extends Person {}
class Woman extends Person {}
In parent class use the EloquentPolymorphism\PolymorphicParent
helper
You must define how database results will be bound with your class hierarchy (in my example it depends on the gender
field value)
protected function instanceFactory($attributes) {
if (!array_key_exists('gender', $attributes)) {
return static::class;
}
switch ($attributes['gender']) {
case self::TYPE_WOMAN:
return Woman::class;
case self::TYPE_MAN:
return Man::class;
}
return static::class;
}
With that you can retrieve a collection of Men and Women :
$persons = Person::all(); //an eloquent collection, containing instances of `Man` and instances of `Woman`
Now we must define constraints in child classes (otherwise Man::all()
would also retrieve a collection of men and women).
For that in children classes you have to use the trait EloquentPolymorphism\PolymorphicChild
and define the polymorphismScope
constraint ;
class Man extends Person {
* This scope will be added to all requests to make sure not retrieving other child.
*
* @param Builder $query
*/
protected function polymorphismScope(Builder $query) {
$query->where('gender', 'm');
}
}
Now if you write Man::all()
or any more complex query on Man
model it will result on a collection of Man
instances, corresponding to the table entries which represent men.
Optionally, you can overwrite the name of the scope you just defined in Man
class adding this code either in parent or child class :
protected function polymorphismScopeIdentifier() {
return 'polymorphism_scope_identifier';
}
It is strongly recommended to define default attributes values in children classes.
In our example it would be comfortable to write :
$woman = new Woman(['name' => 'Sandra']);
$woman->save();
without having to set her gender.
For this purpose, you must overwrite method setChildDefaultAttributes
in children classes
public function setChildDefaultAttributes() {
$this->gender = 'f';
}
The trait PolymorphicParent
prevents unnatural update/create on children like as example :
$man = new Man();
$man->gender = 'f';
$man->save(); //returns false, entry is not saved
This is done by checking that the conditions defined in instanceFactory
method would effectively retrieve an instance of Man
.
You can overwrite this behaviour by implementing the method checkHierarchyConstraintsBeforeSaving
class Man extends Person {
/**
* @return bool
*/
protected function checkHierarchyConstraintsBeforeSaving() {
//Your logic : return true if it's correct to consider this instance as beeing a man, false otherwise
}
}
You can use all other functionality of Eloquent models like usual. In particular, you can define relations and complex queries as needed.
Fork the project in your github account. Init gitflow
git flow init
git flow feature start feature-name develop
Composer install
sh composer.sh install
Test
docker-compose up testunit
Code
git push
Create a merge request from you're release branch to develop