Я знаю что сейчас в тренде писать статью про yii2, но мне хочется рассказать про свое недавнее открытие в первой yii.

Среди моделей достаточно часто встречается возможность использования наследования для создания специализированных сущностей. Например представим, что у нас есть сущность материал, у материала есть поддтипы: статья и галерея. В php это будет выглядеть так:

class Post extends CActiveRecord
{
    private $type;

// some code
}

class Article extends Post
{
// some code
}

class Gallery extends Post
{
// some code
}

Для такой схемы стандартным паттерном будет фабричный метод. В рамках ORM это должно быть реализовано следующем образом:

  1. Нужно запросить все материалы из таблицы material.
  2. Для каждой запипи на основе данных в ней создать необходимый тип модели.

Недавно просматривая исходные коды yii я наткнулся на метод instantiate к моделе CActiveRecord. Как сказано в его описании:

You may override this method if the instance being created depends the attributes that are to be populated to the record.

Это и есть тот самый фабричный метод, который нужен. Но кроме определения типа для модели, которую мы получаем из базы, нужно еще задавать тип для моделей которые мы получаем из форм. Для решения этого момента используется статичный метод. Тогда конечный код будет выглядеть вот так:

class Post extends CActiveRecord
{

    private $type;

    protected function instantiate($attributes)
    {
        $model = self::createModel($attributes, null);
        return $model;
    }

    public static function createModel($attributes = [], $scenario = 'insert')
    {
        if ($attributes) {
            switch ($attributes['type']) {
                case (TYPE_GALLERY): {
                    $model = new Gallery($scenario);
                    break;
                }
                case (TYPE_ARTICLE): {
                    $model = new Article($scenario);
                    break;
                }
                default:
                    $model = new Post($scenario);
            }
            $model->mailing_text_type = $attributes['type'];
        } else {
            $model = new Post($scenario);
        }
        return $model;
    }

}

С помощью такого приема можно значительно улучишить читабельность код.