Завантаження
Завантаження — це процес ініціалізації середовища додатка, створення контейнера впровадження залежностей (DI) та запуску додатка. Ми обговоримо:
- як клас Bootstrap ініціалізує середовище
- як додатки налаштовуються за допомогою 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__); // Configurator відповідає за налаштування середовища застосунку та сервісів. $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(); Як бачимо, з налаштуванням середовища та створенням DI-контейнера (впровадження залежностей) допомагає клас Nette\Bootstrap\Configurator, який ми зараз детальніше розглянемо.
Режим розробки проти робочого режиму
Nette поводиться по-різному залежно від того, чи працює він на сервері розробки чи на робочому сервері:
- 🛠️ Режим розробки (Development)
- Показує панель налагодження Tracy з корисною інформацією (SQL-запити, час виконання, використана пам'ять)
- У разі помилки показує детальну сторінку помилки з викликами функцій та вмістом змінних
- Автоматично оновлює кеш при зміні шаблонів Latte, редагуванні конфігураційних файлів тощо.
- 🚀 Робочий режим (Production)
- Не показує жодної налагоджувальної інформації, всі помилки записує в лог
- У разі помилки показує ErrorPresenter або загальну сторінку “Server Error”
- Кеш ніколи автоматично не оновлюється!
- Оптимізований для швидкості та безпеки
Вибір режиму здійснюється автовизначенням, тому зазвичай не потрібно нічого налаштовувати або вручну перемикати:
- режим розробки: на 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(); Альтернативний підхід — дозволити завантажувати класи лише через Composer, дотримуючись PSR-4.
Часовий пояс
За допомогою конфігуратора ви можете встановити стандартний часовий пояс.
$this->configurator->setTimeZone('Europe/Kyiv'); Конфігурація 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(); }