Nette Documentation Preview

syntax
Bootstrap
*********

<div class=perex>

Bootstrap é o código de inicialização que inicializa o ambiente, cria um recipiente de injeção de dependência (DI), e inicia a aplicação. Vamos discutir:

- como configurar sua aplicação utilizando arquivos NEON
- como lidar com os modos de produção e desenvolvimento
- como criar o recipiente DI

</div>


As aplicações, sejam scripts baseados na web ou em linha de comando, começam por alguma forma de inicialização do ambiente. Nos tempos antigos, podia ser um arquivo chamado, por exemplo, `include.inc.php` que estava encarregado disto, e estava incluído no arquivo inicial.
Nas aplicações Nette modernas, ele foi substituído pela classe `Bootstrap`, que como parte da aplicação pode ser encontrada no `app/Bootstrap.php`. Pode ser parecido, por exemplo, com isto:

```php
use Nette\Bootstrap\Configurator;

class Bootstrap
{
	private Configurator $configurator;
	private string $rootDir;

	public function __construct()
	{
		$this->rootDir = dirname(__DIR__);
		// O configurador é responsável pela configuração do ambiente e dos serviços do aplicativo.
		$this->configurator = new Configurator;
		// Defina o diretório para os arquivos temporários gerados pelo Nette (por exemplo, modelos compilados)
		$this->configurator->setTempDirectory($this->rootDir . '/temp');
	}

	public function bootWebApplication(): Nette\DI\Container
	{
		$this->initializeEnvironment();
		$this->setupContainer();
		return $this->configurator->createContainer();
	}

	private function initializeEnvironment(): void
	{
		// O Nette é inteligente e o modo de desenvolvimento é ativado automaticamente,
		// ou você pode ativá-lo para um endereço IP específico, descomentando a seguinte linha:
		// $this->configurator->setDebugMode('secret@23.75.345.200');

		// Habilita o Tracy: a melhor ferramenta de depuração do tipo "canivete suíço".
		$this->configurator->enableTracy($this->rootDir . '/log');

		// RobotLoader: carrega automaticamente todas as classes no diretório fornecido
		$this->configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
	}

	private function setupContainer(): void
	{
		// Carregar arquivos de configuração
		$this->configurator->addConfig($this->rootDir . '/config/common.neon');
	}
}
```


index.php .[#toc-index-php]
===========================

O arquivo inicial para aplicativos Web é `index.php`, localizado no diretório público `www/`. Ele usa a classe `Bootstrap` para inicializar o ambiente e criar um contêiner DI. Em seguida, ele obtém o serviço `Application` do contêiner, que inicia o aplicativo Web:

```php
$bootstrap = new App\Bootstrap;
// Inicializar o ambiente + criar um contêiner DI
$container = $bootstrap->bootWebApplication();
// O contêiner DI cria um objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Iniciar o aplicativo Nette e tratar a solicitação de entrada
$application->run();
```

Como você pode ver, a classe [api:Nette\Bootstrap\Configurator], que agora vamos apresentar mais detalhadamente, ajuda a configurar o ambiente e criar um recipiente de injeção de dependência (DI).


Desenvolvimento vs Modo de Produção .[#toc-development-vs-production-mode]
==========================================================================

Nette distingue dois modos básicos nos quais uma solicitação é executada: desenvolvimento e produção. O modo de desenvolvimento é focado no máximo conforto do programador, Tracy é exibido, o cache é atualizado automaticamente ao alterar os modelos ou a configuração do container DI, etc. O modo de produção é focado no desempenho, Tracy apenas registra erros e mudanças de gabaritos e outros arquivos não são verificados.

A seleção do modo é feita por autodetecção, de modo que normalmente não há necessidade de configurar ou trocar nada manualmente. O modo é desenvolvimento se a aplicação estiver rodando no localhost (ou seja, endereço IP `127.0.0.1` ou `::1`) e nenhum proxy estiver presente (ou seja, seu cabeçalho HTTP). Caso contrário, ele é executado em modo de produção.

Se você quiser ativar o modo de desenvolvimento em outros casos, por exemplo, para programadores que acessam de um endereço IP específico, você pode usar `setDebugMode()`:

```php
$this->configurator->setDebugMode('23.75.345.200'); // um ou mais endereços IP
```

Definitivamente, recomendamos combinar um endereço IP com um cookie. Armazenaremos um token secreto no cookie `nette-debug`, por exemplo `secret1234`, e o modo de desenvolvimento será ativado para programadores com esta combinação de IP e cookie.

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

Também podemos desligar completamente o modo desenvolvedor, mesmo para o localhost:

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

Note que o valor `true` liga o modo desenvolvedor por hard, o que nunca deveria acontecer em um servidor de produção.


Ferramenta de depuração Tracy .[#toc-debugging-tool-tracy]
==========================================================

Para facilitar a depuração, vamos acionar a grande ferramenta [Tracy |tracy:]. No modo desenvolvedor ela visualiza os erros e no modo de produção registra os erros no diretório especificado:

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


Arquivos temporários .[#toc-temporary-files]
============================================

Nette utiliza o cache para contêiner DI, RobotLoader, modelos, etc. Portanto, é necessário definir o caminho para o diretório onde o cache será armazenado:

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

No Linux ou macOS, defina as [permissões de escrita |nette:troubleshooting#Setting directory permissions] para os diretórios `log/` e `temp/`.


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

Normalmente, queremos carregar automaticamente as classes usando [o RobotLoader |robot-loader:], então temos que iniciá-lo e deixá-lo carregar classes do diretório onde se encontra `Bootstrap.php` (ou seja, `__DIR__`) e todos os seus subdiretórios:

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

Uma maneira alternativa é usar apenas o [Composer |best-practices:composer] PSR-4 auto-carregamento.


Fuso horário .[#toc-timezone]
=============================

O Configurador permite que você especifique um fuso horário para sua aplicação.

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


Configuração de contêineres DI .[#toc-di-container-configuration]
=================================================================

Parte do processo de inicialização é a criação de um container DI, ou seja, uma fábrica para objetos, que é o coração de toda a aplicação. Na verdade, é uma classe PHP gerada pela Nette e armazenada em um diretório cache. A fábrica produz objetos chave da aplicação e arquivos de configuração instruem-no como criá-los e configurá-los, e assim influenciamos o comportamento de toda a aplicação.

Os arquivos de configuração são geralmente escritos no [formato NEON |neon:format]. Você pode ler [o que pode ser configurado aqui |nette:configuring].

.[tip]
No modo de desenvolvimento, o recipiente é atualizado automaticamente cada vez que você altera o código ou os arquivos de configuração. No modo de produção, ele é gerado apenas uma vez e as mudanças de arquivo não são verificadas para maximizar o desempenho.

Os arquivos de configuração são carregados usando `addConfig()`:

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

O método `addConfig()` pode ser chamado várias vezes para adicionar vários arquivos.

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

O nome `cli.php` não é um erro de digitação, a configuração também pode ser escrita em um arquivo PHP, que a devolve como um array.

Alternativamente, podemos usar a [seção`includes`  |dependency-injection:configuration#including files] para carregar mais arquivos de configuração.

Se itens com as mesmas chaves aparecerem dentro dos arquivos de configuração, eles serão [sobrescritos ou fundidos |dependency-injection:configuration#Merging] no caso de arrays. O arquivo incluído posteriormente tem uma prioridade mais alta do que o anterior. O arquivo no qual a seção `includes` é listada tem uma prioridade mais alta do que os arquivos incluídos nela.


Parâmetros estáticos .[#toc-static-parameters]
----------------------------------------------

Os parâmetros usados nos arquivos de configuração podem ser definidos [na seção `parameters` |dependency-injection:configuration#parameters] e também passados (ou sobrescritos) pelo método `addStaticParameters()` (tem o pseudônimo `addParameters()`). É importante que diferentes valores de parâmetros causem a geração de recipientes DI adicionais, ou seja, classes adicionais.

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

Nos arquivos de configuração, podemos escrever a notação usual `%projectId%` para acessar o parâmetro `projectId`.


Parâmetros dinâmicos .[#toc-dynamic-parameters]
-----------------------------------------------

Também podemos adicionar parâmetros dinâmicos ao recipiente, seus diferentes valores, ao contrário dos parâmetros estáticos, não causarão a geração de novos recipientes DI.

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

As variáveis ambientais poderiam ser facilmente disponibilizadas usando parâmetros dinâmicos. Podemos acessá-las via `%env.variable%` em arquivos de configuração.

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


Parâmetros padrão .[#toc-default-parameters]
--------------------------------------------

Você pode usar os seguintes parâmetros estáticos nos arquivos de configuração:

- `%appDir%` é o caminho absoluto para o diretório do arquivo `Bootstrap.php`
- `%wwwDir%` é o caminho absoluto para o diretório que contém o arquivo de entrada `index.php`
- `%tempDir%` é o caminho absoluto para o diretório de arquivos temporários
- `%vendorDir%` é o caminho absoluto para o diretório onde o Composer instala as bibliotecas
- `%rootDir%` é o caminho absoluto para o diretório raiz do projeto
- `%debugMode%` indica se a aplicação está em modo de depuração
- `%consoleMode%` indica se o pedido veio através da linha de comando


Serviços Importados .[#toc-imported-services]
---------------------------------------------

Estamos indo mais fundo agora. Embora o propósito de um recipiente DI seja criar objetos, excepcionalmente pode haver a necessidade de inserir um objeto existente no recipiente. Fazemos isso definindo o serviço com o atributo `imported: true`.

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

Criar uma nova instância e inseri-la no bootstrap:

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


Diferentes Ambientes .[#toc-different-environments]
===================================================

Não hesite em personalizar a classe `Bootstrap` de acordo com suas necessidades. Você pode adicionar parâmetros ao método `bootWebApplication()` para diferenciar os projetos da Web. Como alternativa, você pode adicionar outros métodos, como `bootTestEnvironment()` para inicializar o ambiente para testes de unidade, `bootConsoleApplication()` para scripts chamados pela linha de comando e assim por diante.

```php
public function bootTestEnvironment(): Nette\DI\Container
{
	Tester\Environment::setup(); // Inicialização do 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 é o código de inicialização que inicializa o ambiente, cria um recipiente de injeção de dependência (DI), e inicia a aplicação. Vamos discutir:

  • como configurar sua aplicação utilizando arquivos NEON
  • como lidar com os modos de produção e desenvolvimento
  • como criar o recipiente DI

As aplicações, sejam scripts baseados na web ou em linha de comando, começam por alguma forma de inicialização do ambiente. Nos tempos antigos, podia ser um arquivo chamado, por exemplo, include.inc.php que estava encarregado disto, e estava incluído no arquivo inicial. Nas aplicações Nette modernas, ele foi substituído pela classe Bootstrap, que como parte da aplicação pode ser encontrada no app/Bootstrap.php. Pode ser parecido, por exemplo, com isto:

use Nette\Bootstrap\Configurator;

class Bootstrap
{
	private Configurator $configurator;
	private string $rootDir;

	public function __construct()
	{
		$this->rootDir = dirname(__DIR__);
		// O configurador é responsável pela configuração do ambiente e dos serviços do aplicativo.
		$this->configurator = new Configurator;
		// Defina o diretório para os arquivos temporários gerados pelo Nette (por exemplo, modelos compilados)
		$this->configurator->setTempDirectory($this->rootDir . '/temp');
	}

	public function bootWebApplication(): Nette\DI\Container
	{
		$this->initializeEnvironment();
		$this->setupContainer();
		return $this->configurator->createContainer();
	}

	private function initializeEnvironment(): void
	{
		// O Nette é inteligente e o modo de desenvolvimento é ativado automaticamente,
		// ou você pode ativá-lo para um endereço IP específico, descomentando a seguinte linha:
		// $this->configurator->setDebugMode('secret@23.75.345.200');

		// Habilita o Tracy: a melhor ferramenta de depuração do tipo "canivete suíço".
		$this->configurator->enableTracy($this->rootDir . '/log');

		// RobotLoader: carrega automaticamente todas as classes no diretório fornecido
		$this->configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
	}

	private function setupContainer(): void
	{
		// Carregar arquivos de configuração
		$this->configurator->addConfig($this->rootDir . '/config/common.neon');
	}
}

index.php

O arquivo inicial para aplicativos Web é index.php, localizado no diretório público www/. Ele usa a classe Bootstrap para inicializar o ambiente e criar um contêiner DI. Em seguida, ele obtém o serviço Application do contêiner, que inicia o aplicativo Web:

$bootstrap = new App\Bootstrap;
// Inicializar o ambiente + criar um contêiner DI
$container = $bootstrap->bootWebApplication();
// O contêiner DI cria um objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Iniciar o aplicativo Nette e tratar a solicitação de entrada
$application->run();

Como você pode ver, a classe Nette\Bootstrap\Configurator, que agora vamos apresentar mais detalhadamente, ajuda a configurar o ambiente e criar um recipiente de injeção de dependência (DI).

Desenvolvimento vs Modo de Produção

Nette distingue dois modos básicos nos quais uma solicitação é executada: desenvolvimento e produção. O modo de desenvolvimento é focado no máximo conforto do programador, Tracy é exibido, o cache é atualizado automaticamente ao alterar os modelos ou a configuração do container DI, etc. O modo de produção é focado no desempenho, Tracy apenas registra erros e mudanças de gabaritos e outros arquivos não são verificados.

A seleção do modo é feita por autodetecção, de modo que normalmente não há necessidade de configurar ou trocar nada manualmente. O modo é desenvolvimento se a aplicação estiver rodando no localhost (ou seja, endereço IP 127.0.0.1 ou ::1) e nenhum proxy estiver presente (ou seja, seu cabeçalho HTTP). Caso contrário, ele é executado em modo de produção.

Se você quiser ativar o modo de desenvolvimento em outros casos, por exemplo, para programadores que acessam de um endereço IP específico, você pode usar setDebugMode():

$this->configurator->setDebugMode('23.75.345.200'); // um ou mais endereços IP

Definitivamente, recomendamos combinar um endereço IP com um cookie. Armazenaremos um token secreto no cookie nette-debug, por exemplo secret1234, e o modo de desenvolvimento será ativado para programadores com esta combinação de IP e cookie.

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

Também podemos desligar completamente o modo desenvolvedor, mesmo para o localhost:

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

Note que o valor true liga o modo desenvolvedor por hard, o que nunca deveria acontecer em um servidor de produção.

Ferramenta de depuração Tracy

Para facilitar a depuração, vamos acionar a grande ferramenta Tracy. No modo desenvolvedor ela visualiza os erros e no modo de produção registra os erros no diretório especificado:

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

Arquivos temporários

Nette utiliza o cache para contêiner DI, RobotLoader, modelos, etc. Portanto, é necessário definir o caminho para o diretório onde o cache será armazenado:

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

No Linux ou macOS, defina as permissões de escrita para os diretórios log/ e temp/.

RobotLoader

Normalmente, queremos carregar automaticamente as classes usando o RobotLoader, então temos que iniciá-lo e deixá-lo carregar classes do diretório onde se encontra Bootstrap.php (ou seja, __DIR__) e todos os seus subdiretórios:

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

Uma maneira alternativa é usar apenas o Composer PSR-4 auto-carregamento.

Fuso horário

O Configurador permite que você especifique um fuso horário para sua aplicação.

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

Configuração de contêineres DI

Parte do processo de inicialização é a criação de um container DI, ou seja, uma fábrica para objetos, que é o coração de toda a aplicação. Na verdade, é uma classe PHP gerada pela Nette e armazenada em um diretório cache. A fábrica produz objetos chave da aplicação e arquivos de configuração instruem-no como criá-los e configurá-los, e assim influenciamos o comportamento de toda a aplicação.

Os arquivos de configuração são geralmente escritos no formato NEON. Você pode ler o que pode ser configurado aqui.

No modo de desenvolvimento, o recipiente é atualizado automaticamente cada vez que você altera o código ou os arquivos de configuração. No modo de produção, ele é gerado apenas uma vez e as mudanças de arquivo não são verificadas para maximizar o desempenho.

Os arquivos de configuração são carregados usando addConfig():

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

O método addConfig() pode ser chamado várias vezes para adicionar vários arquivos.

$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');
}

O nome cli.php não é um erro de digitação, a configuração também pode ser escrita em um arquivo PHP, que a devolve como um array.

Alternativamente, podemos usar a seçãoincludes para carregar mais arquivos de configuração.

Se itens com as mesmas chaves aparecerem dentro dos arquivos de configuração, eles serão sobrescritos ou fundidos no caso de arrays. O arquivo incluído posteriormente tem uma prioridade mais alta do que o anterior. O arquivo no qual a seção includes é listada tem uma prioridade mais alta do que os arquivos incluídos nela.

Parâmetros estáticos

Os parâmetros usados nos arquivos de configuração podem ser definidos na seção parameters e também passados (ou sobrescritos) pelo método addStaticParameters() (tem o pseudônimo addParameters()). É importante que diferentes valores de parâmetros causem a geração de recipientes DI adicionais, ou seja, classes adicionais.

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

Nos arquivos de configuração, podemos escrever a notação usual %projectId% para acessar o parâmetro projectId.

Parâmetros dinâmicos

Também podemos adicionar parâmetros dinâmicos ao recipiente, seus diferentes valores, ao contrário dos parâmetros estáticos, não causarão a geração de novos recipientes DI.

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

As variáveis ambientais poderiam ser facilmente disponibilizadas usando parâmetros dinâmicos. Podemos acessá-las via %env.variable% em arquivos de configuração.

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

Parâmetros padrão

Você pode usar os seguintes parâmetros estáticos nos arquivos de configuração:

  • %appDir% é o caminho absoluto para o diretório do arquivo Bootstrap.php
  • %wwwDir% é o caminho absoluto para o diretório que contém o arquivo de entrada index.php
  • %tempDir% é o caminho absoluto para o diretório de arquivos temporários
  • %vendorDir% é o caminho absoluto para o diretório onde o Composer instala as bibliotecas
  • %rootDir% é o caminho absoluto para o diretório raiz do projeto
  • %debugMode% indica se a aplicação está em modo de depuração
  • %consoleMode% indica se o pedido veio através da linha de comando

Serviços Importados

Estamos indo mais fundo agora. Embora o propósito de um recipiente DI seja criar objetos, excepcionalmente pode haver a necessidade de inserir um objeto existente no recipiente. Fazemos isso definindo o serviço com o atributo imported: true.

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

Criar uma nova instância e inseri-la no bootstrap:

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

Diferentes Ambientes

Não hesite em personalizar a classe Bootstrap de acordo com suas necessidades. Você pode adicionar parâmetros ao método bootWebApplication() para diferenciar os projetos da Web. Como alternativa, você pode adicionar outros métodos, como bootTestEnvironment() para inicializar o ambiente para testes de unidade, bootConsoleApplication() para scripts chamados pela linha de comando e assim por diante.

public function bootTestEnvironment(): Nette\DI\Container
{
	Tester\Environment::setup(); // Inicialização do 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();
}