Modèle

Au fur et à mesure que notre application se développe, nous nous apercevons rapidement que nous devons effectuer des opérations de base de données similaires dans divers emplacements et dans divers présentateurs, par exemple acquérir les articles publiés les plus récents. Si nous améliorons notre application en ajoutant un drapeau aux articles pour indiquer un état de travail en cours, nous devons également passer par tous les emplacements de notre application et ajouter une clause where pour nous assurer que seuls les articles terminés sont sélectionnés.

À ce stade, le travail direct avec la base de données devient insuffisant et il sera plus judicieux de nous aider avec une nouvelle fonction qui renvoie les articles publiés. Et lorsque nous ajouterons plus tard une autre clause (par exemple pour ne pas afficher les articles ayant une date future), nous ne modifierons notre code qu'à un seul endroit.

Nous allons placer la fonction dans la classe PostFacade et l'appeler getPublicArticles().

Nous allons créer notre classe modèle PostFacade dans le répertoire app/Model/ pour s'occuper de nos articles :

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

Dans la classe nous passons la base de données Explorer :Nette\Database\Explorer. Cela permettra de profiter de la puissance du conteneur DI.

Nous passerons à HomePresenter que nous éditerons de manière à nous débarrasser de la dépendance sur Nette\Database\Explorer en la remplaçant par une nouvelle dépendance sur notre nouvelle 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);
	}
}

Dans la section utilisation, nous utilisons App\Model\PostFacade, nous pouvons donc raccourcir le code PHP à PostFacade. Nous demandons cet objet dans le constructeur, l'écrivons dans la propriété $facade et l'utilisons dans la méthode renderDefault.

La dernière étape consiste à apprendre au conteneur DI à produire cet objet. Cela se fait généralement en ajoutant un point au fichier config/services.neon dans la section services, en donnant le nom complet de la classe et les paramètres du constructeur. Cela l'enregistre, pour ainsi dire, et l'objet est alors appelé service. Grâce à une magie appelée câblage automatique, nous n'avons généralement pas besoin de spécifier les paramètres du constructeur car l'ID les reconnaît et les transmet automatiquement. Ainsi, il suffirait de fournir le nom de la classe :

...

services:
	- App\Model\PostFacade

Cependant, vous n'avez pas besoin d'ajouter cette ligne non plus. Dans la section search au début de services.neon il est défini que toutes les classes se terminant par -Facade ou -Factory seront recherchées par DI automatiquement, ce qui est également le cas pour PostFacade.

Résumé

La classe PostFacade demande Nette\Database\Explorer dans un constructeur et comme cette classe est enregistrée dans le conteneur DI, le conteneur crée cette instance et la transmet. DI crée ainsi une instance de PostFacade pour nous et la transmet dans un constructeur à la classe HomePresenter qui l'a demandée. Une sorte de poupée Matryoshka de code :) Tous les composants ne demandent que ce dont ils ont besoin et ils ne se soucient pas de savoir où et comment cela est créé. La création est gérée par le conteneur DI.

Vous trouverez ici plus d'informations sur l'injection de dépendances et sur la configuration.