Bootstrap
Bootstrap é o código de inicialização que inicializa o ambiente, cria o contêiner de injeção de dependência (DI) e inicia a aplicação. Vamos discutir:
- como é configurado usando arquivos NEON
- como distinguir entre modo de produção e desenvolvimento
- como criar um contêiner de DI
Aplicações, sejam elas web ou scripts executados a partir da linha de comando, começam sua execução com alguma forma de
inicialização do ambiente. Antigamente, isso era responsabilidade de um arquivo chamado, por exemplo,
include.inc.php
, que o arquivo inicial incluía. Em aplicações Nette modernas, ele foi substituído pela classe
Bootstrap
, que, como parte da aplicação, pode ser encontrada no arquivo app/Bootstrap.php
. Pode
parecer, por exemplo, assim:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// O Configurator é responsável por configurar o ambiente da aplicação e os serviços.
$this->configurator = new Configurator;
// Define o diretório para arquivos temporários gerados pelo Nette (por exemplo, templates 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 habilitá-lo para um endereço IP específico descomentando a linha seguinte:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Ativa o Tracy: o "canivete suíço" definitivo para depuração.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: carrega automaticamente todas as classes no diretório selecionado
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Carrega os arquivos de configuração
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
O arquivo inicial no caso de aplicações web é index.php
, localizado no diretório público www/
.
Ele solicita à classe Bootstrap que inicialize o ambiente e crie o contêiner de DI. Em seguida, obtém o serviço
Application
dele, que inicia a aplicação web:
$bootstrap = new App\Bootstrap;
// Inicialização do ambiente + criação do contêiner de DI
$container = $bootstrap->bootWebApplication();
// O contêiner de DI cria o objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Inicia a aplicação Nette e processa a requisição recebida
$application->run();
Como pode ser visto, a classe Nette\Bootstrap\Configurator ajuda na configuração do ambiente e na criação do contêiner de injeção de dependência (DI), que agora apresentaremos em mais detalhes.
Modo de desenvolvimento vs produção
O Nette se comporta de maneira diferente dependendo se está sendo executado em um servidor de desenvolvimento ou de produção:
- 🛠️ Modo de desenvolvimento (Development)
- Exibe a barra de depuração do Tracy com informações úteis (consultas SQL, tempo de execução, memória usada)
- Em caso de erro, exibe uma página de erro detalhada com a pilha de chamadas de funções e o conteúdo das variáveis
- Atualiza automaticamente o cache quando os templates Latte são alterados, os arquivos de configuração são modificados, etc.
- 🚀 Modo de produção (Production)
- Não exibe nenhuma informação de depuração, todos os erros são registrados no log
- Em caso de erro, exibe o ErrorPresenter ou uma página genérica “Server Error”
- O cache nunca é atualizado automaticamente!
- Otimizado para velocidade e segurança
A seleção do modo é feita por autodeteção, portanto, geralmente não é necessário configurar nada ou alternar manualmente:
- modo de desenvolvimento: em localhost (endereço IP
127.0.0.1
ou::1
) se não houver proxy presente (ou seja, seu cabeçalho HTTP) - modo de produção: em todos os outros lugares
Se quisermos habilitar o modo de desenvolvimento em outros casos, por exemplo, para programadores acessando de um endereço IP
específico, usamos setDebugMode()
:
$this->configurator->setDebugMode('23.75.345.200'); // também pode ser fornecido um array de endereços IP
Recomendamos fortemente combinar o endereço IP com um cookie. Armazenamos um token secreto no cookie
nette-debug
, por exemplo, secret1234
, e desta forma ativamos o modo de desenvolvimento para
programadores acessando de um endereço IP específico e que também possuem o token mencionado no cookie:
$this->configurator->setDebugMode('secret1234@23.75.345.200');
Também podemos desativar completamente o modo de desenvolvimento, mesmo para localhost:
$this->configurator->setDebugMode(false);
Atenção, o valor true
ativa o modo de desenvolvimento permanentemente, o que nunca deve acontecer em um
servidor de produção.
Ferramenta de depuração Tracy
Para facilitar a depuração, ativamos também a excelente ferramenta Tracy. No modo de desenvolvimento, 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
O Nette utiliza cache para o contêiner de DI, RobotLoader, templates, 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
Geralmente, queremos carregar classes automaticamente usando o RobotLoader, então precisamos iniciá-lo e deixá-lo carregar classes do
diretório onde Bootstrap.php
está localizado (ou seja, __DIR__
), e de todos os subdiretórios:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Uma abordagem alternativa é deixar as classes serem carregadas apenas através do Composer seguindo o PSR-4.
Fuso horário
Através do configurator, você pode definir o fuso horário padrão.
$this->configurator->setTimeZone('Europe/Lisbon');
Configuração do contêiner de DI
Parte do processo de inicialização é a criação do contêiner de DI, ou seja, a fábrica de objetos, que é o coração de toda a aplicação. Na verdade, é uma classe PHP gerada pelo Nette e armazenada no diretório de cache. A fábrica produz os objetos chave da aplicação e, por meio de arquivos de configuração, a instruímos sobre como criá-los e configurá-los, influenciando assim o comportamento de toda a aplicação.
Os arquivos de configuração são geralmente escritos no formato NEON. Em um capítulo separado, você aprenderá o que pode ser configurado.
No modo de desenvolvimento, o contêiner é atualizado automaticamente a cada alteração no código ou nos arquivos de configuração. No modo de produção, ele é gerado apenas uma vez e as alterações não são verificadas para maximizar o desempenho.
Carregamos os arquivos de configuração usando addConfig()
:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Se quisermos adicionar mais arquivos de configuração, podemos chamar a função addConfig()
várias vezes.
$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
retorna como um array.
Também podemos adicionar outros arquivos de configuração na seção includes
.
Se elementos com as mesmas chaves aparecerem nos arquivos de configuração, eles serão sobrescritos ou, no caso de arrays, mesclados. O arquivo incluído
posteriormente tem prioridade maior que o anterior. O arquivo em que a seção includes
é listada tem prioridade
maior do que os arquivos incluídos nele.
Parâmetros estáticos
Parâmetros usados nos arquivos de configuração podem ser definidos na seção parameters
e também
podem ser passados (ou sobrescritos) pelo método addStaticParameters()
(tem o alias addParameters()
).
É importante que diferentes valores de parâmetros causem a geração de contêineres de DI adicionais, ou seja, classes
adicionais.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
O parâmetro projectId
pode ser referenciado na configuração usando a notação usual
%projectId%
.
Parâmetros dinâmicos
Também podemos adicionar parâmetros dinâmicos ao contêiner, cujos diferentes valores, ao contrário dos parâmetros estáticos, não causam a geração de novos contêineres de DI.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Assim, podemos adicionar facilmente, por exemplo, variáveis de ambiente, que podem ser referenciadas na configuração usando
a notação %env.variable%
.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Parâmetros padrão
Nos arquivos de configuração, você pode usar estes parâmetros estáticos:
%appDir%
é o caminho absoluto para o diretório com o arquivoBootstrap.php
%wwwDir%
é o caminho absoluto para o diretório com o arquivo de entradaindex.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 a requisição veio da linha de comando
Serviços importados
Agora estamos indo mais a fundo. Embora o propósito do contêiner de DI seja criar objetos, excepcionalmente pode surgir a
necessidade de inserir um objeto existente no contêiner. Fazemos isso definindo o serviço com o sinalizador
imported: true
.
services:
myservice:
type: App\Model\MyCustomService
imported: true
E no bootstrap, inserimos o objeto no contêiner:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Ambiente diferente
Não hesite em modificar a classe Bootstrap de acordo com suas necessidades. Você pode adicionar parâmetros ao método
bootWebApplication()
para distinguir projetos web. Ou podemos adicionar outros métodos, como
bootTestEnvironment()
, que inicializa o ambiente para testes unitários, bootConsoleApplication()
para
scripts chamados da linha de comando, etc.
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();
}