Bootstrap
Bootstrap — это загрузочный код, который инициализирует среду, создает контейнер внедрения зависимостей (DI) и запускает приложение. Мы обсудим:
- как настроить приложение с помощью файлов NEON
- как работать с режимами производства и разработки
- как создать контейнер DI
Приложения, будь то веб-приложения или скрипты командной строки,
начинаются с инициализации среды в той или иной форме. В древние
времена за это мог отвечать файл с именем, например, include.inc.php
,
который включался в исходный файл. В современных приложениях Nette он
заменен классом Bootstrap
, который как часть приложения находится в
файле app/Bootstrap.php
. Это может выглядеть, например, так:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
public static function boot(): Configurator
{
$appDir = dirname(__DIR__);
$configurator = new Configurator;
//$configurator->setDebugMode('secret@23.75.345.200');
$configurator->enableTracy($appDir . '/log');
$configurator->setTempDirectory($appDir . '/temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
$configurator->addConfig($appDir . '/config/common.neon');
return $configurator;
}
}
index.php
В случае веб-приложений начальным файлом является index.php
,
который находится в общедоступном каталоге www/
. Он позволяет
классу Bootstrap
инициализировать среду и возвращает
$configurator
, который создает контейнер DI. Затем он получает сервис
Application
, запускающий веб-приложение:
// инициализируем среду + получаем объект Configurator
$configurator = App\Bootstrap::boot();
// создаем DI-контейнер
$container = $configurator->createContainer();
// DI-контейнер создайет объект Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// запускаем приложение Nette
$application->run();
Как вы видите, класс Nette\Bootstrap\Configurator, который мы сейчас представим более подробно, помогает в настройке окружения и создании контейнера внедрения зависимостей (DI).
Режим разработки и режим производства
Nette различает два основных режима, в которых выполняется запрос: разработка и производство. Режим разработки ориентирован на максимальное удобство программиста, отображается Tracy, кэш автоматически обновляется при изменении шаблонов или конфигурации DI контейнера и т. д. Режим производства ориентирован на производительность, Tracy только регистрирует ошибки, а изменения шаблонов и других файлов не проверяются.
Выбор режима осуществляется путем автоопределения, поэтому обычно
нет необходимости настраивать или переключать что-либо вручную. Режим
разработки используется, если приложение запущено на localhost (т. е.
IP-адрес 127.0.0.1
или ::1
) и отсутствует прокси-сервер (т. е. его
HTTP-заголовок). В противном случае приложение работает в
производственном режиме.
Если вы хотите включить режим разработки в других случаях, например,
для программистов, получающих доступ с определенного IP-адреса, вы
можете использовать setDebugMode()
:
$configurator->setDebugMode('23.75.345.200'); // один или более IP-адресов
Мы определенно рекомендуем сочетать IP-адрес с файлом cookie. Мы будем
хранить секретный токен в cookie nette-debug', например, `secret1234
, и режим
разработки будет активирован для программистов с такой комбинацией IP
и cookie.
$configurator->setDebugMode('secret1234@23.75.345.200');
Можно полностью отключить режим разработчика, даже для localhost:
$configurator->setDebugMode(false);
Обратите внимание, что значение true
жестко включает режим
разработчика, чего никогда не должно происходить на рабочем сервере.
Отладочный инструмент Tracy
Для облегчения отладки мы включим замечательный инструмент Tracy. В режиме разработчика он визуализирует ошибки, а в режиме производства — записывает ошибки в указанный каталог:
$configurator->enableTracy($appDir . '/log');
Временные файлы
Nette использует кэш для DI-контейнера, RobotLoader, шаблонов и т. д. Поэтому необходимо задать путь к директории, где будет храниться кэш:
$configurator->setTempDirectory($appDir . '/temp');
В Linux или macOS установите права на запись для
каталогов log/
и temp/
.
RobotLoader
Обычно мы хотим автоматически загружать классы с помощью RobotLoader, поэтому мы должны запустить его и
позволить ему загрузить классы из каталога, в котором находится
Bootstrap.php
(т. е. __DIR__
) и все его подкаталоги:
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Альтернативный способ — использовать только автозагрузку PSR-4 Composer.
Часовой пояс
Configurator позволяет указать часовой пояс для вашего приложения.
$configurator->setTimeZone('Europe/Prague');
Конфигурация DI-контейнера
Частью процесса загрузки является создание DI-контейнера, то есть фабрики объектов, которая является сердцем всего приложения. На самом деле это PHP-класс, созданный Nette и хранящийся в каталоге кэша. Фабрика создает ключевые объекты приложения, а конфигурационные файлы инструктируют её, как их создавать и настраивать, и таким образом мы влияем на поведение всего приложения.
Файлы конфигурации обычно записываются в формате NEON. Вы можете прочитать что можно настроить здесь.
В режиме разработки контейнер автоматически обновляется каждый раз, когда вы изменяете код или конфигурационные файлы. В производственном режиме он генерируется только один раз, а изменения файлов не проверяются для достижения максимальной производительности.
Файлы конфигурации загружаются с помощью addConfig()
:
$configurator->addConfig($appDir . '/config/common.neon');
Метод addConfig()
может быть вызван несколько раз для добавления
нескольких файлов.
$configurator->addConfig($appDir . '/config/common.neon');
$configurator->addConfig($appDir . '/config/local.neon');
if (PHP_SAPI === 'cli') {
$configurator->addConfig($appDir . '/config/cli.php');
}
Подключение cli.php
не является опечаткой, конфигурация также
может быть записана в PHP-файле, который возвращает ее в виде массива.
Альтернативно, мы можем использовать секцию includes
для загрузки конфигурационных файлов.
Если элементы с одинаковыми ключами отображаются в файлах
конфигурации, они будут перезаписаны или
объединены в случае массивов. Позже включенный файл имеет более
высокий приоритет, чем предыдущие. Файл, указанный в секции
includes
, имеет более высокий приоритет, чем файлы, включенные
в него.
Статические параметры
Параметры, используемые в файлах конфигурации, могут быть определены
в секции parameters
и подхвачены (или перезаписаны) методом addStaticParameters()
(у него есть
алиас addParameters()
). Важно, что разные значения параметров вызывают
генерацию дополнительных DI-контейнеров, то есть дополнительных
классов.
$configurator->addStaticParameters([
'projectId' => 23,
]);
В конфигурационных файлах мы можем написать обычную нотацию
%projectId%
для доступа к параметру с именем projectId
.
Динамические параметры
Можно также добавить динамические параметры в контейнер. Их разные значения, в отличие от статических параметров, не приведут к генерации новых DI-контейнеров.
$configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Переменные среды могут быть легко доступны с использованием
динамических параметров. Мы можем получить доступ к ним через
%env.variable%
в файлах конфигурации.
$configurator->addDynamicParameters([
'env' => getenv(),
]);
Параметры по умолчанию
Вы можете использовать следующие статические параметры в конфигурационных файлах:
%appDir%
– абсолютный путь к директории, содержащей файлBootstrap.php
.%wwwDir%
– абсолютный путь к директории, содержащей входной файлindex.php
%tempDir%
– абсолютный путь к директории для временных файлов.%vendorDir%
– абсолютный путь к директории, в которую Composer устанавливает библиотеки.%debugMode%
указывает, находится ли приложение в режиме отладки%consoleMode%
указывает, поступил ли запрос через командную строку
Импортированные сервисы
Углубимся дальше. Хотя цель DI-контейнера в создании объектов, может
возникнуть необходимость вставить существующий объект в контейнер.
Это делается определением сервиса с атрибутом imported: true
:
services:
myservice:
type: App\Model\MyCustomService
imported: true
Создаём новый экземпляр и вставляем его в Bootstrap:
$configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Разные среды
Не стесняйтесь настроить класс Bootstrap
в соответствии с вашими
потребностями. Вы можете добавлять параметры в метод boot()
для
разделения веб-проектов, или добавлять другие методы, такие как
bootForTests()
, которые инициализируют среду для модульных тестов,
bootForCli()
для скриптов, вызываемых из командной строки, и
так далее.
public static function bootForTests(): Configurator
{
$configurator = self::boot();
Tester\Environment::setup(); // Инициализация Nette Tester
return $configurator;
}