Model
Man mano che la nostra applicazione cresce, scopriamo presto di dover eseguire operazioni simili sul database in punti diversi
e in presenter diversi, per esempio ottenere gli ultimi articoli pubblicati. Se miglioriamo l'applicazione, per esempio
aggiungendo agli articoli un flag che indica se sono bozze, dobbiamo anche rivedere tutti i punti in cui gli articoli vengono
presi dal database e aggiungere una condizione where perché vengano selezionati solo gli articoli che non
sono bozze.
A questo punto lavorare direttamente con il database non basta più e sarà più intelligente usare un nuovo metodo che restituisce gli articoli pubblicati. E quando più avanti aggiungeremo un'altra condizione (per esempio non mostrare gli articoli con data futura), modificheremo il nostro codice in un solo punto.
Metteremo il metodo nella classe PostFacade e lo chiameremo getPublicArticles().
La nostra classe di modello PostFacade la creeremo nella directory app/Model/, perché si occupi 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 ci facciamo passare l'Explorer del database tramite il costruttore. Sfruttiamo così la potenza del container DI.
Passiamo a HomePresenter, che modificheremo eliminando la dipendenza da Nette\Database\Explorer e
sostituendola con una 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 nel codice PHP possiamo abbreviare la
notazione in PostFacade. Ci facciamo passare questo oggetto nel costruttore, lo scriviamo nella proprietà
$facade e lo usiamo nel metodo renderDefault.
L'ultimo passo è insegnare al container DI a produrre questo oggetto. Di solito lo si fa aggiungendo una voce al file
config/services.neon nella sezione services, indicando il nome completo della classe e i parametri del
costruttore. Così viene registrato e l'oggetto si chiama poi servizio. Grazie alla magia dell'autowiring di solito non dobbiamo indicare i parametri del costruttore, perché la
DI li riconosce e li passa da sé. Basterebbe quindi indicare solo il nome della classe:
...
services:
- App\Model\PostFacade
Neanche questa riga però dovete aggiungerla. Nella sezione search di services.neon è definito che
tutte le classi che finiscono con -Facade oppure -Factory vengano trovate automaticamente dalla DI, ed
è il caso anche di PostFacade.
Riepilogo
La classe PostFacade chiede nel proprio costruttore Nette\Database\Explorer e, poiché questa classe
è registrata nel container DI, il container crea questa istanza e la passa. La DI crea così per noi un'istanza di
PostFacade e la passa nel costruttore alla classe HomePresenter, che l'ha richiesta. È come una
matrioska. :) Ognuno dice solo che cosa vuole e non gli importa dove e come venga creato. Della creazione si occupa il
container DI.
Qui potete leggere di più sulla dependency injection e sulla configurazione.