Model

À mesure que notre application grandit, nous découvrons vite qu'il nous faut effectuer des opérations de base de données semblables à divers endroits et dans divers presenters, par exemple récupérer les derniers articles publiés. Si nous améliorons notre application, par exemple en ajoutant aux articles un drapeau indiquant s'il s'agit de brouillons, nous devons aussi passer en revue tous les endroits de l'application où les articles sont récupérés de la base et y ajouter une condition where garantissant que seuls les articles non brouillons sont sélectionnés.

À ce stade, travailler directement avec la base ne suffit plus et il sera plus malin d'utiliser une nouvelle méthode qui renvoie les articles publiés. Et lorsque nous ajouterons plus tard une autre condition (par exemple ne pas afficher les articles à date future), nous ne modifierons notre code qu'à un seul endroit.

Nous placerons la méthode dans la classe PostFacade et l'appellerons getPublicArticles().

Nous créerons notre classe de modèle PostFacade dans le répertoire app/Model/ pour qu'elle s'occupe 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 demandons l'Explorer de la base par le constructeur. Cela tire parti de la puissance du conteneur DI.

Passons à HomePresenter, que nous modifierons en supprimant la dépendance à Nette\Database\Explorer et en la remplaçant par une nouvelle dépendance vers notre nouvelle 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);
	}
}

Dans la section use, nous avons App\Model\PostFacade, nous pouvons donc raccourcir l'écriture dans le code PHP en 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 une entrée au fichier config/services.neon, dans la section services, en indiquant le nom complet de la classe et les paramètres du constructeur. Cela l'enregistre, et l'objet est alors appelé un service. Grâce à la magie de l'autowiring, nous n'avons généralement pas besoin d'indiquer les paramètres du constructeur, car DI les reconnaîtra et les passera automatiquement. Il suffirait donc d'indiquer le nom de la classe :

...

services:
	- App\Model\PostFacade

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

Résumé

La classe PostFacade demande Nette\Database\Explorer dans son constructeur et, comme cette classe est enregistrée dans le conteneur DI, le conteneur crée cette instance et la passe. DI crée ainsi pour nous une instance de PostFacade et la passe dans le constructeur à la classe HomePresenter, qui l'a demandée. C'est comme une poupée russe. :) Chacun se contente d'indiquer ce qu'il veut, sans se soucier de savoir où ni comment cela est créé. La création est prise en charge par le conteneur DI.

Vous pouvez en lire davantage ici sur l'injection de dépendances et la configuration.