jlorente / yii2-activerecord-inheritance

ActiveRecord Inheritance is an util to provide the Class Table Inheritance Pattern the to the Yii2 framework
MIT License
18 stars 7 forks source link
activerecord activerecord-inheritance inheritance php yii2-framework

ActiveRecord Inheritance

ActiveRecord Inheritance is a util to provide the Class Table Inheritance Pattern to the Yii2 framework. Its motivation is to fake inheritance between two ActiveRecord classes.

Installation

Include the package as dependency under the bower.json file.

To install, either run

$ php composer.phar require jlorente/yii2-activerecord-inheritance "*"

or add

...
    "require": {
        ...
        "jlorente/yii2-activerecord-inheritance": "*"
    }

to the require section of your composer.json file.

Usage

An example of usage could be:

Suppose you have the following schema.

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `last_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` int(11) NOT NULL,
  `updated_at` int(11) NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `admin` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `level` INT NOT NULL,
  `banned_users` INT NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  CONSTRAINT `FK_Admin_Id` FOREIGN KEY (`id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
);

To fake the inheritance between the two tables your code must look like this.

use jlorente\db\ActiveRecordInheritanceTrait,
    jlorente\db\ActiveRecordInheritanceInterface;
use yii\db\ActiveRecord;

class User extends ActiveRecord {

    public function tableName() {
        return 'user';
    }

    public function doSomething() {
        echo 'User does something';
    }
}

class Admin extends ActiveRecord implements ActiveRecordInheritanceInterface {
    use ActiveRecordInheritanceTrait;

    public function tableName() {
        return 'admin';
    }

    public static function extendsFrom() {
        return User::className();
    }

    public function doSomething() {
        echo 'Admin does something';
    }
}

And you will be able to use Admin objects as if they were inheriting from User objects.

$admin = new Admin();
$admin->username = 'al-acran';
$admin->email = 'al_acran@gmail.com';
$admin->name = 'Al';
$admin->last_name = 'Acran';
$admin->level = 1;
$admin->save();

You can call parent methods and properties by using the parent relation property.

$admin->doSomething()           //Admin does something
$admin->parent->doSomething()   //User does something

This trait is very useful for faking inheritance, however query filters should be applied on the parent relation.

$admin = Admin::find()
    ->joinWith('parent', function($query) {
        $query->andWhere(['username' => 'al-acran']);
        $query->andWhere(['name' => 'Al']);
    })
    ->andWhere(['level' => 1])
    ->one();

Considerations

In order to use the trait properly, you must consider the following points

General

ActiveRecord methods

Inheritance call hierarchy

License

Copyright © 2015 José Lorente Martín jose.lorente.martin@gmail.com. Licensed under the MIT license. See LICENSE.txt for details.