Bootstrap
Bootstrap е кодът на bootstrap, който инициализира средата, създава контейнера за изпълнение на зависимости (DI) и стартира приложението. Обсъждаме:
- Как да настроите приложение, използващо файлове NEON
- Как да работите с режими за производство и разработка
- Как да създадете контейнер DI
Приложенията, независимо дали са уеб приложения или скриптове от
команден ред, започват с инициализиране на средата под една или друга
форма. В древни времена за това може да е отговарял файл, наречен
например include.inc.php
, който е бил включен в изходния файл. В
съвременните приложения на Nette той е заменен с класа Bootstrap
, който
се намира като част от приложението във файла app/Bootstrap.php
. Това
може да изглежда например така:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
public static function boot(): Configurator
{
$rootDir = dirname(__DIR__);
$configurator = new Configurator;
//$configurator->setDebugMode('secret@23.75.345.200');
$configurator->enableTracy($rootDir . '/log');
$configurator->setTempDirectory($rootDir . '/temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
$configurator->addConfig($rootDir . '/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 регистрира само грешки, а промените в шаблоните и другите файлове не се проверяват.
Режимът се избира чрез автоматично разпознаване, така че обикновено
не е необходимо да конфигурирате или превключвате нещо ръчно. Режимът
за разработка се използва, ако приложението се изпълнява на локален
хост (т.е. IP адресът е 127.0.0.1
или ::1
) и няма прокси сървър
(т.е. HTTP заглавието му). В противен случай приложението работи в
производствен режим.
Ако искате да активирате режима за разработка в други случаи,
например за програмисти, които имат достъп от определен IP адрес, можете
да използвате setDebugMode()
:
$configurator->setDebugMode('23.75.345.200'); // един или повече IP адреси
Определено препоръчваме да комбинирате IP адреса с “бисквитка”. Ще
съхраним тайния токен в “бисквитката” nette-debug', например, `secret1234
,
а режимът за разработка ще бъде активиран за програмистите с тази
комбинация от IP и “бисквитка”.
$configurator->setDebugMode('secret1234@23.75.345.200');
Можете да деактивирате напълно режима за разработчици, дори за localhost:
$configurator->setDebugMode(false);
Обърнете внимание, че стойността true
активира плътно режима за
разработчици, което никога не трябва да се случва на производствен
сървър.
Инструмент за отстраняване на грешки в Tracy
За да улесним дебъгването, ще включим чудесния инструмент Tracy. В режим за разработчици той визуализира грешките, а в производствен режим записва грешките в определена директория:
$configurator->enableTracy($rootDir . '/log');
Временни файлове
Nette използва кеш за DI-контейнер, RobotLoader, шаблони и др. Затова е необходимо да се зададе пътят до директорията, в която се съхранява кешът:
$configurator->setTempDirectory($rootDir . '/temp');
В Linux или macOS задайте разрешения за запис за
директориите log/
и temp/
.
RobotLoader
Обикновено искаме да заредим класовете автоматично с помощта на RobotLoader, така че трябва да го стартираме и да
му позволим да зареди класовете от директорията, в която се намира
Bootstrap.php
(т.е. __DIR__
) и всички негови поддиректории:
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Алтернативен начин е да се използва само автозадаващото устройство PSR-4 Composer.
Часова зона
Конфигураторът ви позволява да зададете часовата зона за вашето приложение.
$configurator->setTimeZone('Europe/Prague');
Конфигурация на DI-контейнер
Част от процеса на изтегляне е създаването на контейнера DI, т.е. фабриката за обекти, която е сърцето на цялото приложение. Всъщност това е клас на PHP, създаден от Nette и съхраняван в директория за кеш. Фабриката създава ключовите обекти на приложението, а конфигурационните файлове я инструктират как да ги създава и конфигурира, като по този начин влияем върху поведението на цялото приложение.
Файловете за конфигурация обикновено се записват във формат NEON. Можете да прочетете какво може да се конфигурира тук.
В режим на разработка контейнерът се актуализира автоматично при всяка промяна на кода или конфигурационните файлове. В производствен режим той се генерира само веднъж и промените във файловете не се проверяват за максимална производителност.
Файловете за конфигурация се зареждат с помощта на addConfig()
:
$configurator->addConfig($rootDir . '/config/common.neon');
Методът addConfig()
може да се извика няколко пъти, за да се добавят
няколко файла.
$configurator->addConfig($rootDir . '/config/common.neon');
$configurator->addConfig($rootDir . '/config/services.neon');
if (PHP_SAPI === 'cli') {
$configurator->addConfig($rootDir . '/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 инсталира библиотеки%rootDir%
е абсолютният път до главната директория на проекта%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;
}