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 arquivoBootstrap.php
%wwwDir%
é o caminho absoluto para o diretório que contém 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 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();
}