Laravel Eloquent Полиморфная Модель - PullRequest
0 голосов
/ 30 апреля 2018

У меня возникла ситуация, когда мне была нужна модель Eloquent для динамического гидратации в определенный класс, который расширяет мою "нормальную" модель eloquent. Вот общая схема, основанная на типичной электронике:

Объект данных:

['id', 'model_type', 'name', 'serial',...]
  • Модель
    • Модель Типа A
    • Модель Типа B

Если все данные находятся в одной таблице (MySQL), у Laravel на самом деле нет способа извлекать эти данные напрямую как полиморф. Вы можете изменить отношения, но не модель напрямую.

По сути, причина этого в том, чтобы отделить логику, которая может касаться одного типа, но не другого. Например, Model Type A и Model Type B могут оба реализовать интерфейс, который описывает их возможности, но специальная логика для A не должна загрязнять B.

1 Ответ

0 голосов
/ 30 апреля 2018

Мое решение для этого - переопределить метод newFromBuilder в модели (Laravel 5.6). Вот так:

App \ Схемы \ BaseScheme

abstract class BaseScheme extends Electronic
{
    // abstract methods to implement
    // ...
}

App \ Схемы \ ElectronicTypeA

class ElectronicTypeA extends BaseScheme
{
    // Electronic Type A logic
}

App \ Схемы \ ElectronicTypeB

class ElectronicTypeB extends BaseScheme
{
    // Electronic Type B logic
} 

App \ Models \ Electronic

use Illuminate\Database\Eloquent\Model;

class Electornic extends Model
{
    public function newFromBuilder($attributes = [], $connection = null)
    {
        if (!class_exists($attributes->model_type)) {
            throw new \Exception("Invalid Scheme ({$attributes->model_type})"); 
        }

        $class = $attributes->model_type;
        $model = new $class;

        if (!$model instanceof \App\Schemes\BaseScheme) {
            throw new \Exception("Scheme class is invalid ({$attributes->model_type})");
        }

        $model->exists = true;

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

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

        $model->fireModelEvent('retrieved', false);

        return $model;
    }

Где \App\Schemes\BaseScheme - это абстракция, которая распространяется на все логические модели. \App\Schemes\BaseScheme также расширяет оригинальную модель Eloquent.

* * * * * * * * * * * '' * '' 'хорошо' в том, что он работает и с возвращенной коллекцией. Таким образом, вы можете взаимодействовать с моделью, как если бы это была обычная модель, но вы действительно взаимодействуете с конкретными классами (typeA, typeB).

...