Nette Documentation Preview

syntax
Bootstrap
*********

<div class=perex>

Bootstrap - це завантажувальний код, який ініціалізує середовище, створює контейнер впровадження залежностей (DI) і запускає додаток. Ми обговоримо:

- як налаштувати застосунок за допомогою файлів NEON
- як працювати з режимами виробництва та розробки
- як створити контейнер DI

</div>


Додатки, чи то веб-додатки, чи то скрипти командного рядка, починаються з ініціалізації середовища в тій чи іншій формі. У стародавні часи за це міг відповідати файл з ім'ям, наприклад, `include.inc.php`, який включався у вихідний файл.
У сучасних додатках Nette він замінений класом `Bootstrap`, який як частина додатка знаходиться у файлі `app/Bootstrap.php`. Це може виглядати, наприклад, так:

```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 .[#toc-index-php]
===========================

У випадку веб-додатків початковим файлом є `index.php`, який знаходиться у загальнодоступному каталозі `www/`. Він дозволяє класу `Bootstrap` ініціалізувати середовище і повертає `$configurator`, який створює контейнер DI. Потім він отримує сервіс `Application`, який запускає веб-додаток:

```php
// ініціалізуємо середовище + отримуємо об'єкт Configurator
$configurator = App\Bootstrap::boot();
// створюємо DI-контейнер
$container = $configurator->createContainer();
// DI-контейнер створює об'єкт Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// запускаємо додаток Nette
$application->run();
```

Як ви бачите, клас [api:Nette\Bootstrap\Configurator], який ми зараз представимо детальніше, допомагає в налаштуванні середовища та створенні контейнера впровадження залежностей (DI).


Режим розробки та режим виробництва .[#toc-development-vs-production-mode]
==========================================================================

Nette розрізняє два основні режими, в яких виконується запит: розробка і виробництво. Режим розробки орієнтований на максимальну зручність програміста, відображається Tracy, кеш автоматично оновлюється у разі зміни шаблонів або конфігурації DI контейнера тощо. Режим виробництва орієнтований на продуктивність, Tracy тільки реєструє помилки, а зміни шаблонів та інших файлів не перевіряються.

Вибір режиму здійснюється шляхом автовизначення, тому зазвичай немає необхідності налаштовувати або перемикати що-небудь вручну. Режим розробки використовується, якщо застосунок запущено на localhost (тобто IP-адресу `127.0.0.1` або `::1`) і відсутній проксі-сервер (тобто його HTTP-заголовок). В іншому разі застосунок працює у виробничому режимі.

Якщо ви хочете ввімкнути режим розробки в інших випадках, наприклад, для програмістів, які отримують доступ з певної IP-адреси, ви можете використовувати `setDebugMode()`:

```php
$configurator->setDebugMode('23.75.345.200'); // одна або більше IP-адрес
```

Ми безумовно рекомендуємо поєднувати IP-адресу з файлом cookie. Ми зберігатимемо секретний токен у cookie `nette-debug', например, `secret1234`, і режим розробки буде активовано для програмістів із такою комбінацією IP і cookie.

```php
$configurator->setDebugMode('secret1234@23.75.345.200');
```

Можна повністю вимкнути режим розробника, навіть для localhost:

```php
$configurator->setDebugMode(false);
```

Зверніть увагу, що значення `true` жорстко вмикає режим розробника, чого ніколи не повинно відбуватися на робочому сервері.


Налагоджувальний інструмент Tracy .[#toc-debugging-tool-tracy]
==============================================================

Для полегшення налагодження ми увімкнемо чудовий інструмент [Tracy |tracy:]. У режимі розробника він візуалізує помилки, а в режимі виробництва - записує помилки в зазначений каталог:

```php
$configurator->enableTracy($appDir . '/log');
```


Тимчасові файли .[#toc-temporary-files]
=======================================

Nette використовує кеш для DI-контейнера, RobotLoader, шаблонів тощо. Тому необхідно задати шлях до директорії, де зберігатиметься кеш:

```php
$configurator->setTempDirectory($appDir . '/temp');
```

У Linux або macOS встановіть [права на запис |nette:troubleshooting#Setting-Directory-Permissions] для каталогів `log/` і `temp/`.


RobotLoader .[#toc-robotloader]
===============================

Зазвичай ми хочемо автоматично завантажувати класи за допомогою [RobotLoader |robot-loader:], тому ми повинні запустити його і дозволити йому завантажити класи з каталогу, в якому знаходиться `Bootstrap.php` (тобто `__DIR__`) і всі його підкаталоги:

```php
$configurator->createRobotLoader()
	->addDirectory(__DIR__)
	->register();
```

Альтернативний спосіб - використовувати лише автозавантаження PSR-4 [Composer |best-practices:composer].


Часовий пояс .[#toc-timezone]
=============================

Configurator дає змогу вказати часовий пояс для вашого застосунку.

```php
$configurator->setTimeZone('Europe/Prague');
```


Конфігурація DI-контейнера .[#toc-di-container-configuration]
=============================================================

Частиною процесу завантаження є створення DI-контейнера, тобто фабрики об'єктів, яка є серцем усього додатка. Насправді це PHP-клас, створений Nette, який зберігається в каталозі кешу. Фабрика створює ключові об'єкти застосунку, а конфігураційні файли інструктують її, як їх створювати та налаштовувати, і таким чином ми впливаємо на поведінку всього застосунку.

Файли конфігурації зазвичай записуються у форматі [NEON |neon:format]. Ви можете прочитати [що можна налаштувати тут |nette:configuring].

.[tip]
У режимі розробки контейнер автоматично оновлюється щоразу, коли ви змінюєте код або конфігураційні файли. У виробничому режимі він генерується лише один раз, а зміни файлів не перевіряються для досягнення максимальної продуктивності.

Файли конфігурації завантажуються за допомогою `addConfig()`:

```php
$configurator->addConfig($appDir . '/config/common.neon');
```

Метод `addConfig()` може бути викликаний кілька разів для додавання декількох файлів.

```php
$configurator->addConfig($appDir . '/config/common.neon');
$configurator->addConfig($appDir . '/config/services.neon');
if (PHP_SAPI === 'cli') {
	$configurator->addConfig($appDir . '/config/cli.php');
}
```

Підключення `cli.php` не є друкарською помилкою, конфігурацію також можна записати в PHP-файлі, який повертає її у вигляді масиву.

Альтернативно, ми можемо використовувати [секцію `includes` |dependency-injection:configuration#Including-Files] для завантаження конфігураційних файлів.

Якщо елементи з однаковими ключами відображаються у файлах конфігурації, вони будуть [перезаписані або об'єднані |dependency-injection:configuration#Merging] у випадку масивів. Пізніше включений файл має вищий пріоритет, ніж попередні. Файл, зазначений у секції `includes`, має вищий пріоритет, ніж файли, включені в нього.


Статичні параметри .[#toc-static-parameters]
--------------------------------------------

Параметри, що використовуються у файлах конфігурації, можуть бути визначені [в секції `parameters` |dependency-injection:configuration#parameters] і підхоплені (або перезаписані) методом `addStaticParameters()` (у нього є аліас `addParameters()`). Важливо, що різні значення параметрів викликають генерацію додаткових DI-контейнерів, тобто додаткових класів.

```php
$configurator->addStaticParameters([
	'projectId' => 23,
]);
```

У конфігураційних файлах ми можемо записати звичайну нотацію `%projectId%` для доступу до параметра з ім'ям `projectId`.


Динамічні параметри .[#toc-dynamic-parameters]
----------------------------------------------

Можна також додати динамічні параметри в контейнер. Їхні різні значення, на відміну від статичних параметрів, не призведуть до генерації нових DI-контейнерів.

```php
$configurator->addDynamicParameters([
	'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```

Змінні середовища можуть бути легко доступні з використанням динамічних параметрів. Ми можемо отримати доступ до них через `%env.variable%` у файлах конфігурації.

```php
$configurator->addDynamicParameters([
	'env' => getenv(),
]);
```


Параметри за замовчуванням .[#toc-default-parameters]
-----------------------------------------------------

Ви можете використовувати наступні статичні параметри у файлах конфігурації:

- `%appDir%` - абсолютний шлях до каталогу з файлом `Bootstrap.php`
- `%wwwDir%` - абсолютний шлях до каталогу, в якому знаходиться файл запису `index.php`
- `%tempDir%` - абсолютний шлях до каталогу для тимчасових файлів
- `%vendorDir%` - абсолютний шлях до каталогу, куди Composer встановлює бібліотеки
- `%rootDir%` - абсолютний шлях до кореневого каталогу проекту
- `%debugMode%` вказує на те, чи перебуває програма у режимі налагодження
- `%consoleMode%` вказує на те, що запит надійшов через командний рядок


Імпортовані сервіси .[#toc-imported-services]
---------------------------------------------

Заглибимося далі. Хоча мета DI-контейнера у створенні об'єктів, може виникнути необхідність вставити наявний об'єкт у контейнер. Це робиться визначенням сервісу з атрибутом `imported: true`:

```neon
services:
	myservice:
		type: App\Model\MyCustomService
		imported: true
```

Створюємо новий екземпляр і вставляємо його в Bootstrap:

```php
$configurator->addServices([
	'myservice' => new App\Model\MyCustomService('foobar'),
]);
```


Різні середовища .[#toc-different-environments]
===============================================

Не соромтеся налаштувати клас `Bootstrap` відповідно до ваших потреб. Ви можете додавати параметри до методу `boot()` для розділення веб-проєктів, або додавати інші методи, як-от `bootForTests()`, які ініціалізують середовище для модульних тестів, `bootForCli()` для скриптів, що викликаються з командного рядка, і так далі.

```php
public static function bootForTests(): Configurator
{
	$configurator = self::boot();
	Tester\Environment::setup(); // Инициализация Nette Tester
	return $configurator;
}
```

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/services.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 встановлює бібліотеки
  • %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;
}