Modello

Man mano che la nostra applicazione cresce, ci accorgiamo presto di dover eseguire operazioni di database simili in varie posizioni e in vari presentatori, ad esempio acquisendo gli articoli pubblicati più recenti. Se miglioriamo la nostra applicazione aggiungendo un flag agli articoli per indicare lo stato di work-in-progress, dobbiamo anche esaminare tutte le posizioni della nostra applicazione e aggiungere una clausola where per assicurarci che vengano selezionati solo gli articoli finiti.

A questo punto, il lavoro diretto con il database diventa insufficiente e sarà più intelligente aiutarsi con una nuova funzione che restituisca gli articoli pubblicati. E quando in seguito aggiungeremo un'altra clausola (ad esempio per non visualizzare gli articoli con data futura), modificheremo il codice in un solo punto.

Inseriamo la funzione nella classe PostFacade e la chiamiamo getPublicArticles().

Creeremo la nostra classe modello PostFacade nella cartella app/Model/ per occuparci dei nostri 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 passiamo il database Explorer. Questo sfrutterà la potenza del contenitore DI.

Passiamo a HomePresenter, che modificheremo in modo da eliminare la dipendenza da Nette\Database\Explorer, sostituendola con una nuova dipendenza dalla nostra nuova classe.

<?php
namespace App\UI\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 d'uso, stiamo usando App\Model\PostFacade, quindi possiamo abbreviare il codice PHP in PostFacade. Richiediamo questo oggetto nel costruttore, lo scriviamo nella proprietà $facade e lo usiamo nel metodo renderDefault.

L'ultimo passo da fare è insegnare al contenitore DI a produrre questo oggetto. Di solito lo si fa aggiungendo un punto elenco al file config/services.neon nella sezione services, indicando il nome completo della classe e i parametri del costruttore. Questo lo registra, per così dire, e l'oggetto viene chiamato service. Grazie a una magia chiamata autowiring, di solito non è necessario specificare i parametri del costruttore, perché DI li riconosce e li passa automaticamente. Pertanto, sarebbe sufficiente fornire solo il nome della classe:

...

services:
	- App\Model\PostFacade

Tuttavia, non è necessario aggiungere questa riga. Nella sezione search all'inizio di services.neon si definisce che tutte le classi che terminano con -Facade o -Factory saranno cercate automaticamente da DI, cosa che avviene anche per PostFacade.

Riepilogo

La classe PostFacade chiede Nette\Database\Explorer in un costruttore e poiché questa classe è registrata nel contenitore DI, il contenitore crea questa istanza e la passa. DI crea così un'istanza di PostFacade per noi e la passa in un costruttore alla classe HomePresenter che l'ha richiesta. Una specie di matrioska di codice. :) Tutti i componenti richiedono solo ciò di cui hanno bisogno e non si preoccupano di dove e come viene creato. La creazione è gestita dal contenitore DI.

Qui si possono leggere ulteriori informazioni sulla dependency injection e sulla configurazione.