profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Hybrid

Collection of Pages with ComponentsTypes of ComponentsSetup server sent events (SSE) content refetchInstall Profound CMS as a proxyScripts dans le générateur de modÚlesProject ScaffoldingBibliothÚque multimédia

Sans interface

Démarrage rapideSplit Screen JSON Component Builder with LLMComponent Zod Pull

API REST

REST API OverviewgetConnect your websitegetGET /routesgetGET /routegetGET /blocksgetGET /blocks/with-cel-cachegetGET /blocks/generatedgetGET /componentsgetGET /components/{name}getGET /dataset/{schema_name}getGET /content-changes (SSE)patchPATCH /dataset/{schema_name}postPOST /translationpatchPATCH /translationsgetGET /usagepostPOST /csvpatchPATCH /csv
All Systems Operational
Powered Byprofound-logo
Theme

Scripts dans le générateur de modÚles

Guide pratique pour écrire des expressions CEL dans le CMS.

Guide pratique pour écrire des expressions CEL dans le CMS.


Fonctionnement de CEL

CEL (Common Expression Language) est un langage de script léger intégré à notre CMS. Il vous permet d'écrire des expressions dynamiques qui peuvent extraire des données des documents, lire les paramÚtres d'URL et calculer des valeurs à la volée.

Voici ce qui se passe lorsqu'un script CEL s'exécute :

Votre script                    Le moteur                      Résultat
    |                              |                              |
    v                              v                              v
documents.get("article", "intro") --> RécupÚre depuis la base de données --> { headline: "Welcome", body: "..." }
         .headline                --> Extrait le champ        --> "Welcome"

ConsidĂ©rez CEL comme un langage de requĂȘte en lecture seule. Il ne peut rien modifier dans la base de donnĂ©es : il se contente de lire des donnĂ©es et de renvoyer un rĂ©sultat calculĂ©. Cela le rend sĂ»r Ă  utiliser partout dans le CMS.


Les éléments de base

Chaque expression CEL a accĂšs Ă  trois choses :

ObjetCe que c'estExemple
documentsRécupÚre n'importe quel document du CMSdocuments.get("country", "us")
metaInformations sur la requĂȘte en cours (locale, paramĂštres d'URL)meta.locale, meta.params.slug
schemaDéfinitions des champs du document courantschema.fields

Auto-référence avec doc

Lorsque vous écrivez des expressions CEL dans un éditeur de document, vous pouvez accéder aux valeurs des champs du document courant à l'aide de l'objet doc. Cela permet de créer des champs calculés et des références entre champs.

// Accéder au champ price du document courant
doc.price

// Calculer un total Ă  partir des champs du document courant
doc.price * doc.quantity

// Condition en fonction de l'état du document courant
doc.status == "published" ? doc.title : "Brouillon : " + doc.title

L'objet doc contient toutes les valeurs des champs du document en cours d'édition. C'est utile pour :

  • Les champs calculĂ©s (par exemple, doc.price * doc.quantity)
  • La logique d'affichage conditionnelle basĂ©e sur l'Ă©tat du document
  • Les expressions de type validation

Récupération de documents

La fonctionnalité la plus puissante de CEL est la récupération de documents partout dans votre CMS.

Obtenir un document unique

Syntaxe : documents.get(schemaName, identifier)

Supposons que vous ayez un document article stocké avec l'identifiant "welcome-post" :

// Stocké dans le CMS sous : article / welcome-post
{
  "headline": "Bienvenue sur notre plateforme",
  "author": "Sarah Chen",
  "body": "Nous sommes ravis d'annoncer...",
  "tags": ["annonce", "actualités"]
}

Pour récupérer l'intégralité du document :

documents.get("article", "welcome-post")

Renvoie :

{
  "headline": "Bienvenue sur notre plateforme",
  "author": "Sarah Chen",
  "body": "Nous sommes ravis d'annoncer...",
  "tags": ["annonce", "actualités"]
}

Pour récupérer uniquement le titre :

documents.get("article", "welcome-post").headline

Renvoie : "Bienvenue sur notre plateforme"

Pour récupérer l'autrice :

documents.get("article", "welcome-post").author

Renvoie : "Sarah Chen"


Utilisation des paramĂštres d'URL

Lorsque votre page utilise des routes dynamiques (comme /articles/[slug]), vous pouvez utiliser meta.params pour récupérer le paramÚtre d'URL et obtenir le bon document.

Si quelqu'un visite /articles/welcome-post :

documents.get("article", meta.params.slug).headline

Renvoie : "Bienvenue sur notre plateforme"

C'est ainsi que vous construisez des pages dynamiques : le mĂȘme script CEL fonctionne pour n'importe quel article, en utilisant simplement le slug prĂ©sent dans l'URL.


Récupérer plusieurs documents

Syntaxe : documents.find(schemaName) ou documents.find(schemaName, filter)

// Obtenir tous les pays
documents.find("country")

Renvoie :

[
  { "code": "us", "name": "États-Unis", "flag": "US" },
  { "code": "sa", "name": "Arabie saoudite", "flag": "SA" },
  { "code": "gb", "name": "Royaume-Uni", "flag": "GB" }
]
// Obtenir des pays avec un filtre
documents.find("country", { "where": { "code": "us" } })

Renvoie :

[
  { "code": "us", "name": "États-Unis", "flag": "US" }
]

Traductions

CEL prend en charge la récupération de contenu traduit de deux maniÚres : traduction automatique basée sur la locale et recherche de traduction explicite.

Traduction automatique via meta.locale

Lorsque meta.locale est définie (par exemple à partir des paramÚtres de route ou des préférences utilisateur), documents.get() fusionne automatiquement le contenu traduit :

// Si meta.locale vaut "fr", renvoie la traduction française fusionnée avec le document de base
documents.get("greeting", "welcome").headline

Fonctionnement :

  1. RécupÚre le contenu du document de base
  2. Si meta.locale n'est pas "en" ou "en-US", recherche la traduction dans la table translations
  3. Fusionne les champs traduits avec le contenu de base : { ...baseContent, ...translatedContent }

Cela signifie que les champs traduits remplacent les champs de base, tandis que les champs non traduits reviennent au document d'origine.

Traduction explicite avec documents.translated()

Pour les cas oĂč vous devez rĂ©cupĂ©rer une traduction spĂ©cifique quel que soit la locale courante :

Syntaxe : documents.translated(schemaName, identifier, locale)

// Toujours récupérer la traduction espagnole
documents.translated("greeting", "welcome", "es").headline

// Récupérer la traduction en fonction du paramÚtre d'URL
documents.translated("product", meta.params.id, meta.params.lang).description

// Comparer des traductions
documents.translated("article", "intro", "en").title + " / " + documents.translated("article", "intro", "fr").title

Exemple de traduction

Vos documents de salutation avec traductions :

// Document de base : greeting / welcome
{ "headline": "Welcome", "subheadline": "Welcome to our platform" }

// Traduction (langue : "fr")
{ "headline": "Bienvenue", "subheadline": "Bienvenue sur notre plateforme" }

// Traduction (langue : "es")
{ "headline": "Bienvenido", "subheadline": "Bienvenido a nuestra plataforma" }

Scripts CEL :

// Avec meta.locale = "fr"
documents.get("greeting", "welcome").headline
// Renvoie : "Bienvenue"

// Traduction espagnole explicite
documents.translated("greeting", "welcome", "es").headline
// Renvoie : "Bienvenido"

// Patrons de repli en cas de traduction manquante
documents.translated("greeting", "welcome", meta.params.lang) != null
  ? documents.translated("greeting", "welcome", meta.params.lang).headline
  : documents.get("greeting", "welcome").headline

Exemples concrets

Exemple 1 : Titre de bloc héros depuis un autre document

Vous avez un hero-block qui doit afficher un titre provenant d'un document article.

Votre document article (identifiant : "homepage-hero") :

{
  "headline": "Construisez plus vite, livrez plus intelligemment",
  "subheadline": "Le CMS moderne pour les développeurs"
}

Script CEL dans le champ titre du bloc héros :

documents.get("article", "homepage-hero").headline

Résultat : le héros affiche "Construisez plus vite, livrez plus intelligemment"


Exemple 2 : Nom du pays Ă  partir du code

Vous construisez une page Ă  /countries/[code] et souhaitez afficher le nom complet du pays.

Vos documents de pays :

// country / us
{ "code": "us", "name": "États-Unis", "flag": "US", "languages": ["en", "es"] }

// country / sa
{ "code": "sa", "name": "Arabie saoudite", "flag": "SA", "languages": ["ar", "en"] }

Script CEL :

documents.get("country", meta.params.code).name

Quand quelqu'un visite /countries/us :

  • meta.params.code = "us"
  • RĂ©sultat : "États-Unis"

Quand quelqu'un visite /countries/sa :

  • meta.params.code = "sa"
  • RĂ©sultat : "Arabie saoudite"

Exemple 3 : Contenu conditionnel en fonction de la locale

Afficher des titres différents selon la locale de l'utilisateur.

meta.locale == "ar-SA" ? "Bienvenue Ă  tous" : "Bienvenue"

Si la locale est "ar-SA" : renvoie "Bienvenue Ă  tous" Si la locale est autre : renvoie "Bienvenue"


Exemple 4 : ChaĂźnage de recherches de documents

Votre article possĂšde un champ countryCode, et vous voulez obtenir le nom complet du pays.

Document article :

{ "headline": "ActualitĂ©s des États-Unis", "countryCode": "us" }

Script CEL :

documents.get("country", documents.get("article", "us-news").countryCode).name

Ce qui se passe :

  1. documents.get("article", "us-news") renvoie { "headline": "ActualitĂ©s des États-Unis", "countryCode": "us" }
  2. .countryCode extrait "us"
  3. documents.get("country", "us") renvoie { "code": "us", "name": "États-Unis", ... }
  4. .name extrait "États-Unis"

RĂ©sultat : "États-Unis"


Exemple 5 : Valeurs de repli

Si un document peut ne pas exister, vous pouvez fournir une valeur de repli :

documents.get("article", meta.params.slug) != null
  ? documents.get("article", meta.params.slug).headline
  : "Article introuvable"

Ou vérifier si un champ spécifique existe :

documents.get("article", "intro").author != null
  ? documents.get("article", "intro").author
  : "Auteur inconnu"

Exemple 6 : Travailler avec des listes

Votre article possÚde des tags et vous voulez vérifier si un tag spécifique existe :

"featured" in documents.get("article", "welcome-post").tags

Renvoie : true si l'article possĂšde le tag "featured"

Obtenir le premier tag :

documents.get("article", "welcome-post").tags[0]

Renvoie : "annonce" (le premier tag)

Compter les tags :

size(documents.get("article", "welcome-post").tags)

Renvoie : 2 (nombre de tags)


Routes paramétriques et meta.params

Les routes paramétriques sont la clé pour construire des pages dynamiques et localisées. Lorsque vous définissez un motif de route comme /{lang}/landingPage, le CMS extrait les paramÚtres de l'URL et les rend disponibles via meta.params.

Fonctionnement des paramĂštres de route

Définition de motif de route : Les routes utilisent la syntaxe :paramName ou {paramName} pour définir des segments dynamiques :

MotifExemple d'URLParamĂštres extraits
/:lang/landingPage/ko/landingPage{ lang: "ko" }
/{country}/{lang}/products/us/en/products{ country: "us", lang: "en" }
/articles/:slug/articles/welcome-post{ slug: "welcome-post" }

Liaisons de paramĂštres : Chaque paramĂštre de route peut ĂȘtre liĂ© Ă  un schĂ©ma de document pour validation :

{
  "pattern": "/{lang}/landingPage",
  "param_bindings": {
    "lang": "language"
  }
}

Cette liaison indique au CMS :

  1. Extraire le segment lang de l'URL
  2. Le valider par rapport au schĂ©ma language (recherche d'un document oĂč content.code correspond)
  3. Si c'est valide, mettre le document complet à disposition dans les paramÚtres résolus

Exemple : page d'accueil selon la langue

Configuration de la route :

  • Chemin : /{lang}/landingPage
  • Motif : /{lang}/landingPage
  • Liaisons de paramĂštres : { "lang": "language" }

Vos documents de salutation :

// greeting / ko
{ "code": "ko", "headline": "Welcome", "subheadline": "Welcome to our platform", "ctaText": "Get Started", "ctaUrl": "/ko/get-started" }

// greeting / en
{ "code": "en", "headline": "Welcome", "subheadline": "Welcome to our platform", "ctaText": "Get Started", "ctaUrl": "/en/get-started" }

// greeting / ja
{ "code": "ja", "headline": "Welcome", "subheadline": "Welcome to our platform", "ctaText": "Start", "ctaUrl": "/ja/get-started" }

Script CEL pour récupérer le contenu localisé :

documents.get("greeting", meta.params.lang).headline

Comment cela se résout :

URLmeta.params.langRésultat
/ko/landingPage"ko""Welcome"
/en/landingPage"en""Welcome"
/ja/landingPage"ja""Welcome"

Motif avancé : routes pays + langue

Pour des routes comme /{country}/{lang}/products :

Configuration de la route :

{
  "pattern": "/{country}/{lang}/products",
  "param_bindings": {
    "country": "country",
    "lang": "language"
  }
}

Scripts CEL :

// Obtenir le nom du pays
documents.get("country", meta.params.country).name

// Obtenir la liste des produits localisée selon le pays
documents.find("product", { "where": { "country": meta.params.country } })

// Combiné : afficher une salutation spécifique au pays dans la langue de l'utilisateur
documents.get("greeting", meta.params.lang).headline + " depuis " + documents.get("country", meta.params.country).name

Cascade de validation : Le CMS valide les paramÚtres hiérarchiquement. Pour les routes /{country}/{lang} :

  1. Valide le paramÚtre country par rapport au schéma country
  2. Valide le paramÚtre lang par rapport au schéma language
  3. Valide éventuellement que lang figure dans le tableau country.languages[] (validation hiérarchique)

meta.segments - accĂšs brut au chemin d'URL

meta.segments fournit le chemin brut de l'URL sous forme de tableau, utile lorsque vous avez besoin d'un accÚs positionnel sans paramÚtres nommés.

Fonctionnement :

Chemin d'URLmeta.segments
/articles/tech/ai-news["articles", "tech", "ai-news"]
/ko/landingPage["ko", "landingPage"]
/us/en/products/featured["us", "en", "products", "featured"]
/[]

Quand utiliser meta.segments vs meta.params

Cas d'usageMeilleure approche
ParamÚtres nommés provenant du motif de routemeta.params.lang
AccÚs basé sur la positionmeta.segments[0]
Obtenir la profondeur du cheminsize(meta.segments)
Vérifier si le chemin contient un segment"admin" in meta.segments

Exemples avec meta.segments

// Obtenir le premier segment (souvent le code langue)
meta.segments[0]

// Vérifier la profondeur du chemin
size(meta.segments) > 2 ? "profond" : "peu profond"

// Vérifier si nous sommes dans la section admin
"admin" in meta.segments ? "mode admin" : "mode public"

// Repli : utiliser le segment si le paramÚtre n'est pas lié
has(meta.params.lang) ? meta.params.lang : meta.segments[0]

Référence complÚte de l'objet meta

L'objet meta contient tout le contexte concernant la requĂȘte en cours :

PropriétéTypeDescription
meta.localestringCode de locale courant (par ex. "en-US", "ko-KR", "ar-SA")
meta.paramsRecord<string, string>ParamĂštres de route extraits du motif d'URL
meta.segmentsstring[]Chemin d'URL scindé en segments
meta.docIdstring \| nullUUID du document courant (null pour un nouveau document)
meta.titlestringTitre du document courant

meta.locale

Le code de locale suit le format BCP 47 (langue-région) :

// Vérifier la locale pour les langues RTL
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"

// Obtenir uniquement la partie langue
meta.locale.split("-")[0]  // Non pris en charge - utilisez plutĂŽt meta.params.lang

meta.params

Les paramÚtres de route sont toujours des chaßnes de caractÚres. Le CMS les valide par rapport aux schémas liés avant l'évaluation :

// Accéder à un paramÚtre nommé
meta.params.lang           // "ko"
meta.params.country        // "us"
meta.params.slug           // "welcome-post"

// Vérifier si un paramÚtre existe
has(meta.params.category)  // true/false

// Utiliser lors d'une récupération de document
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)

meta.segments

Segments bruts de l'URL sous forme de tableau :

// Accéder par index (à partir de 0)
meta.segments[0]           // Premier segment
meta.segments[1]           // DeuxiĂšme segment

// Vérifier la longueur
size(meta.segments)        // Nombre de segments

// Vérifier la présence
"products" in meta.segments  // Le chemin contient-il "products" ?

meta.docId

L'UUID du document courant, utile pour des scripts auto-référentiels :

// Disponible uniquement lors de l'édition d'un document existant
meta.docId != null ? "édition" : "création"

// Utiliser dans une logique conditionnelle
meta.docId != null ? documents.get("article", meta.docId).status : "draft"

meta.title

Le titre du document courant :

// Utiliser pour l'affichage
"Édition : " + meta.title

// Condition basé sur le titre
meta.title.contains("Draft") ? "travail en cours" : "publié"

documents.ref() - recherches chaßnées

Pour une syntaxe plus claire lorsque le schéma est connu mais que l'identifiant est dynamique :

// Approche traditionnelle
documents.get("airports", meta.params.code).name

// Avec ref() - schéma séparé de l'identifiant dynamique
documents.ref("airports").get(meta.params.code).name

Les deux sont équivalents, mais ref() met davantage en évidence la partie dynamique.


Aide-mémoire

Récupération de documents

documents.get("schema", "identifier")       // Récupérer un document
documents.get("schema", "id").fieldName     // Récupérer un champ spécifique
documents.find("schema")                    // Récupérer tous les documents
documents.find("schema", { "where": {...}}) // RequĂȘte filtrĂ©e
documents.ref("schema").get(identifier)     // Recherche chaßnée
documents.translated("schema", "id", "fr")  // Récupération avec locale explicite

Variables de contexte

meta.locale          // "en-US", "ar-SA", etc.
meta.params.xyz      // ParamÚtre d'URL nommé "xyz"
meta.segments        // Chemin d'URL sous forme de tableau : ["articles", "intro"]
meta.segments[0]     // Premier segment du chemin
meta.docId           // ID du document courant (ou null)
meta.title           // Titre du document courant
doc.fieldName        // Valeur du champ du document courant (en contexte éditeur)

Opérateurs

// Comparaison
==  !=  <  <=  >  >=

// Logique
&&  ||  !

// Ternaires (if-else)
condition ? valeurSiVrai : valeurSiFaux

// Appartenance
"value" in listOrMap

Fonctions courantes

size(list)                    // Compter les éléments
size(string)                  // Longueur d'une chaĂźne
"text".startsWith("te")       // true
"text".endsWith("xt")         // true
"text".contains("ex")         // true
has(object.property)          // Vérifier si la propriété existe
hasProperty(obj, "key")       // Vérifier si l'objet possÚde la clé (syntaxe alternative)

Messages d'erreur

Si quelque chose se passe mal, vous verrez l'un de ceux-ci :

ErreurSignification
SYNTAX_ERRORUne faute de frappe dans votre script (guillemet manquant, opérateur incorrect)
TYPE_ERRORVous mélangez des types incompatibles
RUNTIME_ERRORLe script s'est exécuté mais a rencontré un problÚme (variable indéfinie)
FETCH_LIMIT_EXCEEDEDVous récupérez trop de documents (max 50)
TIMEOUTLe script a mis trop de temps (max 5 secondes)
AST_DEPTH_EXCEEDEDExpression trop imbriquée (profondeur max : 50)
SCRIPT_TOO_LONGLe script dépasse la limite de 5000 caractÚres

Extensibilité et capacités futures

Le moteur CEL est conçu pour ĂȘtre extensible. Les capacitĂ©s futures prĂ©vues incluent :

Prévu : intégration du serveur MCP

// Futur : appeler des services externes via MCP
mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)

Prévu : capacités IA

// Futur : génération de contenu assistée par IA
ai.summarize(documents.get("article", meta.params.id).body, 100)
ai.translate(meta.params.text, meta.params.targetLang)
ai.classify(meta.params.input, ["positive", "negative", "neutral"])

Ces capacités seront ajoutées via le systÚme de fonctions enregistrées, en maintenant la rétrocompatibilité avec les scripts existants.


Conseils

  1. Utilisez l'autocomplĂ©tion – Tapez documents. ou meta. et l'Ă©diteur affichera les options disponibles
  2. Commencez simple – Testez d'abord avec documents.get("schema", "id"), puis ajoutez .fieldName
  3. VĂ©rifiez les null – Si un document peut ne pas exister, ajoutez un repli avec != null ? ... : ...
  4. Ne sur-rĂ©cupĂ©rez pas – Chaque documents.get() ou documents.find() compte dans la limite de 50 rĂ©cupĂ©rations
  5. PrĂ©fĂ©rez meta.params Ă  meta.segments – Les paramĂštres nommĂ©s sont validĂ©s et plus fiables
  6. Utilisez has() pour les paramĂštres optionnels – VĂ©rifiez has(meta.params.category) avant d'y accĂ©der
  7. Utilisez documents.ref() pour les identifiants dynamiques – Syntaxe plus claire lorsque le schĂ©ma est fixe mais l'identifiant change
  8. Utilisez doc.fieldName pour les auto-rĂ©fĂ©rences – AccĂ©dez aux champs du document courant dans les expressions calculĂ©es

Références document à document

Cette section couvre des patrons avancés pour lier des documents entre eux et construire des structures de contenu relationnel.

Patron de référence basique

La forme la plus simple : un document référence un autre par identifiant.

// L'article stocke l'ID de l'auteur, récupérer le nom de l'auteur
documents.get("author", documents.get("article", "intro").authorId).name

ChaĂźnage de recherches avec documents.ref()

Pour une syntaxe plus claire lorsque l'identifiant est dynamique :

// Approche traditionnelle
documents.get("country", documents.get("airport", meta.params.code).countryCode).name

// Avec ref() - plus clair lorsque le schéma est connu mais l'identifiant est dynamique
documents.ref("country").get(documents.get("airport", meta.params.code).countryCode).name

Chaßnes de référence multi-niveaux

Construisez des relations profondes en chaĂźnant plusieurs recherches :

// AĂ©roport → Pays → RĂ©gion → Continent
documents.get("continent",
  documents.get("region",
    documents.get("country",
      documents.get("airport", meta.params.code).countryCode
    ).regionCode
  ).continentCode
).name

Référence avec traduction

Combinez références de documents et traductions :

// Obtenir le nom localisé du pays pour un aéroport
documents.translated("country",
  documents.get("airport", meta.params.code).countryCode,
  meta.params.lang
).name

Patrons de référence selon l'usage

Patron 1 : recherche par clé étrangÚre

Le document stocke un ID qui référence un autre document.

// article / tech-news
{ "title": "Mise Ă  jour tech", "authorId": "author-123", "categoryId": "cat-tech" }
// Résoudre le nom de l'auteur
documents.get("author", documents.get("article", meta.params.slug).authorId).name

// Résoudre la catégorie avec repli
documents.get("article", meta.params.slug).categoryId != null
  ? documents.get("category", documents.get("article", meta.params.slug).categoryId).name
  : "Sans catégorie"

Patron 2 : références basées sur un code

Les documents se référencent via des codes sémantiques plutÎt que des UUID.

// airport / JFK
{ "code": "JFK", "name": "John F. Kennedy International", "countryCode": "us" }

// country / us
{ "code": "us", "name": "États-Unis", "currencyCode": "usd" }

// currency / usd
{ "code": "usd", "symbol": "$", "name": "Dollar américain" }
// ChaĂźne AĂ©roport → Pays → Devise
documents.get("currency",
  documents.get("country",
    documents.get("airport", meta.params.code).countryCode
  ).currencyCode
).symbol
// Pour JFK : renvoie "$"

Patron 3 : auto-référence avec le contexte doc

Utilisez doc pour des champs calculés qui référencent d'autres documents en fonction des valeurs du document courant.

// Dans un document produit, récupérer les détails de la catégorie liée
documents.get("category", doc.categoryId).description

// Coût d'expédition calculé d'aprÚs le pays d'origine du produit
documents.get("shipping-rates", doc.originCountry).baseRate * doc.weight

Patron 4 : références bidirectionnelles

Lorsque des documents se référencent mutuellement, faites attention aux limites de récupération.

// Récupérer l'auteur de l'article, puis les autres articles de cet auteur (surveillez le nombre de fetch)
documents.find("article", { "where": { "authorId": documents.get("article", meta.params.slug).authorId } })

Patron 5 : références polymorphes

Lorsque qu'un champ peut référencer différents schémas :

// content-block / hero-1
{ "type": "hero", "sourceType": "article", "sourceId": "welcome-post" }

// content-block / hero-2
{ "type": "hero", "sourceType": "product", "sourceId": "featured-item" }
// Recherche de schéma dynamique selon sourceType
documents.get("content-block", "hero-1").sourceType == "article"
  ? documents.get("article", documents.get("content-block", "hero-1").sourceId).headline
  : documents.get("product", documents.get("content-block", "hero-1").sourceId).name

Suivi des dépendances

Chaque appel Ă  documents.get(), documents.find() et documents.ref().get() est suivi pour l'invalidation de cache. Lorsqu'un document rĂ©fĂ©rencĂ© change, le CMS sait quelles expressions CEL doivent ĂȘtre réévaluĂ©es.

Les dépendances suivies incluent :

  • get : schema:identifier – DĂ©pendance Ă  un document spĂ©cifique
  • ref : schema:identifier – Identique Ă  get, via la syntaxe chaĂźnĂ©e
  • query : schema:* – DĂ©pendance au niveau du schĂ©ma (tout document du schĂ©ma)

Bonnes pratiques pour les références

  1. RĂ©duisez la profondeur des chaĂźnes – Chaque niveau ajoute de la latence et des rĂ©cupĂ©rations
  2. Mettez en cache les rĂ©sultats intermĂ©diaires – Si vous avez besoin deux fois de la mĂȘme valeur imbriquĂ©e, rĂ©cupĂ©rez le parent une seule fois
  3. Utilisez des vĂ©rifications de null – Les rĂ©fĂ©rences peuvent casser si des documents sont supprimĂ©s
  4. PrĂ©fĂ©rez les codes aux UUID – Les codes sont lisibles dans les expressions et stables entre environnements
  5. Surveillez les limites de rĂ©cupĂ©ration – Les chaĂźnes complexes peuvent atteindre rapidement la limite de 50
// Mauvais : rĂ©cupĂšre le mĂȘme document deux fois
documents.get("author", documents.get("article", "intro").authorId).name + " - " +
documents.get("author", documents.get("article", "intro").authorId).bio

// Mieux : utilisez une condition pour vérifier une seule fois
documents.get("article", "intro").authorId != null
  ? documents.get("author", documents.get("article", "intro").authorId).name
  : "Auteur inconnu"

Annexe A : exemple complet de route paramétrique

Ce guide pas-à-pas crée une page de destination multilingue accessible à /{lang}/landingPage.

Étape 1 : crĂ©er le schĂ©ma de document Greeting

Dans l'administration du CMS, créez un schéma personnalisé nommé greeting :

{
  "name": "greeting",
  "fields": [
    { "name": "code", "type": "string", "required": true },
    { "name": "headline", "type": "string", "required": true },
    { "name": "subheadline", "type": "string" },
    { "name": "ctaText", "type": "string" },
    { "name": "ctaUrl", "type": "string" }
  ]
}

Étape 2 : crĂ©er les documents Greeting

Créez des documents pour chaque langue :

Document : greeting/ko

{
  "code": "ko",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Get Started",
  "ctaUrl": "/ko/get-started"
}

Document : greeting/en

{
  "code": "en",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Get Started",
  "ctaUrl": "/en/get-started"
}

Document : greeting/ja

{
  "code": "ja",
  "headline": "Welcome",
  "subheadline": "Welcome to our platform",
  "ctaText": "Start",
  "ctaUrl": "/ja/get-started"
}

Étape 3 : crĂ©er la page

Créez une page avec la configuration suivante :

  • Chemin/motif : /{lang}/landingPage
  • État : Live
  • Correspondances de segments dynamiques : lier lang → le composant language
  {
    "lang": "language"
  }

Étape 4 : ajouter des blocs avec des scripts CEL

Ajoutez un bloc héros à la route avec ces scripts CEL pour chaque champ :

Champ Headline :

documents.get("greeting", meta.params.lang).headline

Champ Subheadline :

documents.get("greeting", meta.params.lang).subheadline

Champ CTA Text :

documents.get("greeting", meta.params.lang).ctaText

Champ CTA URL :

documents.get("greeting", meta.params.lang).ctaUrl

Étape 5 : consommer dans Next.js

Ajoutez une route catch-all. ParametricRoutePage rĂ©sout la page, extrait meta.params depuis l'URL, Ă©value vos liaisons CEL cĂŽtĂ© serveur et rend chaque bloc via votre registre — vous n'avez pas Ă  construire le contexte meta ni Ă  appeler directement le client bas niveau.

// app/[...slug]/page.tsx
import ParametricRoutePage from 'cms-renderer/lib/renderer';
import { registry } from '@/lib/registry';
import { cmsConfig } from '@/lib/cms-config';

export const dynamic = 'force-static';

interface PageProps {
  params: Promise<{ slug: string[] }>;
}

export default async function Page({ params }: PageProps) {
  const { slug } = await params;

  return (
    <ParametricRoutePage
      registry={registry}
      apiKey={cmsConfig.apiKey}
      websiteId={cmsConfig.websiteId}
      cmsUrl={cmsConfig.cmsUrl}
      params={Promise.resolve({ slug })}
    />
  );
}

Étape 6 : tester les routes

Visitez ces URL pour voir le contenu localisé :

URLTitre attendu
/ko/landingPage환영
/en/landingPageWelcome
/ja/landingPageă„ă‚‰ăŁă—ă‚ƒă„ăŸă›

Comment se déroule la résolution

Lorsqu'un utilisateur visite /ko/landingPage :

  1. Correspondance de route : le CMS fait correspondre le motif /{lang}/landingPage
  2. Extraction des paramĂštres : meta.params.lang = "ko"
  3. Validation : le CMS vérifie que "ko" existe dans le schéma language
  4. Évaluation CEL : les scripts tels que documents.get("greeting", meta.params.lang) renvoient le contenu corĂ©en
  5. Réponse : les blocs localisés sont retournés au client

Annexe B : référence technique

Interface CelMeta (TypeScript)

interface CelMeta {
  /** Code de locale courant (par ex. 'en-US') */
  locale: string;
  /** ParamĂštres de route extraits de l'URL */
  params: Record<string, string>;
  /** Segments du chemin d'URL */
  segments: string[];
  /** ID du document courant (si édition d'un document existant) */
  docId: string | null;
  /** Titre du document courant */
  title: string;
}

Algorithme d'extraction des paramĂštres

La fonction extractParams traite les chemins d'URL :

Motif : /{country}/{lang}/products
Chemin : /us/en/products

Algorithme :
1. Normaliser les deux (supprimer les barres obliques finales)
2. Diviser en segments : ["us", "en", "products"] et ["{country}", "{lang}", "products"]
3. Faire correspondre le nombre de segments (doit ĂȘtre identique)
4. Pour chaque paire de segments :
   - Si le motif commence par : ou {}, extraire comme paramĂštre
   - Sinon, la correspondance doit ĂȘtre exacte
5. Retourner : { country: "us", lang: "en" }

Formats de liaison de paramĂštres pris en charge

// Liaison simple (utilise le champ "code" pour la recherche)
{ "lang": "language" }

// Liaison détaillée (champ slug personnalisé)
{
  "lang": {
    "schemaName": "language",
    "slugField": "code"
  },
  "slug": {
    "schemaName": "article",
    "slugField": "slug"
  }
}

Priorité de recherche de document

Lors d'une récupération via documents.get(schema, identifier) :

  1. Correspondance UUID : si l'identifiant est un UUID valide, récupération par id
  2. Champ code : vérifie le champ content.code
  3. Champ slug : vérifie le champ content.slug
  4. Correspondance de titre : vérifie le champ title

Cela permet des références de documents flexibles par n'importe quel identifiant unique.

Continue Reading
Previousâ€čInstall Profound CMS as a proxyNextProject Scaffoldingâ€ș