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
=========

В случае веб-приложений начальным файлом является `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
===========

Обычно мы хотим автоматически загружать классы с помощью [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 устанавливает библиотеки.
- `%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 устанавливает библиотеки.
  • %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;
}