Como funcionam as aplicações?

Atualmente você está lendo o documento básico da documentação Nette. Você aprenderá todo o princípio das aplicações web. Nice de A a Z, desde o momento do nascimento até o último suspiro do script PHP. Após a leitura, você saberá:

  • como tudo isso funciona
  • o que é Bootstrap, Apresentador e Recipiente DI
  • como é a estrutura do diretório

Estrutura do diretório

Abra um exemplo de esqueleto de uma aplicação web chamada WebProject e você pode assistir aos arquivos que estão sendo escritos.

A estrutura do diretório é algo parecido com isto:

web-project/
├── app/                      ← directory with application
│   ├── Core/                 ← classes básicas necessárias
│   │   └── RouterFactory.php ← configuração de endereços URL
│   ├── UI/                   ← apresentadores, modelos e outros
│   │   ├── @layout.latte     ← modelo de layout compartilhado
│   │   └── Home/             ← Diretório do apresentador Home
│   │       ├── HomePresenter.php ← Classe do apresentador da página inicial
│   │       └── default.latte ← template for action default
│   └── Bootstrap.php         ← booting class Bootstrap
├── bin/                      ← scripts for the command line
├── config/                   ← configuration files
│   ├── common.neon
│   └── services.neon
├── log/                      ← error logs
├── temp/                     ← temporary files, cache, …
├── vendor/                   ← libraries installed by Composer
│   ├── ...
│   └── autoload.php          ← autoloading of libs installed by Composer
├── www/                      ← public directory, document root of project
│   ├── .htaccess             ← mod_rewrite rules etc
│   └── index.php             ← initial file that launches the application
└── .htaccess                 ← prohibits access to all directories except www

Você pode mudar a estrutura do diretório de qualquer forma, renomear ou mover pastas e depois basta editar os caminhos para log/ e temp/ no arquivo Bootstrap.php e o caminho para este arquivo em composer.json na seção autoload. Nada mais, nenhuma reconfiguração complicada, nenhuma mudança constante. A Nette tem uma autodetecção inteligente.

Para aplicações um pouco maiores, podemos dividir pastas com apresentadores e modelos em subdiretórios (em disco) e em namespaces (em código), que chamamos de módulos.

O diretório www/ é o diretório público ou a base de documentos do projeto. Você pode renomeá-lo sem ter que definir nada mais no lado da aplicação. Basta configurar a hospedagem para que a raíz do documento vá para este diretório.

Você também pode baixar o WebProject diretamente, incluindo a Nette, usando o Composer:

composer create-project nette/web-project

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

O aplicativo WebProject está pronto para rodar, não há necessidade de configurar mais nada e você pode vê-lo diretamente no navegador acessando a pasta www/.

Solicitação HTTP

Tudo começa quando um usuário abre a página em um navegador e o navegador bate no servidor com uma solicitação HTTP. A requisição vai para um arquivo PHP localizado no diretório público www/, que é index.php. Vamos supor que esta seja uma solicitação para https://example.com/product/123 e será executada.

Sua tarefa é:

  1. inicializar o meio ambiente
  2. obter a fábrica
  3. lançar a aplicação Nette que trata do pedido

Que tipo de fábrica? Nós não produzimos tratores, mas websites! Espere, isso será explicado imediatamente.

Por “inicializar o ambiente” queremos dizer, por exemplo, que Tracy é ativado, o que é uma ferramenta incrível para registrar ou visualizar erros. Ele registra os erros no servidor de produção e os exibe diretamente no servidor de desenvolvimento. Portanto, a inicialização também precisa decidir se o site está rodando em modo de produção ou de desenvolvimento. Para isso, a Nette usa autodetecção: se você executar o site no localhost, ele roda em modo desenvolvedor. Você não precisa configurar nada e o aplicativo está pronto tanto para o desenvolvimento quanto para a implantação em produção. Estas etapas são executadas e descritas em detalhes no capítulo sobre a classe Bootstrap.

O terceiro ponto (sim, pulamos o segundo, mas voltaremos a ele) é iniciar a aplicação. O tratamento dos pedidos HTTP em Nette é feito pela classe Nette\Application\Application (doravante denominada Application), portanto, quando dizemos “executar uma aplicação”, queremos chamar um método com o nome run() sobre um objeto desta classe.

Nette é um mentor que orienta você a escrever aplicações limpas através de metodologias comprovadas. E a mais comprovada é chamada de injeção de dependência, abreviada DI. No momento não queremos sobrecarregá-lo com a explicação de DI, já que existe um capítulo separado, o importante aqui é que os objetos chave serão normalmente criados por uma fábrica para objetos chamados container de DI (abreviado DIC). Sim, esta é a fábrica que foi mencionada há um tempo atrás. E também cria o objeto Application para nós, portanto precisamos primeiro de um container. Nós o obtemos usando a classe Configurator e o deixamos produzir o objeto Application, chamamos o método run() e isto inicia a aplicação Nette. Isto é exatamente o que acontece no arquivo index.php.

Aplicação Nette

A classe Application tem uma única tarefa: responder a uma solicitação HTTP.

As aplicações escritas em Nette são divididas em muitos dos chamados apresentadores (em outras estruturas você pode encontrar o termo controlador, que é o mesmo), que são classes que representam uma página específica do site: por exemplo, página inicial; produto na loja virtual; formulário de login; feed do mapa do site, etc. A aplicação pode ter de um a milhares de apresentadores.

A aplicação começa pedindo ao chamado roteador que decida qual dos apresentadores deve passar o atual pedido de processamento. O roteador decide de quem é a responsabilidade. Ele analisa a URL de entrada https://example.com/product/123, que quer show um produto com id: 123 como uma ação. É um bom hábito escrever um par de apresentador + ação separado por dois pontos como Product:show.

Assim, o roteador transformou a URL em um par Presenter:action + parâmetros, em nosso caso Product:show + id: 123. Você pode ver como é um roteador no arquivo app/Core/RouterFactory.php e nós o descreveremos em detalhes no capítulo Roteamento.

Vamos em frente. O pedido já conhece o nome do apresentador e pode continuar. Ao criar um objeto ProductPresenter, que é o código do apresentador Product. Mais precisamente, pede ao contêiner DI para criar o apresentador, pois a produção de objetos é sua função.

O apresentador pode se parecer com isto:

class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private ProductRepository $repository,
	) {
	}

	public function renderShow(int $id): void
	{
		// obtemos os dados do modelo e os passamos para o modelo
		$this->template->product = $this->repository->getProduct($id);
	}
}

O pedido é tratado pelo apresentador. E a tarefa é clara: fazer ação show com id: 123. O que na linguagem dos apresentadores significa que o método renderShow() é chamado e no parâmetro $id recebe 123.

Um apresentador pode lidar com múltiplas ações, ou seja, ter múltiplos métodos render<Action>(). Mas recomendamos projetar apresentadores com uma ou o menor número possível de ações.

Então, o método renderShow(123) foi chamado, cujo código é um exemplo fictício, mas você pode ver nele como os dados são passados para o modelo, ou seja, escrevendo para $this->template.

Posteriormente, o apresentador retorna a resposta. Pode ser uma página HTML, uma imagem, um documento XML, o envio de um arquivo do disco, JSON ou o redirecionamento para outra página. É importante ressaltar que se não dissermos explicitamente como responder (que é o caso de ProductPresenter), a resposta será renderizar o template com uma página HTML. Por quê? Bem, porque em 99% dos casos queremos desenhar um template, então o apresentador toma este comportamento como padrão e quer tornar nosso trabalho mais fácil. Esse é o ponto de vista da Nette.

Não precisamos nem mesmo especificar o modelo a ser renderizado; a estrutura deduzirá o caminho por si só. No caso da ação show, ele simplesmente tenta carregar o modelo show.latte no diretório com a classe ProductPresenter. Ele também tenta encontrar o layout no arquivo @layout.latte (mais informações sobre a pesquisa de modelos).

Em seguida, os modelos são renderizados. Isso conclui a tarefa do apresentador e de todo o aplicativo, e o trabalho está concluído. Se o modelo não existir, será retornada uma página de erro 404. Você pode ler mais sobre apresentadores na página Apresentadores.

Só para ter certeza, vamos tentar recapitular todo o processo com uma URL ligeiramente diferente:

  1. a URL será https://example.com
  2. iniciamos a aplicação, criamos um container e executamos Application::run()
  3. o roteador decodifica a URL como um par Home:default
  4. um objeto HomePresenter é criado
  5. método renderDefault() é chamado (se existir)
  6. um modelo default.latte com um layout @layout.latte é apresentado

Você pode ter se deparado com muitos conceitos novos agora, mas acreditamos que eles fazem sentido. Criar aplicações em Nette é uma brisa.

Modelos

Quando se trata dos modelos, a Nette utiliza o sistema de modelos Latte. É por isso que os arquivos com os gabaritos terminam com .latte. O Latte é usado porque é o sistema de modelos mais seguro para PHP e, ao mesmo tempo, o sistema mais intuitivo. Você não precisa aprender muito de novo, você só precisa conhecer PHP e algumas tags de Latte. Você descobrirá tudo na documentação.

No modelo, criamos um link para outros apresentadores e ações da seguinte forma:

<a n:href="Product:show $productId">product detail</a>

Basta escrever o familiar par Presenter:action ao invés da URL real e incluir quaisquer parâmetros. O truque é n:href, que diz que este atributo será processado pela Nette. E ele será gerado:

<a href="/product/456">product detail</a>

O roteador mencionado anteriormente está encarregado de gerar a URL. De fato, os roteadores em Nette são únicos na medida em que podem realizar não apenas transformações de uma URL para um par de apresentador:ação, mas também vice-versa gerar uma URL a partir do nome do apresentador + ação + parâmetros. Graças a isto, em Nette você pode alterar completamente a forma da URL em toda a aplicação finalizada sem alterar um único caractere no modelo ou apresentador apenas modificando o roteador. E graças a isto, o chamado trabalho de canonização, que é outra característica única da Nette, que melhora o SEO (otimização da capacidade de busca na internet), evitando automaticamente a existência de conteúdo duplicado em diferentes URLs. Muitos programadores acham isso surpreendente.

Componentes interativos

Temos mais uma coisa a lhe dizer sobre os apresentadores: eles têm um sistema de componentes embutido. Os mais antigos de vocês podem se lembrar de algo semelhante dos formulários Delphi ou ASP.NET Web Forms. O React ou Vue.js é construído sobre algo remotamente semelhante. No mundo das estruturas PHP, esta é uma característica completamente única.

Os componentes são unidades reutilizáveis separadas que colocamos em páginas (ou seja, apresentadores). Eles podem ser formas, datagrids, menus, enquetes, na verdade, qualquer coisa que faça sentido usar repetidamente. Podemos criar nossos próprios componentes ou usar alguns dos enormes componentes de código aberto.

Os componentes mudam fundamentalmente a abordagem para o desenvolvimento de aplicações. Eles abrirão novas possibilidades de composição de páginas a partir de unidades pré-definidas. E eles têm algo em comum com Hollywood.

DI Container e Configuração

O recipiente DI (fábrica para objetos) é o coração de toda a aplicação.

Não se preocupe, não é uma caixa preta mágica, como pode parecer das palavras anteriores. Na verdade, é uma classe PHP bastante enfadonha gerada pela Nette e armazenada em um diretório cache. Ela tem muitos métodos nomeados como createServiceAbcd() e cada um deles cria e devolve um objeto. Sim, há também um método createServiceApplication() que produzirá Nette\Application\Application, que precisávamos no arquivo index.php para executar a aplicação. E há métodos para a produção de apresentadores individuais. E assim por diante.

Os objetos que o container DI cria são chamados de serviços por alguma razão.

O que é realmente especial sobre esta classe é que ela não é programada por você, mas pela estrutura. Ela realmente gera o código PHP e o salva em disco. Você apenas dá instruções sobre quais objetos o recipiente deve ser capaz de produzir e como exatamente. E estas instruções são escritas em arquivos de configuração no formato NEON e, portanto, têm a extensão .neon.

Os arquivos de configuração são usados puramente para instruir o recipiente DI. Assim, por exemplo, se eu especificar a opção expiration: 14 days na seção sessão, o recipiente DI ao criar o objeto Nette\Http\Session que representa a sessão chamará seu método setExpiration('14 days'), e assim a configuração se tornará uma realidade.

Há um capítulo inteiro pronto para você, descrevendo o que pode ser configurado e como definir seus próprios serviços.

Uma vez que você entre na criação de serviços, você se deparará com a palavra autoconexão. Este é um gadget que tornará sua vida incrivelmente mais fácil. Ele pode passar objetos automaticamente onde você precisar (nos construtores de suas aulas, por exemplo) sem ter que fazer nada. Você descobrirá que o recipiente DI em Nette é um pequeno milagre.

E agora?

Passamos pelos princípios básicos das aplicações em Nette. Até agora, muito superficialmente, mas em breve você mergulhará nas profundezas e eventualmente criará aplicações maravilhosas na web. Onde continuar? Você já tentou o tutorial Criar sua primeira aplicação?

Além do acima exposto, Nette possui todo um arsenal de classes úteis, camada de banco de dados, etc. Tente de propósito apenas clicar na documentação. Ou visite o blog. Você descobrirá um monte de coisas interessantes.

Deixe que a estrutura lhe traga muita alegria 💙

versão: 4.0