По мере перевода частей проекта с yii на laravel, возникает необходимость в реализации на laravel тех же шаблонов, которые были реализованы на yii. Некоторое время назад я рассказывал о том, как на yii реализовать абстрактный метод для моделей. В этой статье я опишу, как сделать тоже самое в laravel.

Ключевым моментом является функция, которая будет вызываться каждый раз после выборки данных из БД и на основе данных будет определять тип модели. В laravel - это функция newFromBuilder. Для создания объектов нужного класса в моделях eloquent используется newInstance. Я считаю, что её стоит оставить неизменной, а для определения подкласса на основе данных создать отдельную функцию генератор. Тогда код будет выглядеть следующим образом:

class Plant extends Model
{

    protected $table = 'plants';

    /**
     * Create a new model instance that is existing.
     *
     * @param  array  $attributes
     * @param  string|null  $connection
     * @return static
     */
    public function newFromBuilder($attributes = [], $connection = null)
    {
        $model = static::newInstanceGenerator((array)$attributes, true);

        $model->setRawAttributes((array) $attributes, true);

        $model->setConnection($connection ?: $this->connection);

        return $model;
    }

    /**
     * Create a new instance of the given model.
     *
     * @param  array  $attributes
     * @param  bool   $exists
     * @return static
     */
    public static function newInstanceGenerator($attributes = [], $exists = false){
        $model = null;
        if (isset($attributes['type_id'])) {
            switch($attributes['type_id']) {
                case(PLANT_TYPE_FRUIT):{
                    $model = new Fruit([]);
                    break;
                }
                case(PLANT_TYPE_VEGETABLE):{
                    $model = new Vegetable([]);
                    break;
                }
            }

        }
        if (!$model) {
            $model = new static([]);
        }
        $model->exists = $exists;

        return $model;
    }
}

Данный фрагмент, позволит конкретезировать тип объектов, получамых на основе БД. Новых объектов нужно будет использовать генерацию через функцию newInstanceGenerator:

$fruit = Plant::newInstanceGenerator(['type_id' => PLANT_TYPE_FRUIT], false);

Если сравнивать yii и laravel, то сложность кода в обоих практически одинакова. Когда я пытался разобраться как реализовать этот код, то обращался за помощью к саппорту и они не смогли мне помочь. На мой взгляд, это говорит о том, что существуют проблемы с пониманием единого механизма работы eloquent. C другой стороны, благодаря большому количеству модулей, плагинов и наличию неплохих комментариев в коде очень многие вещи можно узнать читая исходный код.

Надеюсь, что эта небольшая статья поможет кому-нибудь упростить код своего проекта.