Связывание зависимых моделей из разных модулей

Выкладываем свои наработки
Ответить
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Связывание зависимых моделей из разных модулей

Сообщение lynicidn »

«Домашка» по Yii2

Не так давно был написан пост о «подводных камнях», в котором было «домашнее задание» — ответ на которое так никто и не написал, но думаю многие задавались вопросом — как все таки связывать модели из разных модулей. Хочу вам предложить вариант решения данной задачи.

«Наша банда» в составе 3 человек (d3r_rm(jabber), Insolita) пытается решать интересные задачки на данном фреймворке, в очередной раз, в свободное время — сели мы значит и стали проверять «смысловую нагрузку» поговорки -
Одна голова — хорошо, но две лучше
В итоге у нас нарисовалась следующая «концепция по разработке зависимых модулей»:
1. Регистрировать релейшены для моделей должны модули;
2. Релейшены должны храниться в статическом свойстве модели;
3. Возможность добавления релейшенов в обе стороны (как на модульную модель, так и в модульной модели — обратная);


Изображение

Добавление и хранение связей

Код: Выделить всё

protected static $relations = [];

public static function addRelation($name, $targetClass, $link, $multiple = false)
{
    self::$relations[$name] = [$targetClass, $link, $multiple];
}
Конечно же код не идеален (отсутствие php-doc), ну и многие задались сразу же вопросом — «а как быть с доп условиями (andWhere, orderBy, indexBy, ...)»? Но я, к сожалению не буду затрагивать в данной статье этот вопрос, т.к. это всего лишь наброски мыслей.
Трейт решит проблему со статическим свойством — уникальным для класса модели.


Создание связей

Код: Выделить всё

public function getRelation($name, $throwException = true)
{
    if (isset(self::$relations[$name])) {
        return $this->createRelation($name, $throwException);
    }
    return parent::getRelation($name, $throwException);
}

public function __get($name)
{
    if (isset(self::$relations[$name]) && !$this->isRelationPopulated($name)) {
        $related = $this->getRelation($name)->findFor($name, $this);
        $this->populateRelation($name, $related);
        return $related;
    }
    return parent::__get($name);
}

protected function createRelation($name, $throwException = true)
{
    $relation = self::$relations;
    if (!isset($relation[$name])) {
        if (!$throwException) {
            return null;
        }
        throw new InvalidCallException('Relation ' . $name . ' not find in class ' . get_class($this));
    }
    $relation = $relation[$name];
    $class = array_shift($relation);
    $query = $class::find();
    $query->link = array_shift($relation);
    $query->multiple = array_shift($relation);
    $query->primaryModel = $this;
    return $query;
}
подробнее смотрите [[yii\db\BaseActiveRecord::hasOne|hasMany]]

Объявление связей и их регистрация
в данном коде, рассмотрим пример из «домашки» — у пользователя несколько банковских аккаунтов (неймспейсы опустим для облегчения восприятия контента).

Код: Выделить всё

public $relations = [
    'User' => [
        'bankAccounts' => ['BankAccount', ['user_id' => 'id'], true]
    ],
    'BankAccount' => [
        'user' => ['User', ['id' => 'user_id'], false]
    ],
];

protected function registerRelations()
{
    foreach ($this->relations as $owner => $relations) {
        foreach ($relations as $name => $relation) {
            list ($targetClass, $link, $multiple) = $relation;
            $owner::addRelation($name, $targetClass, $link, $multiple);
        }
    }
}
Ждем критику, вопросы, предложения.
В скором времени будет создано и опубликовано расширение в публичном доступе
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Связывание зависимых моделей из разных модулей

Сообщение lynicidn »

п.с. данная статья была опубликована на хабре, но думаю многим известна моя манера общения - в связи с этим мой акк был переведен в режим чтения на 1 месяц, чтобы статье не пылиться - переношу ее сюда
chesar
Сообщения: 514
Зарегистрирован: 2013.04.10, 17:49

Re: Связывание зависимых моделей из разных модулей

Сообщение chesar »

Спасибо, что опубликовали.
lynicidn писал(а):В скором времени будет создано и опубликовано расширение в публичном доступе
up, чтоли... Хочется рабочего примера.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Связывание зависимых моделей из разных модулей

Сообщение lynicidn »

chesar писал(а):Спасибо, что опубликовали.
lynicidn писал(а):В скором времени будет создано и опубликовано расширение в публичном доступе
up, чтоли... Хочется рабочего примера.
спасибо за проявленный интерес, завалены временно, на выходных думаю запакуем в экстешн
chesar
Сообщения: 514
Зарегистрирован: 2013.04.10, 17:49

Re: Связывание зависимых моделей из разных модулей

Сообщение chesar »

lynicidn писал(а):[
Up :)
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Связывание зависимых моделей из разных модулей

Сообщение lynicidn »

chesar писал(а):
lynicidn писал(а):[
Up :)
special for you https://bitbucket.org/ydminko/activemanager/src
пока так, времени нет, позже тесты напишу, каменты
arogachev
Сообщения: 52
Зарегистрирован: 2014.09.09, 14:32

Re: Связывание зависимых моделей из разных модулей

Сообщение arogachev »

Чем обусловлена публикация на Bitbucket? Почему не на Github?
Мой профиль на Github
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Связывание зависимых моделей из разных модулей

Сообщение lynicidn »

arogachev писал(а):Чем обусловлена публикация на Bitbucket? Почему не на Github?
ничего против гитхаба не имею, просто было все настроено уже на битбакете,а что не так? :)
Ответить