Skip to content

Extend eloquent facilities to map one class Hierarchy branch to one table in database

Notifications You must be signed in to change notification settings

celinederoland/eloquent-polymorphic-model

Repository files navigation

Eloquent extension for polymorphic models

Extend eloquent facilities to map one class Hierarchy branch to one table in database.

Purpose

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.

Configure class mapping

Retrieving instances from the parent class

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`

Retrieving instances from children classes

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';
}

Updating/Creating model :

default attributes

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';
}

verifications on save method call

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
  }
}

Complex queries, relations, etc.

You can use all other functionality of Eloquent models like usual. In particular, you can define relations and complex queries as needed.

Contribute

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

About

Extend eloquent facilities to map one class Hierarchy branch to one table in database

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published