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
{
public static function boot(): Configurator
{
$appDir = dirname(__DIR__);
$configurator = new Configurator;
//$configurator->setDebugMode('secret@23.75.345.200');
$configurator->enableTracy($appDir . '/log');
$configurator->setTempDirectory($appDir . '/temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
$configurator->addConfig($appDir . '/config/common.neon');
return $configurator;
}
}
index.php
No caso de aplicações web, o arquivo inicial é index.php
, que está localizado no diretório público
www/
. Ele permite que a classe Bootstrap
inicialize o ambiente e devolva o $configurator
que cria o contêiner DI. Em seguida, obtém o serviço Application
, que executa a aplicação web:
// inicializar o ambiente + obter objeto Configurador
$configurator = App\Bootstrap::boot();
// criar um recipiente DI
$container = $configurator->createContainer();
// Recipiente DI cria um objeto de aplicação Nette
$application = $container->getByType(Nette\Application\Application::class);
// iniciar a aplicação Nette
$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()
:
$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.
$configurator->setDebugMode('secret1234@23.75.345.200');
Também podemos desligar completamente o modo desenvolvedor, mesmo para o localhost:
$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:
$configurator->enableTracy($appDir . '/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:
$configurator->setTempDirectory($appDir . '/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:
$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.
$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()
:
$configurator->addConfig($appDir . '/config/common.neon');
O método addConfig()
pode ser chamado várias vezes para adicionar vários arquivos.
$configurator->addConfig($appDir . '/config/common.neon');
$configurator->addConfig($appDir . '/config/local.neon');
if (PHP_SAPI === 'cli') {
$configurator->addConfig($appDir . '/config/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.
$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.
$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.
$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%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:
$configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Diferentes Ambientes
Sinta-se à vontade para personalizar a classe Bootstrap
de acordo com suas necessidades. Você pode adicionar
parâmetros ao método boot()
para diferenciar projetos web, ou adicionar outros métodos, tais como
bootForTests()
, que inicializa o ambiente para testes unitários, bootForCli()
para scripts chamados a
partir da linha de comando, e assim por diante.
public static function bootForTests(): Configurator
{
$configurator = self::boot();
Tester\Environment::setup(); // Nette Tester initialization
return $configurator;
}