Bootstrap
Bootstrap – це завантажувальний код, який ініціалізує середовище, створює контейнер впровадження залежностей (DI) і запускає додаток. Ми обговоримо:
- як налаштувати застосунок за допомогою файлів NEON
- як працювати з режимами виробництва та розробки
- як створити контейнер DI
Додатки, чи то веб-додатки, чи то скрипти командного рядка,
починаються з ініціалізації середовища в тій чи іншій формі. У
стародавні часи за це міг відповідати файл з ім'ям, наприклад,
include.inc.php
, який включався у вихідний файл. У сучасних додатках Nette
він замінений класом Bootstrap
, який як частина додатка знаходиться
у файлі app/Bootstrap.php
. Це може виглядати, наприклад, так:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// Конфігуратор відповідає за налаштування середовища та служб програми.
$this->configurator = new Configurator;
// Встановіть каталог для тимчасових файлів, що генеруються Nette (наприклад, скомпільовані шаблони)
$this->configurator->setTempDirectory($this->rootDir . '/temp');
}
public function bootWebApplication(): Nette\DI\Container
{
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}
private function initializeEnvironment(): void
{
// Nette розумний, і режим розробки вмикається автоматично,
// або ви можете увімкнути його для певної IP-адреси, не коментуючи наступний рядок:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Вмикає Tracy: найкращий інструмент налагодження "швейцарський армійський ніж".
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: автозавантаження всіх класів у вказаному каталозі
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Завантажити конфігураційні файли
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
Початковим файлом для веб-додатків є index.php
, розташований у
загальнодоступному каталозі www/
. Він використовує клас
Bootstrap
для ініціалізації середовища і створення DI-контейнера.
Потім він отримує сервіс Application
з контейнера, який запускає
веб-додаток:
$bootstrap = new App\Bootstrap;
// Ініціалізація середовища + створення контейнера DI
$container = $bootstrap->bootWebApplication();
// Контейнер 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()
:
$this->configurator->setDebugMode('23.75.345.200'); // одна або більше IP-адрес
Ми безумовно рекомендуємо поєднувати IP-адресу з файлом cookie. Ми
зберігатимемо секретний токен у cookie nette-debug', например, `secret1234
, і
режим розробки буде активовано для програмістів із такою комбінацією
IP і cookie.
$this->configurator->setDebugMode('secret1234@23.75.345.200');
Можна повністю вимкнути режим розробника, навіть для localhost:
$this->configurator->setDebugMode(false);
Зверніть увагу, що значення true
жорстко вмикає режим
розробника, чого ніколи не повинно відбуватися на робочому сервері.
Налагоджувальний інструмент Tracy
Для полегшення налагодження ми увімкнемо чудовий інструмент Tracy. У режимі розробника він візуалізує помилки, а в режимі виробництва – записує помилки в зазначений каталог:
$this->configurator->enableTracy($this->rootDir . '/log');
Тимчасові файли
Nette використовує кеш для DI-контейнера, RobotLoader, шаблонів тощо. Тому необхідно задати шлях до директорії, де зберігатиметься кеш:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
У Linux або macOS встановіть права на запис для
каталогів log/
і temp/
.
RobotLoader
Зазвичай ми хочемо автоматично завантажувати класи за допомогою RobotLoader, тому ми повинні запустити його і
дозволити йому завантажити класи з каталогу, в якому знаходиться
Bootstrap.php
(тобто __DIR__
) і всі його підкаталоги:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Альтернативний спосіб – використовувати лише автозавантаження PSR-4 Composer.
Часовий пояс
Configurator дає змогу вказати часовий пояс для вашого застосунку.
$this->configurator->setTimeZone('Europe/Prague');
Конфігурація DI-контейнера
Частиною процесу завантаження є створення DI-контейнера, тобто фабрики об'єктів, яка є серцем усього додатка. Насправді це PHP-клас, створений Nette, який зберігається в каталозі кешу. Фабрика створює ключові об'єкти застосунку, а конфігураційні файли інструктують її, як їх створювати та налаштовувати, і таким чином ми впливаємо на поведінку всього застосунку.
Файли конфігурації зазвичай записуються у форматі NEON. Ви можете прочитати що можна налаштувати тут.
У режимі розробки контейнер автоматично оновлюється щоразу, коли ви змінюєте код або конфігураційні файли. У виробничому режимі він генерується лише один раз, а зміни файлів не перевіряються для досягнення максимальної продуктивності.
Файли конфігурації завантажуються за допомогою addConfig()
:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Метод addConfig()
може бути викликаний кілька разів для додавання
декількох файлів.
$configDir = $this->rootDir . '/config';
$this->configurator->addConfig($configDir . '/common.neon');
$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
$this->configurator->addConfig($configDir . '/cli.php');
}
Підключення cli.php
не є друкарською помилкою, конфігурацію
також можна записати в PHP-файлі, який повертає її у вигляді масиву.
Альтернативно, ми можемо використовувати секцію includes
для завантаження конфігураційних файлів.
Якщо елементи з однаковими ключами відображаються у файлах
конфігурації, вони будуть перезаписані або
об'єднані у випадку масивів. Пізніше включений файл має вищий
пріоритет, ніж попередні. Файл, зазначений у секції includes
, має
вищий пріоритет, ніж файли, включені в нього.
Статичні параметри
Параметри, що використовуються у файлах конфігурації, можуть бути
визначені в секції
parameters
і підхоплені (або перезаписані) методом
addStaticParameters()
(у нього є аліас addParameters()
). Важливо, що різні
значення параметрів викликають генерацію додаткових DI-контейнерів,
тобто додаткових класів.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
У конфігураційних файлах ми можемо записати звичайну нотацію
%projectId%
для доступу до параметра з ім'ям projectId
.
Динамічні параметри
Можна також додати динамічні параметри в контейнер. Їхні різні значення, на відміну від статичних параметрів, не призведуть до генерації нових DI-контейнерів.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Змінні середовища можуть бути легко доступні з використанням
динамічних параметрів. Ми можемо отримати доступ до них через
%env.variable%
у файлах конфігурації.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Параметри за замовчуванням
Ви можете використовувати наступні статичні параметри у файлах конфігурації:
%appDir%
– абсолютний шлях до каталогу з файломBootstrap.php
%wwwDir%
– абсолютний шлях до каталогу, в якому знаходиться файл записуindex.php
%tempDir%
– абсолютний шлях до каталогу для тимчасових файлів%vendorDir%
– абсолютний шлях до каталогу, куди Composer встановлює бібліотеки%rootDir%
– абсолютний шлях до кореневого каталогу проекту%debugMode%
вказує на те, чи перебуває програма у режимі налагодження%consoleMode%
вказує на те, що запит надійшов через командний рядок
Імпортовані сервіси
Заглибимося далі. Хоча мета DI-контейнера у створенні об'єктів, може
виникнути необхідність вставити наявний об'єкт у контейнер. Це
робиться визначенням сервісу з атрибутом imported: true
:
services:
myservice:
type: App\Model\MyCustomService
imported: true
Створюємо новий екземпляр і вставляємо його в Bootstrap:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Різні середовища
Не соромтеся налаштовувати клас Bootstrap
відповідно до ваших
потреб. Ви можете додати параметри до методу bootWebApplication()
, щоб
розрізняти веб-проекти. Крім того, ви можете додати інші методи, такі як
bootTestEnvironment()
для ініціалізації середовища для модульних тестів,
bootConsoleApplication()
для скриптів, що викликаються з командного рядка,
і так далі.
public function bootTestEnvironment(): Nette\DI\Container
{
Tester\Environment::setup(); // Ініціалізація Nette Tester
$this->setupContainer();
return $this->configurator->createContainer();
}
public function bootConsoleApplication(): Nette\DI\Container
{
$this->configurator->setDebugMode(false);
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}