项目作者: celinederoland

项目描述 :
Extend eloquent facilities to map one class Hierarchy branch to one table in database
高级语言: PHP
项目地址: git://github.com/celinederoland/eloquent-polymorphic-model.git


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 :

  1. class Person extends Model {
  2. protected $table = 'Person';
  3. protected $primaryKey = 'person_id';
  4. }

Define empty children classes :

  1. class Man extends Person {}
  2. 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)

  1. protected function instanceFactory($attributes) {
  2. if (!array_key_exists('gender', $attributes)) {
  3. return static::class;
  4. }
  5. switch ($attributes['gender']) {
  6. case self::TYPE_WOMAN:
  7. return Woman::class;
  8. case self::TYPE_MAN:
  9. return Man::class;
  10. }
  11. return static::class;
  12. }

With that you can retrieve a collection of Men and Women :

  1. $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 ;

  1. class Man extends Person {
  2. * This scope will be added to all requests to make sure not retrieving other child.
  3. *
  4. * @param Builder $query
  5. */
  6. protected function polymorphismScope(Builder $query) {
  7. $query->where('gender', 'm');
  8. }
  9. }

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 :

  1. protected function polymorphismScopeIdentifier() {
  2. return 'polymorphism_scope_identifier';
  3. }

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 :

  1. $woman = new Woman(['name' => 'Sandra']);
  2. $woman->save();

without having to set her gender.

For this purpose, you must overwrite method setChildDefaultAttributes in children classes

  1. public function setChildDefaultAttributes() {
  2. $this->gender = 'f';
  3. }

verifications on save method call

The trait PolymorphicParent prevents unnatural update/create on children like as example :

  1. $man = new Man();
  2. $man->gender = 'f';
  3. $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

  1. class Man extends Person {
  2. /**
  3. * @return bool
  4. */
  5. protected function checkHierarchyConstraintsBeforeSaving() {
  6. //Your logic : return true if it's correct to consider this instance as beeing a man, false otherwise
  7. }
  8. }

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

  1. git flow init
  2. git flow feature start feature-name develop

Composer install

  1. sh composer.sh install

Test

  1. docker-compose up testunit

Code

  1. git push

Create a merge request from you’re release branch to develop