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.