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

O Nette se comporta de forma diferente, dependendo se está sendo executado em um servidor de desenvolvimento ou de produção:

🛠️ Development Mode (Modo de desenvolvimento)
Exibe a barra de depuração Tracy com informações úteis (por exemplo, consultas SQL, tempo de execução, uso de memória).
Mostra uma página de erro detalhada com rastros de chamadas de função e conteúdo de variáveis quando ocorre um erro.
Atualiza automaticamente o cache quando modelos Latte, arquivos de configuração etc. são modificados.
Modo de produção
Não exibe nenhuma informação de depuração; todos os erros são registrados.
Mostra um ErrorPresenter ou uma página genérica de “Erro do servidor” quando ocorre um erro.
O cache nunca é atualizado automaticamente!
Otimizado para velocidade e segurança.

O modo é determinado automaticamente, portanto, na maioria dos casos, não há necessidade de configurá-lo ou alterná-lo manualmente:

  • Modo de desenvolvimento: Ativo no localhost (endereço IP 127.0.0.1 ou ::1), a menos que um proxy esteja em uso (ou seja, com base em seus cabeçalhos HTTP).
  • Modo de produção: Ativo em todos os outros lugares.

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();
}
versão: 4.0