Aller au contenu principal

Architecture trois-tiers

Comprendre et implémenter les trois couches fondamentales d'une application

Petite vérification​

Avant de commencer, vérifiez si vous savez...

  1. dans le code de CharacterService::createForPlayer, repérer la ligne qui associe le personnage nouvellement créé au joueur récupéré ($character->setPlayer($player);), et indiquer dans quelle couche (Présentation, Métier ou Accès aux données) se trouve cette logique
  2. écrire un constructeur de service qui injecte un CharacterRepository par promotion de propriété (private CharacterRepository $characterRepository), sans passer par un setter
  3. dans un GameController, remplacer un appel direct à characterRepository par un appel à characterService, puis vérifier par relecture du fichier qu'aucune ligne du Controller ne mentionne plus directement le mot Repository
📌 Réponse attendue

Notions théoriques​

L'architecture trois-tiers est la forme la plus courante de l'architecture multi-tiers. L'application est divisée en exactement trois niveaux (couches), chacun ayant une responsabilité exclusive.

Les trois couches​

1. Couche de présentation​

Gère l'interface utilisateur et les interactions avec l'utilisateur. Elle ne contient aucune logique métier.

  • Reçoit les requêtes HTTP
  • Appelle la couche de traitement
  • Affiche les résultats

Dans Symfony : Controllers + Templates Twig

2. Couche de traitement (Business Logic)​

Contient toutes les règles métier de l'application. C'est le cœur de l'application.

  • Valide et transforme les données
  • Applique les règles du domaine
  • Orchestre les appels à la couche de données

Dans Symfony : Services, Domain classes

3. Couche d'accès aux données​

Gère la persistance et la récupération des données. Elle isole le reste de l'application des détails de stockage.

  • Lit et écrit en base de données
  • Cache les données si nécessaire
  • Expose une interface indépendante du moteur de base de données

Dans Symfony : Repositories, Entities (Doctrine ORM)

Représentation graphique​

┌─────────────────────────────────────┐
│ COUCHE PRÉSENTATION │
│ Controller + Templates Twig │
└──────────────┬──────────────────────┘
│ appelle
┌──────────────▼──────────────────────┐
│ COUCHE DE TRAITEMENT │
│ Services PHP │
└──────────────┬──────────────────────┘
│ appelle
┌──────────────▼──────────────────────┐
│ COUCHE D'ACCÈS AUX DONNÉES │
│ Repositories + Entities Doctrine │
└──────────────┬──────────────────────┘
│
Base de données

Exemple de mise en application​

Voici comment la création d'un personnage se répartit sur les trois couches :

Couche présentation (GameController.php) :

#[Route('/game/create-character/{playerId}', name: 'create_character')]
public function createCharacter(int $playerId): Response
{
$character = $this->characterService->createForPlayer($playerId);
return $this->render('character/created.html.twig', ['character' => $character]);
}

Couche traitement (CharacterService.php) :

class CharacterService
{
public function __construct(
private PlayerRepository $playerRepository,
private CharacterRepository $characterRepository,
) {}

public function createForPlayer(int $playerId): Character
{
$player = $this->playerRepository->find($playerId);
if ($player === null) {
throw new \InvalidArgumentException('Joueur introuvable');
}
$character = new Character();
$character->setName('Nouveau Personnage');
$character->setPlayer($player);
$this->characterRepository->save($character, true);
return $character;
}
}

Couche données (CharacterRepository.php) :

class CharacterRepository extends ServiceEntityRepository
{
public function findByPlayer(Player $player): array
{
return $this->findBy(['player' => $player]);
}
}

Test de mémorisation/compréhension​


Quelles sont les trois couches de l'architecture trois-tiers ?


Quelle couche contient les règles de validation métier ?


Un Controller peut-il appeler directement un Repository ?


Où se trouvent les entités Doctrine dans l'architecture trois-tiers ?


Quel est l'avantage principal de séparer les trois couches ?



TP pour réfléchir et résoudre des problèmes​

Identifiez et implémentez les trois couches dans votre application de jeu

Étape 1 : Créez la classe CharacterService en injectant CharacterRepository via le constructeur.

Étape 2 : Ajoutez dans CharacterRepository une méthode findByPlayer qui retourne tous les personnages d'un joueur.

Étape 3 : Dans CharacterService, ajoutez la méthode getCharactersForPlayer qui utilise findByPlayer du repository.


Bonne pratique - Ne jamais sauter une couche

La règle d'or de l'architecture trois-tiers : chaque couche ne communique qu'avec la couche directement adjacente. Le Controller ne doit jamais appeler directement un Repository, et le Repository ne doit jamais connaître le Controller. Cette discipline garantit que chaque couche reste testable et remplaçable indépendamment.

📌 Une solution