Список всех статей:
Обзор app-* шаблонов и demo
Текущая статья будет посвящена обзору app, app-api и app-console шаблонов, а также demo приложений.
Рассмотрим некоторые особенности конфигурирования шаблонов приложений по умолчанию, а также логику работы конфигов и расположение кодовой базы.
Начну с главного – различия app-* шаблонов и demo.
App
App-* – шаблоны приложения, готовые для использования в собственных проектах. Это просто болванка, скелетон или template готового приложения.
App – шаблон для классического PHP web + console приложения с server side rendering. То есть весь HTML страницы будет генерироваться на сервере.
App-api – шаблон для PHP web + console приложения с client side rendering. Обычно такие шаблоны используют для создания бэкендов для Single Page Application или различного рода “апишек”.
App-console – шаблон для написания console приложения. Из шаблона удалены все web-related things, однако вы можете в дальнейшем добавить туда их самостоятельно или воспользоваться одним из шаблонов выше.
На момент написания статьи в Yii3 существуют только 3 шаблона. В планах добавить еще несколько шаблонов для быстрого старта с асинхронными фреймворками, такими как AMPHP, ReactPHP, Swoole, RoadRunner, а также Temporal.
Demo
Demo – монорепозиторий с уже готовыми приложениями. В demo приложениях мы будем показывать вариации использования тех или иных библиотек. Приложения в demo предназначены просто для демонстрации работы фреймворка. Чтобы начать писать на Yii3, лучше создайте проект используя app-* шаблон.
На момент написания статьи demo содержит два приложения: blog и blog-api. В планах добавить еще интеграцию с RoadRunner и Temporal.
Если у вас есть желание создать новое приложение или улучшить существующее, то создайте Issue или PR, или просто напишите в чат, и мы обязательно рассмотрим любые доработки.
Начнем разбор фреймворка с app шаблона.
Установка
composer create-project yiisoft/app app --stability=dev
Флаг --stability=dev
нужен потому, что шаблоны приложения не имеют релизов, так как зависят от других пакетов, которые не имеют релизов.
Внимательный читатель может заметить, что в первой статье я обещал обозревать только стабильные пакеты. Простите меня за мою ложь. Я больше так не буду. Но не обещаю :)
После выполнения команды по установке в текущей директории появится директория с именем app. Там и лежит наш “пациент”.
cd app
– переходим в директорию с проектом.
Первым делом запускаем тесты:
./vendor/bin/codecept run
Тесты проходят. Всё отлично.
Структура
Общая структура app-* шаблонов и demo приложений покажется весьма знакомой современному разработчику.
Из непонятного – директории resources и runtime.
Runtime – директория, отвечающая за хранение промежуточных данных: кэша приложения, записей дебагера, ошибок от Codeception, кеша схемы Cycle и прочих пользовательских файлов. Подобные директории, как правило, стоит скрывать от индексирования в IDE. В PHPStorm, например, нужно в контекстном меню выбрать Mark Directory as
→ Excluded
.
Resources – директория для дополнительных ресурсов, таких как web assets, translator messages, layout + views, mail templates, rbac settings и любые другие ресурсы, которые вы захотите хранить у себя в приложении вне src и config.
Давайте заглянем глубже в директорию config.
С первого взгляда может показаться, что ничего не понятно – но давайте разбираться.
Директории web и console, а также файлы с суффиксами *-web
и *-console
подключаются, когда вы запускаете приложение из соответствующего окружения. yiisoft/config позволяет вам вручную манипулировать всеми этими файлами, но в yiisoft/yii-runner-* репозиториях все настройки по умолчанию прописаны за вас.
Директория common и файлы без префиксов будут подключаться во всех окружениях. Сначала они, потом *-web
или *-console
файлы, перезаписывая и дополняя то, что находится в общих конфигах.
Директории web и console отвечают за конфигурацию DI непосредственно для web и console приложений.
Например, конфигурация web содержит несколько файлов, которые объединяться в единый, и ими будет конфигурироваться контейнер зависимостей.
Также в директории config можно заметить 3 дочерние директории dev, prod и test. Они будут подключаться, когда переменная окружения YII_ENV
будет равняться dev, prod или test соответственно.
Структура подключаемых конфигов
У вас может появиться потребность изменить конфиг так, чтобы с ним было удобнее работать – переименовать директорию config, поменять расположение файлов внутри неё, хранить конфигурации модулей внутри самих модулей или помимо dev, prod или test окружений создать дополнительные окружения.
За работу с конфигами отвечает пакет yiisoft/config. А все необходимые параметры подключения этих файлов лежат в корневом composer.json. Они выглядят примерно так:
"extra": {
"config-plugin-options": {
"source-directory": "config"
},
"config-plugin-environments": {
"dev": {
"params": [
"test/params.php"
]
},
"prod": {
"params": [
"test/params.php"
]
},
"test": {
"params": [
"test/params.php"
]
}
},
"config-plugin": {
"common": "common/*.php",
"params": [
"params.php",
"?params-local.php"
],
"web": [
"$common",
"web/*.php"
],
"console": [
"$common",
"console/*.php"
],
...
}
},
Большую часть из примера я вырезал из-за одинаковости настройки.
Полную документацию работы пакета yiisoft/config вы можете найти в README репозитория. Более подробный разбор пакета будет в одной и следующих статей.
Точки входа в приложение
Точкой доступа для запуска приложения в web окружении является файл public/index.php
.
В нем есть запуск так называемого “раннера”, который конфигурирует, инициализирует и запускает основное приложение.
<?php
/// ...
// Run HTTP application runner
$runner = (new HttpApplicationRunner(dirname(__DIR__), $_ENV['YII_DEBUG'], $_ENV['YII_ENV']))
->withTemporaryErrorHandler(new ErrorHandler(
new Logger([new FileTarget(dirname(__DIR__) . '/runtime/logs/app.log')]),
new JsonRenderer(),
))
;
$runner->run();
Консольная версия раннера лежит в файле yii
в корневом каталоге.
Запуск консольного приложения выглядит следующим образом:
<?php
/// ...
// Run console application runner
$runner = new ConsoleApplicationRunner(__DIR__, $_ENV['YII_DEBUG'], $_ENV['YII_ENV']);
$runner->run();
Интерфейсы использования раннеров довольно простые. Достаточно указать всего несколько аргументов и вызвать $runner->run()
для его запуска. При желании раннеры можно сконфигурировать иначе. Разные раннеры предоставляют различные методы конфигурирования.
Полный разбор раннеров будет также в одной из следующих статей. Для справки, сейчас существуют следующие раннеры:
Также существует базовый раннер с общей функциональностью – yiisoft/yii-runner
Немного пояснений про withTemporaryErrorHandler()
При запуске HTTP раннера можно указать temporary error handler. Это обработчик, который будет обрабатывать все ошибки произошедшие до запуска основного приложения. Например, ошибка может произойти в момент конфигурирования DI контейнера. Так как контейнер еще не инициализирован, из него невозможно получить ErrorHandler. Для этих целей будет использоваться “временный”. Наличие такого временного обработчика ошибок позволит получить ответ в запрашиваемом формате – html, json или другом, который вы можете также сконфигурировать вручную.
Однако, использование “невременного” вам может тоже понадобиться. В нем можно подписаться на события приложения, заинжектить в него какой-то класс или что-то на ваш вкус. После запуска контейнера, временный обработчик отключается, и подключается обработчик из контейнера зависимостей.
Основные директории src и tests
Я уверен, что код в src вам покажется простым и понятным.
В src или tests нет каких-то Yii-specific мест. Максимум – это сконфигурированные классы по умолчанию. Всё взаимодействие классов происходит как во многих других фреймворках, с помощью ООП и Dependency Injection. Любые конфигурации классов вы можете переписать с помощью params.php
. Об этом будет рассказано в следующих статьях.
По умолчанию в шаблонах app-* и demo приложениях мы инициализируем Codeception с базовыми настройками, потому как считаем, что он будет чаще использоваться при разработке реальных проектов. Этот тестовый фреймворк никак не привязан к Yii3, и вы спокойно можете удалить его и оставить классический PHPUnit, который тоже идет вместе с шаблонами.
Пример контроллера
Рассмотрим пример контроллера на основе файла src/Controller/SiteController.php
:
<?php
declare(strict_types=1);
namespace App\Controller;
use Psr\Http\Message\ResponseInterface;
use Yiisoft\Yii\View\ViewRenderer;
final class SiteController
{
public function __construct(private ViewRenderer $viewRenderer)
{
$this->viewRenderer = $viewRenderer->withControllerName('site');
}
public function index(): ResponseInterface
{
return $this->viewRenderer->render('index');
}
}
\Yiisoft\Yii\View\ViewRenderer
– класс, который рендерит представление.
Метод ViewRenderer::withControllerName()
меняет базовую директорию в контексте класса с @views
на @views/site
.
Метод ViewRenderer::render()
вызывает непосредственно рендеринг представления @views/site/index.php
. Помимо PHP шаблонов Yii3 поддерживает еще и Twig.
Полный список всех поддерживаемых шаблонизаторов вы можете найти здесь.
В Telegram чате недавно подняли вопрос поддержки Smarty. Если вы любитель Smarty и хотите поддержку этого или любого другого шаблонизатора в Yii3, то приносите ваши предложения в Issue или в наш Telegram чат.
withControllerName()
– простой хелпер. Этот метод создан для того, чтобы не дублировать базовую директорию при каждом вызове метода render()
.
Вы можете не использовать этот метод и воспользоваться функцией внедрения зависимостей в action. В этом случае контроллер будет выглядеть следующим образом:
<?php
declare(strict_types=1);
namespace App\Controller;
use Psr\Http\Message\ResponseInterface;
use Yiisoft\Yii\View\ViewRenderer;
final class SiteController
{
public function index(ViewRenderer $viewRenderer): ResponseInterface
{
return $viewRenderer->render('site/index');
}
}
Пример функционального теста
Рассмотрим пример функционального теста на основе файла tests/Functional/SiteControllerTest.php
:
<?php
declare(strict_types=1);
namespace App\Tests\Functional;
use PHPUnit\Framework\TestCase;
use Yiisoft\Yii\Testing\FunctionalTester;
final class SiteControllerTest extends TestCase
{
private ?FunctionalTester $tester;
protected function setUp(): void
{
$this->tester = new FunctionalTester();
}
public function testGetIndex()
{
$method = 'GET';
$url = '/';
$this->tester->bootstrapApplication('web', dirname(__DIR__, 2));
$response = $this->tester->doRequest($method, $url);
$this->assertStringContainsString(
'Don\'t forget to check the guide',
$response->getContent()
);
}
}
В данной реализации используется пакет yiisoft/yii-testing.
Данный пакет предоставляет тестовый раннер приложения с возможностью подставлять моки сервисов непосредственно в контейнер зависимостей.
В примере выше приложение инициализируется строчкой $this->tester->bootstrapApplication('web', dirname(__DIR__, 2));
. web
указывает на окружение определений контейнера. Помните *-web
и *-console
файлы и директории? Это оно.
Далее в тесте происходит вызов маршрута GET /
строчкой $response = $this->tester->doRequest($method, $url)
. В переменной $response
будет объект класса \Yiisoft\Yii\Testing\ResponseAccessor
. Этот объект создан для упрощения работы с объектом ответа сервера. В дальнейшем этот класс будет расширяться дополнительными удобными методами для работа с объектом ответа, но и сейчас вы можете выполнить все необходимые проверки.
Для того, чтобы подставить сервис-заглушку в ваше приложение, вы можете вызвать метод mockService
: $this->tester->mockService($className, $definition);
. Вот реальный пример подстановки сервиса-заглушки.
О том, какими могут быть $className
и $definition
вы узнаете в следующей статье.
Инструменты для разработки
В шаблонах мы предустанавливаем вспомогательные для разработки инструменты.
Такие инструменты, как Psalm, Codeception, Infection, PHPUnit и PHPUnit-watcher добавлены в каждый из шаблонов.
Наличие сразу и Codeception, и PHPUnit обусловлено тем, что Codeception не ограничивает в написании юнит тестов напрямую при помощи PHPUnit.
Несмотря на то, что мы стараемся придерживаться OCP в разработке, мы открыты к изменениям. Если вы считаете, что шаблон приложения будет удобнее с вашими идеями, то создайте Issue, и мы постараемся воплотить их в коде. Это относится как и к шаблонам, так и к вспомогательным инструментам, и к фреймворку в целом.
Полезные ссылки
Канал для обсуждения Yii3. Задавайте вопросы, помогайте другим, принимайте участие в развитии фреймворка.
Страничка, где вы можете выразить благодарность финансово и ускорить разработку фреймворка.