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 savedThis 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 developComposer install
sh composer.sh installTest
docker-compose up testunitCode
git pushCreate a merge request from you're release branch to develop