04Приложение и его компоненты
Из чего состоит приложение Yii, что делает входной скрипт, какие свойства приложения стоит настроить и как работают компоненты через Yii::$app.
Приложение Yii — это объект Yii::$app, созданный входным скриптом по массиву-конфигурации. Он держит компоненты (БД, запрос, ответ, пользователь…), знает, где лежат контроллеры и представления, и проводит каждый запрос через свой жизненный цикл.
Что есть в приложении кроме MVC#
единственный PHP-файл, доступный снаружи (web/index.php или консольный yii). Создаёт приложение и запускает обработку запроса.
глобальный объект, координирующий всё остальное; доступен как Yii::$app.
именованные сервисы (db, request, user, cache…), зарегистрированные в конфигурации и создаваемые лениво.
самодостаточные мини-приложения со своими контроллерами, моделями и представлениями. См. Модули.
код до и после действия контроллера: доступ, кеш, CORS. См. Фильтры.
переиспользуемые блоки интерфейса внутри представлений. См. Виджеты.
Входной скрипт#
Он делает пять вещей: объявляет константы, подключает автозагрузчик Composer и класс Yii, читает конфигурацию, создаёт приложение и вызывает run().
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require __DIR__ . '/../vendor/autoload.php'; // автозагрузчик Composer
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; // класс Yii + автозагрузчик Yii + DI-контейнер
$config = require __DIR__ . '/../config/web.php';
(new yii\web\Application($config))->run();#!/usr/bin/env php
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/vendor/yiisoft/yii2/Yii.php';
$config = require __DIR__ . '/config/console.php';
$exitCode = (new yii\console\Application($config))->run();
exit($exitCode);Константы объявляют в самом начале, до подключения других файлов:
YII_DEBUGfalseYII_ENVprod (по умолчанию), dev, test; порождает YII_ENV_PROD, YII_ENV_DEV, YII_ENV_TESTYII_ENABLE_ERROR_HANDLERtruedefined('X') or define('X', v) — идиома «определить, если ещё не определено»: так константу можно переопределить снаружи, например в тестовом входном скрипте.
Объект приложения#
Два вида: yii\web\Application для HTTP и yii\console\Application для команд. Оба наследуют yii\base\Application, которая в свою очередь — модуль и Service Locator.
Обязательные свойства#
return [
'id' => 'basic', // уникальный идентификатор приложения
'basePath' => dirname(__DIR__), // корень с кодом; задаёт псевдоним @app
// ...
];Свойства, которые настраивают чаще всего#
aliases['@uploads' => '@webroot/uploads']. Удобнее, чем Yii::setAlias() в кодеbootstrapBootstrapInterface получит вызов bootstrap($app). Держите список коротким — он выполняется всегдаcomponentscontrollerMapcontrollerNamespaceapp\controllers; admin/post ищется в app\controllers\admin\PostControllermodules'forum' => ['class' => 'app\modules\forum\Module']paramsYii::$app->params['adminEmail']. Обычно подключают config/params.phplanguage / sourceLanguagetimeZonedate_default_timezone_set()catchAll['site/offline', 'param' => 'value']name, version, charsetUTF-8)Свойства с разумными умолчаниями#
defaultRoutesite для web (→ site/index), help для консолиlayout, layoutPath, viewPathmain в @app/views/layouts, представления в @app/views. layout => false отключает шаблонruntimePath@app/runtime, псевдоним @runtime. Должна быть доступна на запись и закрыта от вебаvendorPath@app/vendor, псевдоним @vendorextensions@vendor/yiisoft/extensions.phpenableCoreCommandsmigrate, cache, asset…). По умолчанию trueСобытия приложения#
Обработчики вешают прямо в конфигурации через синтаксис 'on имяСобытия' или кодом после создания приложения:
return [
'on beforeRequest' => function ($event) {
// приложение создано, запрос ещё не обрабатывался — удобно выбрать язык по домену
},
'on beforeAction' => function (\yii\base\ActionEvent $event) {
if ($somethingWrong) {
$event->isValid = false; // отменить выполнение действия
}
},
'on afterAction' => function (\yii\base\ActionEvent $event) {
$event->result = strtoupper($event->result); // изменить результат действия
},
];| Событие | Когда | Полезно для |
|---|---|---|
beforeRequest | до начала обработки запроса | переключение языка, темы, редиректы на обслуживание |
afterRequest | после обработки, до отправки ответа | постобработка, статистика |
beforeAction | перед действием; сначала у приложения, затем у модуля, затем у контроллера | проверки доступа «на самом верху» |
afterAction | после действия; в обратном порядке: контроллер → модуль → приложение | обёртка результата |
Жизненный цикл приложения#
- Входной скрипт читает конфигурацию — обычный PHP-массив из
config/web.php. - Создаётся объект приложения:
preInit()применяет критичные свойства (basePath), регистрируется обработчик ошибок, применяется остальная конфигурация,init()вызываетbootstrap()— подключаются расширения и компоненты изbootstrap. run()обрабатывает запрос: событиеbeforeRequest→ разбор маршрута компонентомrequest→ создание модуля/контроллера/действия → выполнение → событиеafterRequest→ отправка ответа.- Скрипт получает код выхода и завершает работу.
Подробнее о каждом шаге — в разделе Жизненный цикл запроса.
Компоненты приложения#
Приложение — это Service Locator: набор именованных объектов, к которым обращаются как Yii::$app->id. Компонент создаётся при первом обращении и дальше переиспользуется в рамках запроса.
'components' => [
'cache' => 'yii\caching\ApcCache', // просто имя класса
'db' => [ // массив конфигурации
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'search' => function () { // фабрика-замыкание
return new app\components\SolrService('127.0.0.1');
},
],Если компонент нужен в каждом запросе, даже когда к нему явно не обращаются (например, log должен ловить сообщения с самого начала), добавьте его ID в bootstrap:
'bootstrap' => ['log'],Встроенные компоненты#
У них фиксированные ID и классы по умолчанию — достаточно указать только нужные свойства.
| ID | Класс | За что отвечает |
|---|---|---|
request | yii\web\Request | параметры запроса, заголовки, куки, разбор маршрута |
response | yii\web\Response | код состояния, заголовки, тело, форматирование ответа |
urlManager | yii\web\UrlManager | разбор и генерация URL, правила ЧПУ |
user | yii\web\User | текущий аутентифицированный пользователь (только web) |
session | yii\web\Session | сессия и flash-сообщения (только web) |
db | yii\db\Connection | соединение с БД; класс и dsn нужно указать явно |
errorHandler | yii\web\ErrorHandler | перехват ошибок и исключений |
log | yii\log\Dispatcher | маршрутизация сообщений лога по целям |
view | yii\web\View | рендеринг представлений, регистрация скриптов |
assetManager | yii\web\AssetManager | публикация и подключение JS/CSS |
formatter | yii\i18n\Formatter | форматирование дат, чисел, размеров |
i18n | yii\i18n\I18N | переводы сообщений |
mailer | yii\symfonymailer\Mailer / yii\swiftmailer\Mailer | отправка писем |
cache | по соглашению yii\caching\Cache | кеш данных; не встроен, но ожидается многими компонентами |
id и basePath. Второе определяет псевдоним @app, от которого считаются runtimePath, viewPath и другие пути.
Лениво — при первом обращении Yii::$app->id. Чтобы создать его при старте каждого запроса, ID добавляют в bootstrap.
beforeAction: приложение → модуль → контроллер. afterAction: контроллер → модуль → приложение.
'catchAll' => ['site/offline'] — все запросы пойдут в это действие.
Чтобы константу можно было определить раньше (например, в тестовом входном скрипте или на сервере) без правки кода — повторный define вызвал бы ошибку.