Séparer traitement, modèle et gabarit
Objectif : Acheminer une requête vers son traitement puis afficher les données dans un gabarit sans logique métier.
Une page PHP devient difficile à faire évoluer lorsqu’elle mélange l’analyse de la requête, les appels à la base et la construction du HTML. Vous allez répartir ces tâches : le point d’entrée choisit le parcours, le contrôleur prépare les données, le dépôt interroge la base et le gabarit affiche le résultat.
Le modèle Contact et le dépôt ContactDepot ont déjà leurs responsabilités, présentées dans les leçons précédentes. Ici, vous ne déplacez pas leurs règles : vous organisez le passage des données jusqu’à l’affichage, en gardant les gabarits exempts de requêtes SQL et de décisions métier.
Le chemin d’une requête
Le point d’entrée public/index.php reçoit la requête et sélectionne le traitement approprié. Un contrôleur appelle les services ou le dépôt concernés, puis rassemble des valeurs destinées à la page. Enfin, un gabarit PHP produit le HTML à partir de ces valeurs. Le navigateur ne reçoit que le résultat rendu, jamais les objets PHP ni les requêtes SQL.
- Le point d’entrée route et coordonne la requête.
- Le contrôleur prépare les données et choisit le gabarit à rendre.
- Le dépôt lit ou modifie les données persistées ; le modèle porte les règles du contact.
- Le gabarit affiche les données reçues et échappe les valeurs qui entrent dans le HTML.
Dans le projet, la liste des contacts suit ce parcours : le contrôleur reçoit la recherche, demande les résultats à ContactDepot, puis transmet au gabarit la recherche et les contacts. Le gabarit ne décide pas comment effectuer la recherche ; il se contente de présenter les valeurs. Le nom exact des méthodes du dépôt doit rester celui défini dans votre fichier src/Depot/ContactDepot.php.
Préparer les données dans le contrôleur
Le contrôleur reçoit le dépôt par son constructeur, ce qui lui permet de déléguer la lecture sans créer lui-même la connexion PDO. L’exemple suivant présente la forme du traitement : adaptez uniquement l’appel de recherche et les accesseurs aux noms effectivement présents dans votre dépôt et votre classe Contact. Les données préparées sont transmises au gabarit sans produire de sortie depuis la logique métier.
<?php
declare(strict_types=1);
namespace Carnet\Controleur;
use Carnet\Depot\ContactDepot;
final class ContactControleur
{
public function __construct(
private ContactDepot $depot
) {
}
/**
* @return array{titre: string, recherche: string, contacts: array}
*/
public function afficherListe(string $recherche): array
{
$contacts = $this->depot->rechercher($recherche);
return [
'titre' => 'Mes contacts',
'recherche' => $recherche,
'contacts' => $contacts,
];
}
}La méthode retourne un tableau de données plutôt que d’afficher du texte. Dans le point d’entrée, ces valeurs peuvent être affectées à des variables, puis le gabarit de liste peut être inclus. L’inclusion s’exécute dans la portée où elle est appelée : les variables préparées juste avant sont donc accessibles dans le fichier inclus.
<?php
$donnees = $controleur->afficherListe($recherche);
$titre = $donnees['titre'];
$contacts = $donnees['contacts'];
require dirname(__DIR__, 2) . '/templates/contacts.php';Afficher sans exposer les données
Les données d’un contact peuvent contenir des caractères interprétés par le navigateur comme du HTML. Le gabarit doit donc les échapper au moment de les insérer dans le document. Utilisez htmlspecialchars avec ENT_QUOTES et l’encodage UTF-8, comme dans le contrat du projet. Cette opération concerne l’affichage HTML ; elle ne remplace ni la validation métier ni les paramètres liés des requêtes SQL.
<ul class="carnet-liste">
<?php foreach ($contacts as $contact): ?>
<li class="carnet-contact">
<h2><?= htmlspecialchars($contact->getNom(), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?= htmlspecialchars($contact->getCourriel() ?? '', ENT_QUOTES, 'UTF-8') ?></p>
<p><?= htmlspecialchars($contact->getTelephone() ?? '', ENT_QUOTES, 'UTF-8') ?></p>
</li>
<?php endforeach; ?>
</ul>Cet extrait montre la zone d’affichage d’un gabarit, pas une page autonome : il prend place dans templates/contacts.php, au sein du squelette HTML commun défini par le contrat. Utilisez les accesseurs réellement déclarés dans votre modèle. L’échappement se fait à chaque insertion dans le HTML, y compris pour la recherche, un message ou un titre contrôlé par une requête.
À retenir
- Le point d’entrée route ; il ne doit pas contenir le HTML des pages.
- Le contrôleur délègue les accès au dépôt et retourne les données utiles à l’affichage.
- Le gabarit reçoit ces données et se limite à produire le HTML.
- Échappez chaque valeur dynamique au moment de l’insérer dans le HTML avec htmlspecialchars.
- Respectez les classes et les fichiers prévus par le contrat du projet.
Dans la prochaine leçon, vous raccorderez ces responsabilités à l’initialisation commune et au formulaire de connexion du carnet privé.