Bootstrap

Bootstrap is boot code that initializes the environment and creates a Dependency Injection (DI) container. Let's say:

  • how to configure your application using NEON files
  • how to handle production and development modes
  • how to create the DI container

In charge of setting up the environment and creating a Dependency Injection (DI) container in Nette is the Configurator class. It is used in user class Bootstrap located in the app/Bootstrap.php file. For example, it might look like this:

use Nette\Configurator;

class Bootstrap
{
	public static function boot(): Configurator
	{
		$configurator = new Configurator;
		$configurator->setDebugMode('23.75.345.200');
		$configurator->enableTracy(__DIR__ . '/../log');
		$configurator->setTempDirectory(__DIR__ . '/../temp');
		$configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
		$configurator->addConfig(__DIR__ . '/config/common.neon');
		return $configurator;
	}
}

Development Mode

Development mode is automatically enabled when we're running on the localhost. If you want to enable it in other cases, for example, for programmers accessing from a specific IP address, you can use setDebugMode():

$configurator->setDebugMode('23.75.345.200'); // one or more IP addresses

Even more secure is the combination of an IP address and a cookie. We will store a secret token into the nette-debug' cookie, e.g. `secret1234, and the development mode will be activated for programmers with this combination of IP and cookie.

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

We can also turn off developer mode completely:

$configurator->setDebugMode(false);

Debugging Tool Tracy

For easy debugging, we will turn on the great tool Tracy. In developer mode it visualizes errors and in production mode it logs errors to the specified directory:

$configurator->enableTracy(__DIR__ . '/../log');

Caching

Nette uses the cache for DI container, RobotLoader, templates, etc. Therefore it is necessary to set the path to the directory where the cache will be stored:

$configurator->setTempDirectory(__DIR__ . '/../temp');

RobotLoader

Usually, we will want to automatically load the classes using RobotLoader, so we have to start it up and let it load classes from the directory where Bootstrap.php is located (i.e. __DIR__) and all its subdirectories:

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

An alternative way is to only use Composer PSR-4 autoloading.

Timezone

Configurator allows you to specify a timezone for your application.

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

DI Container Configuration

Part of the boot process is the creation of a DI container, which is the heart of the entire application. It is configured primarily using configuration files that are written in the NEON format. In a separate chapter, you can read everything about configuration.

We load the configuration files using addConfig():

$configurator->addConfig(__DIR__ . '/config/common.neon');

The method addConfig() can be called multiple times to add multiple files.

$configurator->addConfig(__DIR__ . '/config/common.neon');
$configurator->addConfig(__DIR__ . '/config/local.neon');
if (PHP_SAPI === 'cli') {
	$configurator->addConfig(__DIR__ . '/config/cli.neon');
}

Alternatively, we can use the includes section to load more configuration files.

includes:
	- parameters.php
	- services.neon
	- presenters.neon

If items with the same keys appear within configuration files, they will be overwritten or merged in the case of arrays. Each subsequent file has a higher priority in merging. The file containing the includes section has a higher priority than the included files.

Static Parameters

Parameters can be passed to the DI container by the addParameters() method; their values must be known at compile time. The container is always generated for the different values of these parameters.

$configurator->addParameters([
	'foo' => 'bar',
	'baz' => 123,
]);

In configuration files, we can write %foo% to access the parameter named foo. By default, the Configurator populates the following parameters: appDir, wwwDir, tempDir, debugMode and consoleMode.

Dynamic Parameters

We can also feed dynamic parameters to the DI container. Their values needn't be known at compile time: they are used at run time. Different values don't regenerate the container.

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

Environment variables could be easily made available using dynamic parameters. We can access them via %env.variable% in configuration files.

$configurator->addDynamicParameters([
	'env' => $_ENV,
]);

External Services

We can insert an instance of a class into the DI container directly before the DI container creates it for us. The service must be defined with the imported: true attribute.

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

Create a new instance and insert it in bootstrap:

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

Creating a Container and index.php

The method createContainer() generates the container class and returns its instance:

$container = $configurator->createContainer();

In the development mode, the container is automatically updated each time you change the code or configuration files. In production mode, it is generated only once and file changes are not checked to avoid compromising performance.

If we are creating a web application, all requests are handled by one file located in the public www/ directory, and that is index.php. It lets the Bootstrap class to return $configurator which creates DI container. He gets the $configurator from the Bootstrap and then creates a DI container. It then obtains a service from it that runs the web application:

$configurator = App\Bootstrap::boot();
$container = $configurator->createContainer();
$application = $container->getByType(Nette\Application\Application::class);
$application->run();