tlr-symfony — bundle socle générique multisite
tlr-symfony est le socle générique de l'écosystème Telaria. Il fournit les briques réutilisables qui n'ont aucune dépendance IA : multisite, CMS moteur, Markdown, contact, i18n.
| Champ | Valeur |
|---|---|
| Package Composer | tlr/symfony-bundle |
| Namespace | Tlr\Symfony\ |
| Pilote | telaria-app (mĂŞme release flow) |
| Version en prod | develop (5476856) |
Spec fonctionnelle CMS :
specs/telaria-cms.mdSchéma BDD complet :../bdd/schema.mdMultisite VPS :../vps/03-vhosts-multisite.md
Périmètre
tlr-symfony ├── Multisite SiteResolver · SiteContext — un déploiement Symfony sert N domaines ├── CMS moteur CmsContent · CmsTag · CmsImage · routes canoniques custom ├── Markdown service de rendu Markdown → HTML (réutilisable) ├── Contact formulaire de contact + rate limiter intégré └── i18n extraction automatique des chaînes
Résolution multisite
Un seul déploiement Symfony sert plusieurs domaines avec des contenus distincts. La résolution se fait par Host HTTP à chaque requête.
requĂŞte HTTP (host: telaria.dev)
│
SiteResolver → SELECT * FROM site WHERE host = 'telaria.dev'
│ (fallback : site.is_primary = true)
â–Ľ
SiteContext → injecté dans les services (Twig, mail, CMS)
│
CMS routing → cms_content.slug WHERE site_id = <site.id>
Couplage app → bundle : resolve_target_entities dans doctrine.yaml pour CmsUserInterface → App\Entity\User. Le bundle ne dépend pas de la classe User directement.
Entités
site — Domaine servi
| Colonne | Type | Notes |
|---|---|---|
id |
INT AUTO_INCREMENT | PK |
host |
VARCHAR(255) UNIQUE | host canonique sans schéma (ex. telaria.dev) |
aliases |
JSON | nullable — hosts supplémentaires (ex. ["www.telaria.dev"]) |
slug |
VARCHAR(64) UNIQUE | id stable /^[a-z0-9-]+$/ (ex. codexia) |
label |
VARCHAR(128) | nom affiché |
locale_default |
VARCHAR(8) | défaut fr |
layout_template |
VARCHAR(128) | template Twig de layout |
theme |
VARCHAR(64) | nullable — clé CSS du thème |
brand_domain / brand_tld |
VARCHAR | nullable |
contact_email |
VARCHAR(255) | nullable — destinataire formulaire de contact |
sender_email |
VARCHAR(255) | nullable — expéditeur mails sortants |
home_slug |
VARCHAR(255) | nullable — slug de la page CMS racine (/) |
og_image_default |
VARCHAR(512) | nullable |
enabled |
BOOL | défaut true |
is_primary |
BOOL | site de repli si aucun host ne matche — un seul attendu |
created_at / updated_at |
DATETIME_IMMUTABLE | PrePersist/PreUpdate |
cms_content — Page ou contenu éditorial
Slug unique par site (contrainte composite UNIQUE(site_id, slug)).
| Colonne | Type | Notes |
|---|---|---|
id |
INT AUTO_INCREMENT | PK |
site_id |
INT FK | → site.id |
author_id |
INT FK | → user.id via CmsUserInterface |
title |
VARCHAR(255) | |
slug |
VARCHAR(255) | auto-slugifié à la création — UNIQUE(site_id, slug) |
excerpt |
TEXT | nullable |
markdown |
TEXT | contenu source |
status |
VARCHAR(20) | draft | published | archived |
published_at |
DATETIME | nullable — posé au premier publish() |
updated_at |
DATETIME | PrePersist/PreUpdate |
visibility |
VARCHAR(20) | public | protected | private |
type |
VARCHAR(50) | page (défaut) | block (fragments non indexés) |
noindex |
BOOL | meta robots noindex + exclusion sitemap |
og_image |
VARCHAR(512) | nullable — surcharge OG image du site |
cms_tag — Étiquette transverse
Vocabulaire partagé entre sites. Slug auto-généré depuis name.
cms_content_tag — Pivot ManyToMany
cms_content_id FK → cms_content.id / cms_tag_id FK → cms_tag.id.
cms_image — Image média
Upload sécurisé via FileUploader — validation MIME réelle (finfo, pas l'extension du fichier).
| Colonne | Type | Notes |
|---|---|---|
id |
INT AUTO_INCREMENT | PK |
filename |
VARCHAR(255) | nom de fichier stocké |
mime |
VARCHAR(100) | type MIME validé par finfo |
size |
INT | octets |
width / height |
INT | nullable |
checksum |
VARCHAR(64) | SHA-256 — déduplication |
created_at |
DATETIME | |
owner_id |
INT FK | → user.id |
site_id |
INT FK | nullable → site.id SET NULL si site supprimé |
content_id |
INT FK | nullable → cms_content.id (rattachement optionnel) |
Patterns Doctrine notables
Auto-mapping — Zéro fichier XML/YAML de mapping, zéro migration au bootstrap du bundle.
resolve_target_entities — CmsUserInterface → App\Entity\User (résolu dans doctrine.yaml de l'app). Le bundle ne dépend pas de la classe User.
Lifecycle callbacks — created_at / updated_at via #[PrePersist] / #[PreUpdate] sur les entités concernées.
Companion Entity — cms_content_seo (dans telaria-app) est une extension OneToOne de cms_content : la table cms_content appartient au bundle et ne peut pas être modifiée directement — le pattern companion permet d'ajouter des colonnes SEO côté app sans toucher au bundle.
Slug auto-généré — Le slug de cms_content est slugifié depuis le titre à la création (service interne). Contrainte UNIQUE(site_id, slug) : le CMS permet des slugs identiques entre sites différents.
Rate limiter (contact)
Le formulaire de contact utilise le composant RateLimiter Symfony (politique token_bucket). La destination est Site.contact_email. L'expéditeur est Site.sender_email.
Intégration dans l'app (doctrine.yaml)
doctrine: orm: resolve_target_entities: Tlr\Symfony\Contract\CmsUserInterface: App\Entity\User
Dépannage
Site non résolu — 404 ou site incorrect
# Vérifier les sites en base php bin/console doctrine:query:sql "SELECT id, host, slug, is_primary, enabled FROM site" # Host non dans la liste → SiteResolver prend le site is_primary=true comme fallback # Corriger : ajouter le host ou l'alias dans le BO / app:sites:sync php bin/console app:sites:sync
Slug de page introuvable
La contrainte UNIQUE(site_id, slug) : deux pages peuvent avoir le même slug sur des sites différents. Si une page ne s'affiche pas, vérifier que site_id pointe vers le bon site.
CMS content non publié
Statut draft ou archived → non visible en front (requête filtre status = 'published'). Publier depuis le back-office ou via Doctrine.
Voir aussi
specs/telaria-cms.md— spec fonctionnelle CMS../bdd/schema.md— schéma BDD complet (types exacts)../vps/03-vhosts-multisite.md— multisite Apache + SiteResolver en prod../guides/architecture-symfony.md— vue d'ensemble bundles../guides/patterns-symfony.md— patterns Doctrine (Companion Entity, rate limiter…)