profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Hybrid

Collection of Pages with ComponentsTypes of ComponentsSetup server sent events (SSE) content refetchΡύθμιση διακομιστή μεσολάβησης πίνακα διαχείρισηςCEL Scripting in Template BuilderProject ScaffoldingΒιβλιοθήκη πολυμέσων

Χωρίς κεφαλή

Γρήγορη εκκίνησηjson και Claude κώδικαςComponent Zod Pull

REST API

επισκόπηση του REST APIgetConnect your websitegetGET /routesgetGET /routegetGET /blocksgetΛήψη μπλοκ με cel cachegetGET /blocks/generatedgetGET /componentsgetGET /components/{name}getΛήψη ονόματος σχήματος συνόλου δεδομένωνgetGET /content-changes (SSE)patchPATCH /dataset/{schema_name}postPOST /translationpatchPATCH /translationsgetGET /usagepostPOST /csvpatchPATCH /csv
All Systems Operational
Powered Byprofound-logo
Theme

CEL Scripting in Template Builder

Ένας πρακτικός οδηγός για τη σύνταξη εκφράσεων CEL στο CMS.

Ένας πρακτικός οδηγός για τη σύνταξη εκφράσεων CEL στο CMS.


Πώς λειτουργεί η CEL

Η CEL (Common Expression Language) είναι μια ελαφριά γλώσσα scripting ενσωματωμένη στο CMS μας. Σας επιτρέπει να γράφετε δυναμικές εκφράσεις που αντλούν δεδομένα από έγγραφα, διαβάζουν παραμέτρους URL και υπολογίζουν τιμές κατά την εκτέλεση.

Τι συμβαίνει όταν εκτελείται ένα script CEL:

Η CEL λειτουργεί σαν γλώσσα ερωτημάτων μόνο για ανάγνωση. Δεν μπορεί να τροποποιήσει τίποτα στη βάση δεδομένων· απλώς διαβάζει δεδομένα και επιστρέφει ένα υπολογισμένο αποτέλεσμα. Αυτό την καθιστά ασφαλή για χρήση οπουδήποτε στο CMS.


Τα βασικά δομικά στοιχεία

Κάθε έκφραση CEL έχει πρόσβαση σε τρία πράγματα:

ΑντικείμενοΤι είναιΠαράδειγμα
documentsΑνάκτηση οποιουδήποτε εγγράφου από το CMSdocuments.get("country", "us")
metaΠληροφορίες για το τρέχον αίτημα (τοπικές ρυθμίσεις, παράμετροι URL)meta.locale, meta.params.slug
schemaΟι ορισμοί πεδίων του τρέχοντος εγγράφουschema.fields

Αναφορά στον εαυτό του με το doc

Όταν γράφετε εκφράσεις CEL μέσα σε έναν επεξεργαστή εγγράφων, μπορείτε να αποκτήσετε πρόσβαση στις τιμές των πεδίων του τρέχοντος εγγράφου χρησιμοποιώντας το αντικείμενο doc. Αυτό επιτρέπει υπολογιζόμενα πεδία και αναφορές μεταξύ πεδίων.

Το αντικείμενο doc περιέχει όλες τις τιμές πεδίων του εγγράφου που επεξεργάζεστε. Είναι χρήσιμο για:

  • Υπολογιζόμενα πεδία (π.χ. doc.price * doc.quantity)
  • Λογική conditional εμφάνισης με βάση την κατάσταση του εγγράφου
  • Εκφράσεις τύπου επικύρωσης

Ανάκτηση εγγράφων

Η ισχυρότερη δυνατότητα της CEL είναι η ανάκτηση εγγράφων από οπουδήποτε στο CMS.

Λήψη ενός εγγράφου

Σύνταξη: documents.get(schemaName, identifier)

Αν έχετε ένα έγγραφο article αποθηκευμένο με αναγνωριστικό "welcome-post", μπορείτε να το ανακτήσετε ως εξής:

Για ανάκτηση ολόκληρου του εγγράφου:

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

Για ανάκτηση μόνο του τίτλου:

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

Χρήση παραμέτρων URL

Όταν η σελίδα σας διαθέτει δυναμικές διαδρομές, όπως /articles/[slug], μπορείτε να χρησιμοποιήσετε το meta.params για να λάβετε την παράμετρο URL και να ανακτήσετε το σωστό έγγραφο.

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

Έτσι δημιουργείτε δυναμικές σελίδες: το ίδιο script CEL λειτουργεί για κάθε άρθρο, χρησιμοποιώντας το slug που υπάρχει στη διεύθυνση URL.


Ανάκτηση πολλών εγγράφων

Σύνταξη: documents.find(schemaName) ή documents.find(schemaName, filter)

// Λήψη όλων των χωρών
documents.find("country")
// Λήψη χωρών με φίλτρο
documents.find("country", { "where": { "code": "us" } })

Μεταφράσεις

Η CEL υποστηρίζει την ανάκτηση μεταφρασμένου περιεχομένου εγγράφων με δύο τρόπους: αυτόματη μετάφραση βάσει τοπικών ρυθμίσεων και ρητή αναζήτηση μετάφρασης.

Αυτόματη μετάφραση μέσω του meta.locale

Όταν έχει οριστεί το meta.locale (για παράδειγμα από παραμέτρους διαδρομής ή προτιμήσεις χρήστη), η documents.get() συγχωνεύει αυτόματα το μεταφρασμένο περιεχόμενο:

// Αν το meta.locale είναι "fr", επιστρέφει τη γαλλική μετάφραση συγχωνευμένη με το βασικό έγγραφο
documents.get("greeting", "welcome").headline

Πώς λειτουργεί:

  1. Ανακτά το περιεχόμενο του βασικού εγγράφου
  2. Αν το meta.locale δεν είναι "en" ή "en-US", αναζητά τη μετάφραση στον πίνακα translations
  3. Συγχωνεύει τα μεταφρασμένα πεδία πάνω από το βασικό περιεχόμενο

Τα μεταφρασμένα πεδία αντικαθιστούν τα βασικά πεδία, ενώ τα πεδία χωρίς μετάφραση χρησιμοποιούν το βασικό έγγραφο.

Ρητή μετάφραση με documents.translated()

Όταν χρειάζεται να ανακτήσετε μια συγκεκριμένη μετάφραση ανεξάρτητα από την τρέχουσα τοπική ρύθμιση:

Σύνταξη: documents.translated(schemaName, identifier, locale)

// Πάντα ανάκτηση της ισπανικής μετάφρασης
documents.translated("greeting", "welcome", "es").headline

// Ανάκτηση μετάφρασης βάσει παραμέτρου URL
documents.translated("product", meta.params.id, meta.params.lang).description

// Σύγκριση μεταφράσεων
documents.translated("article", "intro", "en").title + " / " + documents.translated("article", "intro", "fr").title

Παραδείγματα από τον πραγματικό κόσμο

Παράδειγμα 1: Τίτλος hero block από άλλο έγγραφο

Έχετε ένα hero-block που πρέπει να εμφανίζει έναν τίτλο από ένα έγγραφο article.

Το script CEL στο πεδίο τίτλου του hero block είναι:

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

Αποτέλεσμα: Το hero εμφανίζει τον αντίστοιχο τίτλο.


Παράδειγμα 2: Όνομα χώρας από κωδικό

Δημιουργείτε μια σελίδα στη διεύθυνση /countries/[code] και θέλετε να εμφανίσετε το πλήρες όνομα της χώρας.

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

Όταν κάποιος επισκέπτεται το /countries/us, το meta.params.code είναι "us" και το αποτέλεσμα είναι το όνομα της χώρας.


Παράδειγμα 3: Conditional περιεχόμενο βάσει τοπικής ρύθμισης

Εμφανίστε διαφορετικούς τίτλους ανάλογα με την τοπική ρύθμιση του χρήστη:

meta.locale == "ar-SA" ? "Welcome, everyone" : "Welcome"

Παράδειγμα 4: Αλυσιδωτές αναζητήσεις εγγράφων

Αν το article διαθέτει πεδίο countryCode και θέλετε να λάβετε το πλήρες όνομα της χώρας:

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

Οι αναζητήσεις μπορούν να συνδυάζονται, ώστε το αποτέλεσμα ενός εγγράφου να χρησιμοποιείται ως αναγνωριστικό για την ανάκτηση του επόμενου.


Παράδειγμα 5: Εφεδρικές τιμές

Αν ένα έγγραφο μπορεί να μην υπάρχει, μπορείτε να παρέχετε εφεδρική τιμή:

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

Μπορείτε επίσης να ελέγξετε αν υπάρχει ένα συγκεκριμένο πεδίο:

documents.get("article", "intro").author != null
  ? documents.get("article", "intro").author
  : "Unknown Author"

Παράδειγμα 6: Εργασία με λίστες

Για να ελέγξετε αν υπάρχει μια συγκεκριμένη ετικέτα:

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

Επιστρέφει true αν το άρθρο έχει την ετικέτα.

Για να λάβετε την πρώτη ετικέτα:

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

Για να μετρήσετε τις ετικέτες:

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

Παραμετρικές διαδρομές και meta.params

Οι παραμετρικές διαδρομές είναι το κλειδί για τη δημιουργία δυναμικών, πολυγλωσσικών σελίδων. Όταν ορίζετε ένα μοτίβο διαδρομής όπως /{lang}/landingPage, το CMS εξάγει τις παραμέτρους από τη διεύθυνση URL και τις διαθέτει μέσω του meta.params.

Πώς λειτουργούν οι παράμετροι διαδρομής

Οι διαδρομές χρησιμοποιούν τη σύνταξη :paramName ή {paramName} για τον ορισμό δυναμικών τμημάτων. Κάθε παράμετρος μπορεί να συνδεθεί με ένα schema εγγράφου για επικύρωση.

Η σύνδεση ενημερώνει το CMS να εξαγάγει το τμήμα από το URL, να το επικυρώσει στο αντίστοιχο schema και, αν είναι έγκυρο, να διαθέσει ολόκληρο το έγγραφο στις επιλυμένες παραμέτρους.

Παράδειγμα: Σελίδα προορισμού βάσει γλώσσας

Διαμόρφωση διαδρομής:

  • Διαδρομή: /{lang}/landingPage
  • Μοτίβο: /{lang}/landingPage
  • Συνδέσεις παραμέτρων: { "lang": "language" }

Script CEL για ανάκτηση τοπικοποιημένου περιεχομένου:

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

meta.segments — Πρόσβαση στη μη επεξεργασμένη διαδρομή URL

Το meta.segments παρέχει τη μη επεξεργασμένη διαδρομή URL ως πίνακα και είναι χρήσιμο όταν χρειάζεστε πρόσβαση βάσει θέσης χωρίς ονομασμένες παραμέτρους.

Πότε να χρησιμοποιείτε meta.segments αντί για meta.params

Περίπτωση χρήσηςΚαλύτερη προσέγγιση
Ονομασμένες παράμετροι από το μοτίβο διαδρομήςmeta.params.lang
Πρόσβαση βάσει θέσηςmeta.segments[0]
Λήψη του βάθους της διαδρομήςsize(meta.segments)
Έλεγχος αν η διαδρομή περιέχει ένα τμήμα"admin" in meta.segments

Παραδείγματα με meta.segments

// Λήψη του πρώτου τμήματος
meta.segments[0]

// Έλεγχος βάθους διαδρομής
size(meta.segments) > 2 ? "deep" : "shallow"

// Έλεγχος αν βρισκόμαστε στην ενότητα διαχείρισης
"admin" in meta.segments ? "admin mode" : "public mode"

// Εφεδρική λύση: χρήση τμήματος αν η παράμετρος δεν είναι συνδεδεμένη
has(meta.params.lang) ? meta.params.lang : meta.segments[0]

Πλήρης αναφορά του αντικειμένου meta

Το αντικείμενο meta περιέχει όλο το περιβάλλον του τρέχοντος αιτήματος:

ΙδιότηταΤύποςΠεριγραφή
meta.localestringΚωδικός τρέχουσας τοπικής ρύθμισης
meta.paramsRecord<string, string>Παράμετροι διαδρομής που εξάγονται από το URL
meta.segmentsstring[]Η διαδρομή URL χωρισμένη σε τμήματα
meta.docIdstring | nullUUID του τρέχοντος εγγράφου
meta.titlestringΤίτλος του τρέχοντος εγγράφου

meta.locale

Ο κωδικός τοπικής ρύθμισης ακολουθεί τη μορφή BCP 47:

// Έλεγχος τοπικών ρυθμίσεων για γλώσσες RTL
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"

meta.params

Οι παράμετροι διαδρομής είναι πάντα συμβολοσειρές. Το CMS τις επικυρώνει έναντι των συνδεδεμένων schema πριν από την αξιολόγηση:

// Πρόσβαση σε ονομασμένη παράμετρο
meta.params.lang
meta.params.country
meta.params.slug

// Έλεγχος αν υπάρχει παράμετρος
has(meta.params.category)

// Χρήση σε ανάκτηση εγγράφου
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)

meta.docId

Το UUID του τρέχοντος εγγράφου, χρήσιμο για scripts που αναφέρονται στο ίδιο το έγγραφο:

meta.docId != null ? "editing" : "creating new"
meta.docId != null ? documents.get("article", meta.docId).status : "draft"

meta.title

Ο τίτλος του τρέχοντος εγγράφου:

"Editing: " + meta.title
meta.title.contains("Draft") ? "work in progress" : "published"

documents.ref() — Αλυσιδωτές αναζητήσεις

Για καθαρότερη σύνταξη όταν το schema είναι γνωστό αλλά το αναγνωριστικό είναι δυναμικό:

// Παραδοσιακή προσέγγιση
documents.get("airports", meta.params.code).name

// Χρήση ref()
documents.ref("airports").get(meta.params.code).name

Και οι δύο τρόποι είναι ισοδύναμοι, αλλά το ref() κάνει το δυναμικό μέρος πιο σαφές.


Γρήγορη αναφορά

Ανάκτηση εγγράφων

documents.get("schema", "identifier")
documents.get("schema", "id").fieldName
documents.find("schema")
documents.find("schema", { "where": {...}})
documents.ref("schema").get(identifier)
documents.translated("schema", "id", "fr")

Μεταβλητές περιβάλλοντος

meta.locale
meta.params.xyz
meta.segments
meta.segments[0]
meta.docId
a.meta.title
doc.fieldName

Τελεστές

==  !=  <  <=  >  >=
&&  ||  !
condition ? valueIfTrue : valueIfFalse
"value" in listOrMap

Συνηθισμένες συναρτήσεις

size(list)
size(string)
"text".startsWith("te")
"text".endsWith("xt")
"text".contains("ex")
has(object.property)
hasProperty(obj, "key")

Μηνύματα σφάλματος

Αν κάτι πάει στραβά, θα δείτε ένα από τα εξής:

ΣφάλμαΤι σημαίνει
SYNTAX_ERRORΤυπογραφικό λάθος στο script σας
TYPE_ERRORΣυνδυάζετε τύπους που δεν είναι συμβατοί
RUNTIME_ERRORΤο script εκτελέστηκε αλλά αντιμετώπισε πρόβλημα
FETCH_LIMIT_EXCEEDEDΑνακτάτε πάρα πολλά έγγραφα (μέγιστο 50)
TIMEOUTΤο script χρειάστηκε υπερβολικά πολύ χρόνο (μέγιστο 5 δευτερόλεπτα)
AST_DEPTH_EXCEEDEDΗ έκφραση είναι υπερβολικά ένθετη
SCRIPT_TOO_LONGΤο script υπερβαίνει το όριο των 5.000 χαρακτήρων

Επεκτασιμότητα και μελλοντικές δυνατότητες

Η μηχανή CEL έχει σχεδιαστεί για επεκτασιμότητα. Οι μελλοντικές δυνατότητες περιλαμβάνουν:

Προγραμματισμένο: Ενσωμάτωση διακομιστή MCP

mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)

Προγραμματισμένο: Δυνατότητες AI

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"])

Οι δυνατότητες αυτές θα προστεθούν μέσω του συστήματος καταχωρισμένων συναρτήσεων, διατηρώντας τη συμβατότητα με τα υπάρχοντα scripts.


Συμβουλές

  1. Χρησιμοποιήστε την αυτόματη συμπλήρωση — Πληκτρολογήστε documents. ή meta. για να δείτε τις διαθέσιμες επιλογές
  2. Ξεκινήστε απλά — Δοκιμάστε πρώτα documents.get("schema", "id") και έπειτα προσθέστε .fieldName
  3. Ελέγχετε για null — Αν ένα έγγραφο μπορεί να μην υπάρχει, προσθέστε εφεδρική τιμή
  4. Μην ανακτάτε υπερβολικά πολλά δεδομένα — Κάθε documents.get() ή documents.find() μετρά στο όριο των 50 ανακτήσεων
  5. Προτιμήστε το meta.params έναντι του meta.segments — Οι ονομασμένες παράμετροι επικυρώνονται και είναι πιο αξιόπιστες
  6. Χρησιμοποιήστε has() για προαιρετικές παραμέτρους — Ελέγξτε την ύπαρξη πριν από την πρόσβαση
  7. Χρησιμοποιήστε documents.ref() για δυναμικά αναγνωριστικά — Προσφέρει σαφέστερη σύνταξη
  8. Χρησιμοποιήστε doc.fieldName για αναφορές στο ίδιο έγγραφο — Αποκτήστε πρόσβαση στα πεδία του τρέχοντος εγγράφου

Αναφορές από έγγραφο σε έγγραφο

Αυτή η ενότητα καλύπτει προηγμένα μοτίβα σύνδεσης εγγράφων και δημιουργίας σχεσιακών δομών περιεχομένου.

Βασικό μοτίβο αναφοράς

Η απλούστερη μορφή είναι ένα έγγραφο να αναφέρεται σε άλλο μέσω αναγνωριστικού:

documents.get("author", documents.get("article", "intro").authorId).name

Αλυσιδωτές αναζητήσεις με documents.ref()

Όταν το αναγνωριστικό είναι δυναμικό:

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

Αλυσίδες αναφορών πολλών επιπέδων

Μπορείτε να δημιουργήσετε βαθιές σχέσεις συνδυάζοντας πολλές αναζητήσεις. Να λαμβάνετε υπόψη την καθυστέρηση και το όριο των 50 ανακτήσεων.

Αναφορά με μετάφραση

documents.translated("country",
  documents.get("airport", meta.params.code).countryCode,
  meta.params.lang
).name

Παρακολούθηση εξαρτήσεων

Κάθε κλήση documents.get(), documents.find() και documents.ref().get() παρακολουθείται για ακύρωση της cache. Όταν αλλάζει ένα έγγραφο που αναφέρεται, το CMS γνωρίζει ποιες εκφράσεις CEL πρέπει να αξιολογηθούν ξανά.

Βέλτιστες πρακτικές για αναφορές

  1. Περιορίστε το βάθος των αλυσίδων — Κάθε επίπεδο αυξάνει την καθυστέρηση και τον αριθμό ανακτήσεων
  2. Αποθηκεύστε ενδιάμεσα αποτελέσματα στην cache — Μην ανακτάτε δύο φορές την ίδια τιμή
  3. Χρησιμοποιήστε ελέγχους null — Οι αναφορές μπορεί να αποτύχουν αν διαγραφούν έγγραφα
  4. Προτιμήστε κωδικούς αντί για UUID — Είναι πιο ευανάγνωστοι και σταθεροί
  5. Παρακολουθείτε τα όρια ανακτήσεων — Πολύπλοκες αλυσίδες μπορούν γρήγορα να φτάσουν το όριο των 50

Παράρτημα A: Πλήρες παράδειγμα παραμετρικής διαδρομής

Αυτός ο οδηγός δημιουργεί μια πολύγλωσση σελίδα προορισμού διαθέσιμη στη διεύθυνση /{lang}/landingPage.

Βήμα 1: Δημιουργία schema εγγράφου Greeting

Στη διαχείριση του CMS δημιουργήστε ένα προσαρμοσμένο schema με το όνομα greeting, με πεδία code, headline, subheadline, ctaText και ctaUrl.

Βήμα 2: Δημιουργία εγγράφων Greeting

Δημιουργήστε ένα έγγραφο για κάθε γλώσσα, όπως greeting/ko, greeting/en και greeting/ja.

Βήμα 3: Δημιουργία σελίδας

Δημιουργήστε μια σελίδα με τη διαμόρφωση:

  • Διαδρομή/Μοτίβο: /{lang}/landingPage
  • Κατάσταση: Ενεργή
  • Αντιστοιχίσεις δυναμικών τμημάτων: αντιστοίχιση lang στο στοιχείο language

Βήμα 4: Προσθήκη blocks με scripts CEL

Προσθέστε ένα hero block στη διαδρομή με τα ακόλουθα scripts CEL:

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

Βήμα 5: Χρήση στο Next.js

Προσθέστε μια catch-all διαδρομή. Το ParametricRoutePage επιλύει τη σελίδα, εξάγει το meta.params από το URL, αξιολογεί τις συνδέσεις CEL στην πλευρά του διακομιστή και αποδίδει κάθε block μέσω του registry.

Βήμα 6: Έλεγχος των διαδρομών

Επισκεφθείτε τις διευθύνσεις URL για να δείτε το τοπικοποιημένο περιεχόμενο:

URLΑναμενόμενος τίτλος
/ko/landingPage환영
/en/landingPageΚαλώς ήρθατε
/ja/landingPageいらっしゃいませ

Πώς λειτουργεί η επίλυση

Όταν ένας χρήστης επισκέπτεται το /ko/landingPage:

  1. Αντιστοίχιση διαδρομής: Το CMS αντιστοιχίζει το μοτίβο /{lang}/landingPage
  2. Εξαγωγή παραμέτρου: meta.params.lang = "ko"
  3. Επικύρωση: Το CMS επικυρώνει ότι το "ko" υπάρχει στο schema language
  4. Αξιολόγηση CEL: Τα scripts επιλύονται στο κορεατικό περιεχόμενο
  5. Απόκριση: Τα τοπικοποιημένα blocks επιστρέφονται στον client

Παράρτημα B: Τεχνική αναφορά

Διεπαφή CelMeta (TypeScript)

Η διεπαφή περιλαμβάνει τις ιδιότητες locale, params, segments, docId και title, οι οποίες αντιστοιχούν στο περιβάλλον της τρέχουσας αίτησης.

Αλγόριθμος εξαγωγής παραμέτρων

Η συνάρτηση extractParams επεξεργάζεται τις διαδρομές URL: κανονικοποιεί τις διαδρομές, τις χωρίζει σε τμήματα, συγκρίνει τον αριθμό τμημάτων, εξάγει τα δυναμικά τμήματα ως παραμέτρους και επιστρέφει το αποτέλεσμα.

Υποστηριζόμενες μορφές σύνδεσης παραμέτρων

{ "lang": "language" }

{
  "lang": {
    "schemaName": "language",
    "slugField": "code"
  },
  "slug": {
    "schemaName": "article",
    "slugField": "slug"
  }
}

Προτεραιότητα αναζήτησης εγγράφων

Κατά την ανάκτηση μέσω documents.get(schema, identifier):

  1. Αντιστοίχιση UUID: Αν το αναγνωριστικό είναι έγκυρο UUID, γίνεται ανάκτηση μέσω id
  2. Πεδίο code: Ελέγχεται το πεδίο content.code
  3. Πεδίο slug: Ελέγχεται το πεδίο content.slug
  4. Αντιστοίχιση τίτλου: Ελέγχεται το πεδίο title

Αυτό επιτρέπει ευέλικτες αναφορές σε έγγραφα μέσω οποιουδήποτε μοναδικού αναγνωριστικού.

Continue Reading
Previous‹Ρύθμιση διακομιστή μεσολάβησης πίνακα διαχείρισηςNextProject Scaffolding›