Модули ¶
Модули - это законченные программные блоки, состоящие из моделей, представлений, контроллеров и других вспомогательных компонентов. При установке модулей в приложение, конечный пользователь получает доступ к их контроллерам. По этой причине модули часто рассматриваются как миниатюрные приложения. В отличие от приложений, модули нельзя развертывать отдельно. Модули должны находиться внутри приложений.
Создание модулей ¶
Модуль помещается в директорию, которая называется yii\base\Module::basePath модуля. Так же как и в
директории приложения, в этой директории существуют поддиректории controllers
, models
, views
и другие, в которых
размещаются контроллеры, модели, представления и другие элементы. В следующем примере показано примерное содержимое модуля:
forum/
Module.php файл класса модуля
controllers/ содержит файлы классов контроллеров
DefaultController.php файл класса контроллера по умолчанию
models/ содержит файлы классов моделей
views/ содержит файлы представлений контроллеров и шаблонов
layouts/ содержит файлы представлений шаблонов
default/ содержит файлы представления контроллера DefaultController
index.php файл основного представления
Классы модулей ¶
Каждый модуль объявляется с помощью уникального класса, который наследуется от yii\base\Module. Этот класс должен быть помещен в корне yii\base\Module::basePath модуля и поддерживать автозагрузку. Во время доступа к модулю будет создан один экземпляр соответствующего класса модуля. Как и экземпляры приложения, экземпляры модулей нужны, чтобы код модулей мог получить общий доступ к данным и компонентам.
Приведем пример того, как может выглядеть класс модуля:
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->params['foo'] = 'bar';
// ... остальной инициализирующий код ...
}
}
Если метод init()
стал слишком громоздким из-за кода, который задает свойства модуля, эти свойства можно сохранить
в виде конфигурации, а затем загрузить в методе init()
следующим образом:
public function init()
{
parent::init();
// инициализация модуля с помощью конфигурации, загруженной из config.php
\Yii::configure($this, require __DIR__ . '/config.php');
}
При этом в конфигурационном файле config.php
может быть код следующего вида, аналогичный
конфигурации приложения:
<?php
return [
'components' => [
// список конфигураций компонентов
],
'params' => [
// список параметров
],
];
Контроллеры в модулях ¶
При создании контроллеров модуля принято помещать классы контроллеров в подпространство controllers
пространства
имён класса модуля. Это также подразумевает, что файлы классов контроллеров должны располагаться в директории controllers
yii\base\Module::basePath модуля. Например, чтобы описать контроллер post
в модуле forum
из
предыдущего примера, класс контроллера объявляется следующим образом:
namespace app\modules\forum\controllers;
use yii\web\Controller;
class PostController extends Controller
{
// ...
}
Изменить пространство имен классов контроллеров можно задав свойство yii\base\Module::$controllerNamespace. Если какие-либо контроллеры выпадают из этого пространства имен, доступ к ним можно осуществить, настроив свойство yii\base\Module::$controllerMap, аналогично тому, как это делается в приложении.
Представления в модулях ¶
Представления модуля также следует поместить в поддиректорию views
yii\base\Module::basePath
модуля. Виды, которые рендерит контроллер модуля, должны располагаться в директории views/ControllerID
, где ControllerID
соответствует идентификатору контроллера. Например, если контроллер реализуется
классом PostController
, представления следует разместить в поддиректории views/post
yii\base\Module::basePath модуля.
В модуле можно задать шаблон, который будет использоваться для рендеринга всех представлений
контроллерами модуля. По умолчанию шаблон помещается в директорию views/layouts
, а свойство yii\base\Module::$layout
должно указывать на имя этого шаблона. Если не задать свойство layout
, модуль будет использовать шаблон, заданный
в приложении.
Консольные команды в модулях ¶
Ваш модуль также может объявлять команды, которые будут доступны через консоль.
Для того, чтобы команда стала доступна, надо изменить свойство yii\base\Module::$controllerNamespace для консольного режима так, чтобы оно содержало пространство имён ваших команд.
Этого можно добиться проверяя класс экземпляра приложения Yii в методе init
модуля:
public function init()
{
parent::init();
if (Yii::$app instanceof \yii\console\Application) {
$this->controllerNamespace = 'app\modules\forum\commands';
}
}
Ваши команды будут доступны из командной строки как:
yii <module_id>/<command>/<sub_command>
Использование модулей ¶
Чтобы задействовать модуль в приложении, достаточно включить его в свойство yii\base\Application::modules
в конфигурации приложения. Следующий код в конфигурации приложения
задействует модуль forum
:
[
'modules' => [
'forum' => [
'class' => 'app\modules\forum\Module',
// ... другие настройки модуля ...
],
],
]
Info: Для подключения консольных команд вашего модуля, нужно также включить его в конфигурации консольного приложения
Свойству yii\base\Application::modules присваивается массив, содержащий конфигурацию модуля. Каждый ключ массива представляет собой идентификатор модуля, который однозначно определяет модуль среди других модулей приложения, а соответствующий массив - это конфигурация для создания модуля.
Маршруты ¶
Как маршруты приложения используются для обращения к контроллерам приложения, маршруты
модуля используются, чтобы обращаться к контроллерам этого модуля. Маршрут контроллера в модуле должен начинаться с
идентификатора модуля, за которым следуют идентификатор контроллера и
идентификатор действия. Например, если в приложении задействован модуль forum
,
то маршрут forum/post/index
соответствует действию index
контроллера post
этого модуля. Если маршрут состоит только
из идентификатора модуля, то контроллер и действие определяются исходя из свойства yii\base\Module::$defaultRoute,
которое по умолчанию равно default
. Таким образом, маршрут forum
соответствует контроллеру default
модуля forum
.
Правила в URL manager для модулей должны быть добавленны перед началом работы yii\web\UrlManager::parseRequest(), что не
позволяет размещать код добавления правил модуля в init()
, так как инициализация происходит уже после обработки маршрутов. Таким образом, добавление маршрутов необходимо осуществить в предзагрузке
модуля. Хорошей практикой, также, будет объединение всех правил модуля
при помощи yii\web\GroupUrlRule.
Если же вы используете модуль для версионирования API, URL правила необходимо добавлять
непосредственно в конфигурации urlManager
приложения.
Получение доступа к модулям ¶
Зачастую внутри модуля может потребоваться доступ к экземпляру класса модуля, через который получаются идентификатор модуля, его параметры, компоненты, и т. п. Это можно сделать с помощью следующей конструкции:
$module = MyModuleClass::getInstance();
где MyModuleClass
соответствует имени класса модуля, доступ к которому нужно получить. Метод getInstance()
возвращает
запрошенный в данный момент экземпляр класса модуля. Если модуль не запрошен, метод вернет null
. Учтите, что обычно
экземпляры класса модуля вручную не создаются, так как созданный вручную экземпляр будет отличаться от экземпляра,
созданного Yii в качестве ответа на запрос.
Info: При разработке модуля нельзя исходить из предположения, что модулю будет назначен конкретный идентификатор. Это связано с тем, что идентификатор, назначаемый модулю при использовании в приложении или в другом модуле, может быть выбран совершенно произвольно. Чтобы получить идентификатор модуля, нужно вначале выбрать экземпляр модуля, как это описано выше, а затем получить доступ к идентификатору через свойство
$module->id
.
Доступ к экземпляру модуля можно получить следующими способами:
// получение дочернего модуля с идентификатором "forum"
$module = \Yii::$app->getModule('forum');
// получение модуля, к которому принадлежит запрошенный в настоящее время контроллер
$module = \Yii::$app->controller->module;
Первый подход годится только если известен идентификатор модуля, а второй подход наиболее полезен, если известно, какой контроллер запрошен.
Имея экземпляр модуля можно получить доступ к параметрам и компонентам, зарегистрированным в модуле. Например,
$maxPostCount = $module->params['maxPostCount'];
Предзагрузка модулей ¶
Может потребоваться запускать некоторые модули при каждом запросе. Модуль debug - один из таких модулей. Для этого список идентификаторов таких модулей необходимо указать в свойстве bootstrap приложения.
Например, следующая конфигурация приложения обеспечивает загрузку модуля debug
при каждом запросе:
[
'bootstrap' => [
'debug',
],
'modules' => [
'debug' => 'yii\debug\Module',
],
]
Вложенные модули ¶
Модули могут вкладываться друг в друга без ограничений по глубине. Иными словами, в модуле содержится модуль, в который входит еще один модуль, и т. д. Первый модуль называется родительским, остальные - дочерними. Дочерние модули объявляются в свойстве yii\base\Module::modules родительских модулей. Например,
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->modules = [
'admin' => [
// здесь имеет смысл использовать более лаконичное пространство имен
'class' => 'app\modules\forum\modules\admin\Module',
],
];
}
}
Маршрут к контроллеру вложенного модуля должен содержать идентификаторы всех его предков. Например, маршрут
forum/admin/dashboard/index
соответствует действию index
контроллера dashboard
модуля admin
, который в свою
очередь является дочерним модулем модуля forum
.
Info: Метод getModule() возвращает только те дочерние модули, которые принадлежат родительскому модулю непосредственно. В свойстве yii\base\Application::$loadedModules содержится список загруженных модулей, в том числе прямых и косвенных потомков, с индексированием по имени класса.
Лучшие практики ¶
Модули лучше всего подходят для крупных приложений, функционал которых можно разделить на несколько групп, в каждой из которых функции тесно связаны между собой. Каждая группа функций может разрабатываться в виде модуля, над которым работает один разработчик или одна команда.
Модули - это хороший способ повторно использовать код на уровне групп функций. В виде модулей можно реализовать такую функциональность, как управление пользователями или управление комментариями, а затем использовать эти модули в будущих разработках.