Modelo

À medida que a aplicação cresce, logo descobriremos que em diferentes lugares, em diferentes presenters, precisamos realizar operações semelhantes com o banco de dados. Por exemplo, obter os artigos publicados mais recentemente. Se melhorarmos a aplicação, por exemplo, adicionando um sinalizador aos artigos para indicar se estão em rascunho, teremos que percorrer todos os lugares na aplicação onde os artigos são obtidos do banco de dados e adicionar uma condição where para selecionar apenas os artigos não rascunhados.

Nesse momento, o trabalho direto com o banco de dados se torna insuficiente e será mais conveniente usar uma nova função que nos retornará os artigos publicados. E quando adicionarmos outra condição posteriormente, por exemplo, que artigos com data futura não devem ser exibidos, modificaremos o código em apenas um lugar.

Colocaremos a função, por exemplo, na classe PostFacade e a chamaremos de getPublicArticles().

No diretório app/Model/, criaremos nossa classe de modelo PostFacade, que cuidará dos artigos:

<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('posts')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}

Na classe, solicitaremos a passagem do Database Explorer através do construtor. Aproveitaremos assim o poder do contêiner de DI.

Mudaremos para o HomePresenter, que modificaremos para nos livrarmos da dependência de Nette\Database\Explorer e a substituiremos pela nova dependência de nossa nova classe.

<?php
namespace App\Presentation\Home;

use App\Model\PostFacade;
use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private PostFacade $facade,
	) {
	}

	public function renderDefault(): void
	{
		$this->template->posts = $this->facade
			->getPublicArticles()
			->limit(5);
	}
}

Na seção use, temos App\Model\PostFacade, então podemos encurtar a escrita no código PHP para PostFacade. Solicitaremos este objeto no construtor, o escreveremos na propriedade $facade e o usaremos no método renderDefault.

Resta o último passo, que é ensinar o contêiner de DI a produzir este objeto. Isso geralmente é feito adicionando um marcador ao arquivo config/services.neon na seção services, indicando o nome completo da classe e os parâmetros do construtor. Assim, o registramos e o objeto é então chamado de serviço. Graças à mágica chamada autowiring, geralmente não precisamos especificar os parâmetros do construtor, pois o DI os reconhece e os passa automaticamente. Bastaria, portanto, indicar apenas o nome da classe:

...

services:
	- App\Model\PostFacade

No entanto, você nem precisa adicionar esta linha. Na seção search no início de services.neon, está definido que todas as classes terminadas com a palavra -Facade ou -Factory serão encontradas automaticamente pelo DI, o que também é o caso de PostFacade.

Resumo

A classe PostFacade solicita a passagem de Nette\Database\Explorer em seu construtor e, como esta classe está registrada no contêiner de DI, o contêiner cria esta instância e a passa. O DI cria assim para nós a instância de PostFacade e a passa no construtor para a classe HomePresenter, que a solicitou. É como uma matriosca. :) Todos apenas dizem o que querem e não se preocupam onde e como algo é criado. O contêiner de DI cuida da criação.

Aqui você pode ler mais sobre injeção de dependência e configuração.