Aller au contenu

Imports et usage

Objectif : exposer les trois façades sous un import unique et les utiliser dans un contrôleur réel.

Ce que vous allez apprendre : ré-exporter les façades depuis le package, et les combiner (session, flash, cookie) dans le flux d'un formulaire, en restant cohérent avec les helpers déjà fournis par Forge.

Là où nous en sommes

Vous avez les quatre fichiers : _facade.py, session.py, cookies.py, flash.py.
Il reste à les rendre commodes à importer, puis à les employer.

L'ajout

Ré-exportez les façades dans mvc/helpers/__init__.py :

# mvc/helpers/__init__.py
from mvc.helpers.cookies import Cookies
from mvc.helpers.flash import Flash
from mvc.helpers.session import Session

__all__ = ["Session", "Cookies", "Flash"]

Un contrôleur peut alors tout importer en une ligne et composer le flux :

# mvc/controllers/note_controller.py (extrait)
from core.http.request import Request
from core.http.response import Response
from core.mvc.controller.base_controller import BaseController
from mvc.helpers import Cookies, Flash, Session


class NoteController(BaseController):

    @staticmethod
    def _ensure_session(request: Request):
        """Garantit une session et renvoie (session_id, data)."""
        session_id = Session.current_id(request)
        data = Session.get(session_id) if session_id else None
        if data is None:
            session_id = Session.new()
            data = Session.get(session_id)
        return session_id, data

    @staticmethod
    def form(request: Request) -> Response:
        session_id, data = NoteController._ensure_session(request)
        theme = Cookies.get(request, "theme", default="light")   # lecture : sans risque
        response = BaseController.render(
            "note/form.html",
            request=request,
            context={
                "csrf_token": data["csrf_token"],
                "flash": Flash.get(session_id),   # one-shot : lu puis supprimé
                "theme": theme,
            },
        )
        Session.set_cookie(response, session_id)   # le SEUL Set-Cookie de cette réponse
        return response

    @staticmethod
    def create(request: Request) -> Response:
        # ... traitement de la création ...
        # Motif POST -> redirect : Forge pose le flash ET redirige.
        return BaseController.redirect("/note/form", request=request, flash="Note enregistrée")

Comprendre ce code

  • __init__.py ré-exporte les trois classes : from mvc.helpers import Session, Flash, Cookies suffit, et __all__ borne la surface publique du package.
  • _ensure_session compose les primitifs de Session (lire l'id, lire la session, en créer une si besoin).
    On garde la logique get-or-create dans le contrôleur ; les façades, elles, restent des primitifs.
  • Lecture du flash : Flash.get(session_id) dans le rendu.
    S'il y a un message en attente (posé par une action précédente), il s'affiche une fois.
  • Pose du flash : pour le cas POST→redirect, on utilise BaseController.redirect(..., flash="…"), déjà fourni par Forge, qui pose le message et redirige.
    Flash.set(...) de notre façade sert seulement aux rares cas où l'on pose un flash sans rediriger.
  • Cookie : on lit un cookie applicatif (theme) sans risque.
    On ne le réécrit pas ici, car cette réponse pose déjà le cookie de session (Session.set_cookie) ; rappel du palier 3 : un seul Set-Cookie par réponse.
    Pour changer le thème, on le ferait sur une réponse dédiée qui ne pose pas la session.

Tester

Lancez l'application (forge run) et ouvrez le formulaire : le jeton CSRF est rempli, le thème lu depuis le cookie, et après une création le message « Note enregistrée »
apparaît une seule fois au retour.

À retenir

  • mvc/helpers/__init__.py donne un import unique pour les trois façades.
  • La logique get-or-create se compose dans le contrôleur ; les façades restent des primitifs.
  • Réutilisez les helpers de Forge quand ils existent (BaseController.redirect pour flash+redirect) ; vos façades complètent, elles ne remplacent pas.
  • Respectez la limite un seul Set-Cookie par réponse.

Continuer avec le Bilan