Modello

Man mano che l'applicazione cresce, ci accorgeremo presto che in diversi punti, in diversi presenter, abbiamo bisogno di eseguire operazioni simili con il database. Ad esempio, ottenere gli articoli pubblicati più di recente. Se miglioriamo l'applicazione, ad esempio aggiungendo un flag agli articoli per indicare se sono in bozza, dobbiamo poi passare attraverso tutti i punti dell'applicazione in cui gli articoli vengono recuperati dal database e aggiungere una condizione where per selezionare solo gli articoli non in bozza.

In quel momento, il lavoro diretto con il database diventa insufficiente e sarà più pratico aiutarci con una nuova funzione che ci restituirà gli articoli pubblicati. E quando in seguito aggiungeremo un'altra condizione, ad esempio che non devono essere visualizzati articoli con data futura, modificheremo il codice solo in un punto.

Posizioneremo la funzione ad esempio nella classe PostFacade e la chiameremo getPublicArticles().

Nella directory app/Model/ creiamo la nostra classe modello PostFacade, che si occuperà degli articoli:

<?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');
	}
}

Nella classe, tramite il costruttore, ci facciamo passare l'Explorer del database. Sfruttiamo così la potenza del container DI.

Passiamo a HomePresenter, che modificheremo in modo da eliminare la dipendenza da Nette\Database\Explorer e sostituirla con la nuova dipendenza dalla nostra nuova 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);
	}
}

Nella sezione use abbiamo App\Model\PostFacade, quindi possiamo abbreviare la scrittura nel codice PHP in PostFacade. Richiediamo questo oggetto nel costruttore, lo scriviamo nella proprietà $facade e lo usiamo nel metodo renderDefault.

Resta l'ultimo passo, ovvero insegnare al container DI a produrre questo oggetto. Di solito si fa aggiungendo un trattino nella sezione services del file config/services.neon, indicando il nome completo della classe e i parametri del costruttore. In questo modo la registriamo e l'oggetto viene quindi chiamato servizio. Grazie alla magia chiamata autowiring di solito non dobbiamo specificare i parametri del costruttore, perché DI li riconosce e li passa da solo. Basterebbe quindi indicare solo il nome della classe:

...

services:
	- App\Model\PostFacade

Tuttavia, non è nemmeno necessario aggiungere questa riga. Nella sezione search all'inizio di services.neon è definito che tutte le classi che terminano con la parola -Facade o -Factory vengono trovate automaticamente da DI, il che è anche il caso di PostFacade.

La classe PostFacade richiede nel costruttore il passaggio di Nette\Database\Explorer e poiché questa classe è registrata nel container DI, il container crea questa istanza e la passa. DI crea così per noi l'istanza di PostFacade e la passa nel costruttore alla classe HomePresenter, che l'ha richiesta. Una specie di matrioska. :) Tutti dicono solo cosa vogliono e non si preoccupano di dove e come viene creato qualcosa. Della creazione si occupa il container DI.

Qui potete leggere di più sulla dependency injection e sulla configurazione.