02-ce-que-je-construis/specs/layout-cms.md

TLR-002 — Système de layout par page

Sélection du layout dans le CMS, templates dans le bundle — mécanisme générique réutilisable sur adoption-app.

Table des matières

  1. Contexte
  2. Périmètre lot 1
  3. Entité CmsContent — champ layout
  4. Migration
  5. Formulaire BO
  6. Résolution du template
  7. Templates bundle
  8. Nettoyage
  9. PHPUnit
  10. Ordre d'implémentation

Contexte

La livraison staging de TLR-002 (6d33521) implémentait un layout 3-cols uniquement pour /docs. Le besoin réel : toute page CMS (y compris la homepage) doit pouvoir choisir son layout. Mécanisme générique, réutilisable sur adoption-app.

État actuel pertinent :

  • CmsFrontController (/{slug}) → cms/show.html.twig → Ă©tend site.layoutTemplate (per-site, pas per-page)
  • DocsCmsController (/docs + /docs/{slug}) → docs/cms-layout.html.twig (3-col hardcodĂ©)
  • FrontController (/) → si site.homeSlug dĂ©fini → forwarde vers CmsFrontController ; sinon → front/index.html.twig (placeholder "nope" actuellement)
  • tlr/symfony-bundle : pas encore de dossier templates/ — premier ajout

Périmètre lot 1

In scope : champ layout sur CmsContent · dropdown BO · 2 layouts (default, three-col) · templates dans le bundle · homepage par défaut bundle · pages d'erreur bundle.

Out of scope : création de layouts via l'UI · plus de 2 layouts.


1. Entité CmsContent — champ layout (bundle tlr-symfony)

public const string LAYOUT_DEFAULT   = 'default';
public const string LAYOUT_THREE_COL = 'three-col';
public const array  LAYOUTS          = [self::LAYOUT_DEFAULT, self::LAYOUT_THREE_COL];

#[ORM\Column(length: 50, nullable: true)]
private ?string $layout = null;

Getter/setter classiques. null et 'default' sont équivalents côté rendu.


2. Migration

ALTER TABLE cms_content ADD layout VARCHAR(50) DEFAULT NULL;

Convention nommage : Version20260616120000.


3. Formulaire BO — CmsContentType (telaria-app)

->add('layout', ChoiceType::class, [
    'label'       => 'Mise en page',
    'required'    => false,
    'placeholder' => 'Par défaut',
    'choices'     => array_combine(
        array_map(fn($l) => ucfirst(str_replace('-', ' ', $l)), CmsContent::LAYOUTS),
        CmsContent::LAYOUTS
    ),
])

4. Résolution du template

Helper partagé (méthode privée ou service léger) :

private function resolveLayout(CmsContent $page): string
{
    return match ($page->getLayout()) {
        CmsContent::LAYOUT_THREE_COL => 'cms/layouts/three-col.html.twig',
        default                      => 'cms/layouts/default.html.twig',
    };
}

Variables injectées :

  • default → page, body_html, page_seo
  • three-col → idem + docs (findDocNavBySite($site)) + current_slug

CmsFrontController (/{slug}) : adopte resolveLayout().

DocsCmsController (/docs + /docs/{slug}) : garde les deux routes (le "doc" est dans le nom, c'est son périmètre). /docs/{slug} adopte resolveLayout() à la place du template hardcodé.


5. Templates bundle (tlr-symfony/templates/)

Premier dossier templates/ du bundle. Surcharge app : templates/bundles/TlrSymfonyBundle/.

cms/layouts/default.html.twig

Layout simple, contenu centré, pas de nav ni chatbot.

{% extends 'html.twig' %}
{% block doc_title %}{{ page.title }}{% endblock %}
{% block main %}
<main class="cms-default-layout">
    <div class="container py-4">
        <h1 class="h3 mb-4">{{ page.title }}</h1>
        {{ body_html|raw }}
    </div>
</main>
{% endblock %}

cms/layouts/three-col.html.twig

Reprend docs/cms-layout.html.twig (6d33521). Variables : page, body_html, docs, current_slug. Route nav : docs.show (garder pour lot 1).

front/index.html.twig — homepage par défaut

Affiché quand site.homeSlug est null. Filet de sécurité pour nouvelles installs (adoption-app).

{% extends 'html.twig' %}
{% block main %}
<main>
    <div class="container text-center py-5">
        <h1 class="display-6">Bienvenue</h1>
        <p class="text-muted">Ce site est en cours de configuration.</p>
    </div>
</main>
{% endblock %}

Pages d'erreur

  • bundles/TwigBundle/Exception/error404.html.twig
  • bundles/TwigBundle/Exception/error500.html.twig

Pages minimalistes, compatibles html.twig. Pas de dépendance à site (peut être null en contexte d'erreur).


6. Nettoyage (telaria-app)

  • templates/docs/cms-layout.html.twig → supprimer (remplacĂ© par le template bundle)
  • DocsCmsController : garder tel quel structurellement, remplacer le template hardcodĂ© par resolveLayout()

7. PHPUnit

  • DocsCmsControllerTest : /docs/{slug} → 200, template three-col
  • CmsFrontControllerTest : tester layout default ET three-col (page en base avec champ renseignĂ©)
  • Homepage : GET / avec site.homeSlug = null → 200, template bundle "Bienvenue" (pas de redirect login)

8. Ordre d'implémentation

  1. Bundle tlr-symfony : champ layout + migration + templates (cms/layouts/ + front/index.html.twig + error pages)
  2. App telaria-app : dropdown BO + resolveLayout() dans CmsFrontController et DocsCmsController + suppression docs/cms-layout.html.twig
  3. PHPUnit vert → dev (poseidon) → staging → récap inbox Chef

Assistant documentaire

Posez une question sur la documentation. Les réponses citent leurs sources — un clic ouvre le document à gauche.

Loading…
Loading the web debug toolbar…
Attempt #