AR

Comprendre la stack

Le rôle de chaque outil, à partir du prototype que vous avez sous les yeux.

  1. Symfony

    Reçoit la requête, lit les filtres, prépare les fixtures et choisit la réponse.

  2. Twig

    Rend le HTML avec des composants maison : props, blocs et attributs fusionnés.

  3. Turbo

    Remplace une page ou une région par du HTML serveur, sans API JSON.

  4. Stimulus

    Ajoute les comportements locaux : focus, chargement, thème, dialogues.

Un exemple : ouvrir une mission

Dans Missions, le lien d’une ligne pointe vers /missions?selected=1. Il vit dans la Frame mission-results : Turbo n’échange que cette région et met l’URL à jour. Symfony valide les paramètres et redirige une sélection hors filtre. Stimulus place le focus sur le titre de la fiche. Sans JavaScript, le même lien charge la page complète.

Essayer le parcours
Symfony : le contrôleur prépare les données

Un contrôleur par rubrique, quelques lignes chacun. Les paramètres d’URL arrivent par #[MapQueryParameter] (un paramètre non scalaire répond 400), le filtrage vit dans le domaine (MissionFilter, enum MissionStatus) et les données passent par l’interface WorkspaceRepository, servie ici par des fixtures en mémoire.

#[Route('', name: 'index', methods: ['GET'])]
public function index(
    #[MapQueryParameter(validationFailedStatusCode: 400)] string $q = '',
    #[MapQueryParameter(validationFailedStatusCode: 400)] string $status = '',
): Response {
    $filter = new MissionFilter($q, MissionStatus::tryFrom($status));

    return $this->render('mission/index.html.twig', [
        'missions' => $this->workspace->findMissions($filter),
    ]);
}
Documentation Symfony 7.4 : contrôleurs
Twig et TwigComponent : un design system de composants maison

Toutes les pages héritent de base.html.twig. Les primitives Ui:* et les composants métier Mission:*, Document:* sont des composants anonymes : des props déclarées par {% props %}, un bloc content et fusionnent les attributs avec attributes.defaults() : un data-action Stimulus ou une classe passés par l’appelant sont conservés. La rosette Ui:Guilloche est une classe PHP qui calcule ses courbes ; le gabarit les lit via computed pour ne les calculer qu’une fois par rendu.

<twig:Ui:Button href="{{ path('app_document_index') }}" intent="secondary">
  Ouvrir les documents
</twig:Ui:Button>

<twig:Ui:Guilloche :seed="mission.id" :progress="mission.progress" :size="44" />
Documentation Symfony UX TwigComponent
Turbo : navigation, régions et transitions

Turbo Drive charge les pages ; la balise view-transition lui laisse animer le passage d’une page à l’autre avec l’API View Transitions, le rail restant immobile. Les Frames mission-results et document-results ne remplacent que la liste et la fiche après un filtre GET.

<meta name="view-transition" content="same-origin">
<turbo-frame id="mission-results" data-turbo-action="advance">
  <!-- Liste et fiche rendues par Twig -->
</turbo-frame>
Documentation Turbo : Frames
Stimulus : petites interactions et cycle de vie

filtered_results_controller.js gère chargement, erreur et focus de la région filtrée de Missions et de Documents, branché dans Twig par stimulus_controller() et stimulus_action(). Le skeleton n’apparaît qu’après 140 ms de requête, jamais pour une réponse rapide. theme_controller.js révèle le thème depuis le bouton. Chaque minuteur est nettoyé à la déconnexion et avant la mise en cache Turbo.

export default class extends Controller {
    static targets = ['skeleton', 'content'];
    start(event) {
        this.skeletonTimer = setTimeout(() => this.showSkeleton(), SKELETON_DELAY);
    }
    disconnect() { this.stopLoading(); }
}
Documentation Stimulus : cycle de vie
SCSS et Encore : des tokens aux composants

Les styles sont des modules @use rangés par couche : settings (primitives de marque, rôles sémantiques, points de rupture), base, components (un partiel par composant Ui), layout, domain, pages et motion. Les composants ne lisent que des propriétés CSS sémantiques : le thème sombre redéfinit les rôles, pas les composants. Les listes s’adaptent à leur conteneur avec des container queries.

// settings/_tokens.scss
:root { --action: #{brand.$green}; --copper: #8c4810; }
[data-theme='dark'] { --action: #8fcfa2; }

// components/_status.scss
.ui-status--amber { --_ink: var(--copper); }
Documentation Encore

Symfony 7.4, Twig 3, TwigComponent 3.6, Stimulus 3 et Turbo 8 sont utilisés ici. Ce guide explique cette réalisation.

Rechercher dans votre espace

Rémunération du dirigeantMission à votre tour Audit de votre structureMission en cours Votre synthèseDocument de la mission Rémunération du dirigeant DocumentsToutes vos pièces FacturationHistorique des factures Design systemEncres, composants, mouvement