дом модульный комплект

модульные дома в барнауле купить

модульные здания новосибирск

Гибкая модульная архитектура на Yii2 - Часть 1: Подключение модулей, роутинг и события

При разработке сложных приложений, которые нужно поддерживать долгое время, очень важно добиться гибкой и легко изменяемой архитектуры. Один из основополагающих принципов, помогающих сделать это, - модульность. Вся система разбивается на изолированные модули с низкой связанностью.

Многие считают, что на Yii2 нельзя писать сложные приложения. Но это не более, чем заблуждение. В этом цикле статей я хочу показать эффективный подход к построению модульной архитектуры на Yii2, который помогает строить гибкие и легко изменяемые системы.

одноэтажные модульные дома для постоянного проживания

Сразу обращаю ваше внимание на несколько моментов:

  • Этот подход наша команда использует в RESTful приложении. Поэтому здесь не затрагиваются вопросы работы с представлениями. Скорее всего данная архитектура будет корректно работать и для классических сайтов. Но могут быть подводные камни.
  • Здесь рассматривается только общая архитектура. Все вопросы оптимизации производительности и кастомизации выходят за рамки этой статьи.

Исходники с тестовыми данными лежат здесь (обратите внимание, ссылка указывает не на последний коммит).

Постановка задачи

Итак, какие требования мы предъявляем к нашему модульному приложению?

  • Возможность свободно включать и выключать любые модули. Приложение должно корректно работать с любым набором модулей. Но так же модули должны иметь возможность взаимодействовать друг с другом: обмениваться данными и командами.
  • Каждый модуль может иметь несколько версий, которые тоже должны безболезненно заменяться. Это позволяет добиться большой гибкости. Мы просто разрабатываем две версии модуля и подключаем ту, которая нужна текущему пользователю.
  • Модули должны быть самодостаточными. Это следствие первых двух требований. Если модуль может быть в любой момент добавлен/удален, он должен содержать в себе все, что необходимо для его работы, и абсолютно не зависеть от других модулей.
  • Возможность менять список активный модулей и их версий без вмешательства в код. Чтобы это можно было сделать, например, из админки.

Общий взгляд на архитектуру

В любом приложении есть логика, общая для всей системы. Поэтому наша система состоит из ядра и подключаемых модулей. Структура файлов особо не отличается от общепринятой в Yii2.

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

Подключение модулей

Прежде всего давайте посмотрим на структуру файлов модулей:

Здесь мы видим два модуля (созданы для примера): example_billing и example_tracker . Оба модуля имеют по две версии: v1 и v2 . Вся конечная логика описывается в модулях-версиях. В корневых модулях находятся классы, используемые всеми версиями (например, общие объекты событий).

Хранение списка модулей и их версий

Доступные модули и их версии хранятся в базе данных в таблицах module и module_version соответственно. В директории migrations можно увидеть миграции для их создания и заполнения. Их модели имеют следующий вид:

Вы можете хранить список модулей и их версий где хотите (хоть в настроечных файлах), но с БД работать удобней.

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

Инициализация приложения

При инициализации приложения нам нужно сделать две вещи: собрать из модулей правила роутинга и собрать обработчики событий. Это делается через обращение к статичным методам класса активной версии модуля. Использование статичных методов позволит нам обойтись без полной инициализации модуля.

Модули-версии наследуются от класса appcomponentsVersionModule . Этот класс содержит два метода:

Вот как выглядит подключение модулей:

С правилами роутинга все просто. UrlManager получает список роутов через VersionModule::getUrlRules() :

Регистрацию событий мы рассмотрим чуть позже. А сейчас обратим внимание на добавление модуля в приложение.

Замете, что добавляется модуль-версия. Но добавляется он под именем своего корневого модуля. Это сделано для того, чтобы к активной версии можно было всегда обращаться одинаково. Если у модуля example_billing активна версия v1 , то обращение к Yii::$app->getModule('example_billing') вернет нам класс appmodulesexample_billingmodulesv1V1 . Так же благодаря этому не нужно явно указывать версию модуля в урлах. Это избавляет клиентское приложение от еще одной зависимости.

Работа с событиями

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

Названия событий лучше хранить в виде констант. Это избавит нас от опечаток и облегчит навигацию по коду. Вопрос в том, где хранить эти названия? Логично было бы хранить их в самой версии. Чтобы было видно, какие события она может генерировать. Но в таком случае мы получаем новую зависимость: из одного модуля мы напрямую обращаемся к константе из другого. Это неприемлемо!

Чтобы такого не было, можно хранить имена событий в одном месте, где-нибудь в ядре. Это рабочий вариант. Но тогда нам придется указывать имя модуля в названии константы, плюс получим огромный список в одном месте.Есть еще один вариант - хранить имена событий в корневом классе модуля. Но в таком случае при полном отключении модуля вы не сможете просто удалить его директорию (такое может понадобиться при сборке приложения с урезанным функционалом) т.к. на корневой класс будут тоже ссылаться. Какой из этих способов использовать - решайте сами. Мне больше нравится второй.

Если версии одного модуля не сильно отличаются друг от друга (в нашем случае это было так), то большинство событий в модулей будут общими для всех версий. И нет необходимости объявлять их дважды. Вот как, например, выглядит описание событий в модуле ExampleBilling :

События ядра можно хранить в классе приложения:

Объекты событий лежат в директориях events в ядре или в модулях. И точно так же они могут быть общие для нескольких версий (и лежать в корне модуля) или принадлежать к конкретной версии.

Подписывание на события

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

Модуль или приложение передает массив обработчиков. Для каждого события можно назначить несколько обработчиков. Обработчиком может служить любой callable тип. На мой взгляд, удобней держать их в одном месте и поэтому я использую для этого классы EventHandler со статичными методами (но это только на мой взгляд).

Вот в каком виде список обработчиков возвращает модуль ExampleBilling :

Здесь добавляется два обработчика для события из ядра. Но точно так же мы может подписаться на события из других модулей или даже из своего же модуля.

Заключение

В этой статье мы рассмотрели основные механизмы. Это уже рабочий вариант. Дальше мы рассмотрим, как облегчить написание версий, слабо связанных между собой. А так же поговорим о том, как удобно разнести по модулям миграции и словари.

Коментарии

Thank you for comment!
Ваше сообщение будет доступно после проверки.

Haru Atari, большое спасибо. Проблема была в htaccess. все заработало на ура. На данный момент перенес код на Advanced версию Yii2.

Джони, добрый день. Код на гитхабе является рабочим. Сначала надо указать данные для подключения к вашей БД и применить миграции из репозитория. Тогда будут резолвиться контроллеры из активных версий модулей. Я не могу просто так угадать, в чем у вас проблема. Попробуйте добавить в UrlManager точки останова и посмотрите, собираются ли правила роутинга из активных модулей.

Добрый день! Уже не первый день пытаюсь запустить данный проект из гитхаба, но кроме страницы "Not Found (#404)" у меня ничего не запускается. Не могли бы Вы по подробнее написать инструкцию запуска проекта или выложить рабочую версию? Этот вариант разработки модулей мне очень понравился. Спасибо вам за ваши старания!

Ок. Продублировал оглавление под статьей.

лучше вниз. Я искал сейчас и если бы не вышестоящие комментарии, то не вспомнил бы что ссылки есть вверху. Можно и там и там

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

Спасибо за статьи! есть одно предложение, переместить ссылки на следующии статьи вниз.

модульные дома в красноярске под ключ цены

модульные дома санкт петербург

Комментарии запрещены.

Навигация по записям