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
{
	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`, которая запускает веб-приложение:

```php
$bootstrap = new App\Bootstrap;
// Инициализация среды + создание DI-контейнера
$container = $bootstrap->bootWebApplication();
// 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
$this->configurator->setDebugMode('23.75.345.200'); // один или более IP-адресов
```

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

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

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

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

Обратите внимание, что значение `true` жестко включает режим разработчика, чего никогда не должно происходить на рабочем сервере.


Отладочный инструмент Tracy .[#toc-debugging-tool-tracy]
========================================================

Для облегчения отладки мы включим замечательный инструмент [Tracy |tracy:]. В режиме разработчика он визуализирует ошибки, а в режиме производства — записывает ошибки в указанный каталог:

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


Временные файлы .[#toc-temporary-files]
=======================================

Nette использует кэш для DI-контейнера, RobotLoader, шаблонов и т. д. Поэтому необходимо задать путь к директории, где будет храниться кэш:

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

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


RobotLoader
===========

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

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

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


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

Configurator позволяет указать часовой пояс для вашего приложения.

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


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

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

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

.[tip]
В режиме разработки контейнер автоматически обновляется каждый раз, когда вы изменяете код или конфигурационные файлы. В производственном режиме он генерируется только один раз, а изменения файлов не проверяются для достижения максимальной производительности.

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

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

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

```php
$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`|dependency-injection:configuration#Including-Files] для загрузки конфигурационных файлов.

Если элементы с одинаковыми ключами отображаются в файлах конфигурации, они будут [перезаписаны или объединены |dependency-injection:configuration#Merging] в случае массивов. Позже включенный файл имеет более высокий приоритет, чем предыдущие. Файл, указанный в секции `includes`, имеет более высокий приоритет, чем файлы, включенные в него.


Статические параметры .[#toc-static-parameters]
-----------------------------------------------

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

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

В конфигурационных файлах мы можем написать обычную нотацию `%projectId%` для доступа к параметру с именем `projectId`.


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

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

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

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

```php
$this->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
$this->configurator->addServices([
	'myservice' => new App\Model\MyCustomService('foobar'),
]);
```


Разные среды .[#toc-different-environments]
===========================================

Не стесняйтесь настраивать класс `Bootstrap` в соответствии с вашими потребностями. Вы можете добавить параметры в метод `bootWebApplication()`, чтобы различать веб-проекты. Также можно добавить другие методы, например `bootTestEnvironment()` для инициализации окружения для модульных тестов, `bootConsoleApplication()` для скриптов, вызываемых из командной строки, и так далее.

```php
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();
}
```

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();
}