Information
Cette page n’est pas disponible dans la langue demandée. Elle est affichée dans la langue par défaut.

Framework PHP + Project hôte

Documentation globale v1.0.0 (janv. 2026)

Résumé de l’architecture, l’arborescence, la config et le fonctionnement global du framework natora-core et du projet hôte.

Vue d’ensemble Arborescences Configuration Cycle requête Routing & i18n Views (Smarty) JSON & validations Sécurité Modules Pages CMS Mails Logs Dev/Deploy Rôles & permissions Admin (roles/permissions)

1) Vue d’ensemble

Objectif

natora-core fournit le socle commun : Kernel, Container, Router, Request/Response, i18n, Smarty, sécurité, mailer, logging.

Project contient les routes/pages/features spécifiques au site, surcharge certains services (ex: mailer SMTP), et ajoute ses templates et traductions.

Principes de design (v1.0.0)

  • Contrats simples
    validations JSON uniques, comportements prédictibles.
  • Locale canonique
    URL préfixée /fr, /en, etc (canonicalisation dans le Router).
  • Sécurité centralisée
    CSP (nonce), headers, CSRF, throttling.
  • Surcharge propre
    le projet remplace/étend via le Container, sans “fork” du core.

Composants majeurs

Composant Rôle Notes
Kernel Boot + pipeline middleware + dispatch route + réponse Applique headers sécurité, gère mode prod/dev
Container DI : services & factories Core + Project registrars, surcharges possibles côté Project
Router Routes + canonicalisation locale Les contrôleurs retournent des paths neutres (/profile), le Router applique la locale
I18n Résolution langue + dictionnaires Pages : common.php + {page}.php. Mails : mails.php
View (Smarty 5) Rendu templates pages & emails Globals garantis : APP, CURRENT_YEAR, dictionnaire i18n (TXT_*)
Security Auth, CSRF, remember-me, throttling, anti-spam Remember-me selector/validator, throttles login + pwreset, contact spam guard
Mail Envoi activation / reset / contact PHPMailer, templates HTML+TXT
Logging PSR-3 + access log Unifié : logger.core et logger.project avec préfixes

2) Arborescences (core + project)

2.1. natora-core (package Composer)

vendor/ natora/ natora-core/ src/ Kernel.php Container/... Routing/... Http/... View/... I18n/... Security/... Mail/... Database/... Modules/... config/ app.php paths.php security.php logging.php mail.php form.php view.php i18n/ fr/ common.php auth.php profile.php admin.php mails.php en/ ... storage/ templates/ layouts/ pages/ mails/

2.2. Project (app hôte)

project/ public/ index.php assets/ css/ js/ img/ app/ Controllers/ ... Mail/ PhpMailerUserMailer.php (surcharge core possible) Services/ ... config/ app.php paths.php security.php logging.php mail.php form.php view.php (optionnel) *.dev.php / *.prod.php / *.local.php i18n/ fr/ common.php admin.php mails.php en/ ... storage/ templates/ layouts/ pages/ mails/ logs/ app.log vendor/ autoload.php ...

Surcharge (principe) : le project peut remplacer un service core via le Container (ex : user_mailer, provider permissions DB, extensions profile, etc.).

3) Configuration

La config est chargée au boot (core + project). Les clés sont accessibles via le service config (ex : $cfg->get('mail.driver')).

3.1. Fichiers de config (références)

Fichier Contenu Exemples de clés
config/app.php Nom app, env, debug, base_url, timezone app.name, app.env, app.debug
config/paths.php Chemins FS + URLs publiques paths.storage, paths.templates, paths.assets_base_url
config/security.php CSP, headers, HSTS, cookies session security.csp.mode, security.csp.directives
config/logging.php Driver log + fichier + niveaux logging.driver, logging.file
config/mail.php Mail driver, SMTP, from/reply-to mail.driver, mail.from.email, mail.reply_to.email
config/form.php Limites input + règles UX form.contact.subject_max, form.auth.password_min
config/view.php Smarty dirs/cache + mapping pages view.templates_dir, view.compile_dir

3.2. Convention “core + project”

  • Le core fournit des valeurs par défaut raisonnables.
  • Le project peut surcharger via ses fichiers config (mêmes clés, priorité project).
  • Les environnements (dev/prod) peuvent être gérés par variantes *.dev.php/*.prod.php ou une couche d’override (selon ton loader).

Globals View (toujours assignés) : APP, AUTH (pages), dictionnaire i18n (TXT_*).

4) Cycle global d’une requête

HTTP Request ↓ public/index.php (front controller) - charge autoload - charge config core + project - instancie Kernel + Container - boot (logger, i18n, view, security) ↓ Kernel::handle(Request) - request_id - middleware access log (début) - middleware i18n (résout locale) - middlewares route (csrf/auth/perm...) - router dispatch → controller ↓ Controller - lit Request (GET/POST/JSON) - appelle services (repos, auth, mailer, etc.) - retourne Response (HTML ou JSON) ↓ Kernel::send(Response) - headers sécurité (+ CSP si activée) - access log (fin) ↓ HTTP Response

Point clé : la canonicalisation locale est dans le Router (pas dans les contrôleurs). Les contrôleurs utilisent des chemins neutres (/login, /profile), le Router ajoute la locale.

5) Routing & i18n

5.1. Locale canonique dans l’URL

  • URLs attendues : /fr, /fr/profile, /en/login…
  • Si la locale est absente ou invalide : redirection vers la locale par défaut (ex: /fr).
  • La langue active est ensuite disponible via $i18n->lang().

5.2. Dictionnaires i18n

Pages

Chargement systématique :

i18n/{lang}/common.php + i18n/{lang}/{page}.php

“page” est défini explicitement par le contrôleur (recommandé) ou par convention.

Mails

Chargement dédié :

i18n/{lang}/mails.php

Évite d’importer des trads “page” inutiles dans les emails.

5.3. URL generation

  • Les contrôleurs renvoient des chemins neutres (/profile).
  • Le Router applique la locale (et sait produire des URLs absolues si nécessaire pour les mails).

6) Views (Smarty 5)

6.1. Organisation templates

storage/templates/ layouts/ base.tpl pages/ home.tpl auth/login.tpl profile/view.tpl admin/pages_list.tpl admin/pages_edit.tpl ... mails/ layout.html.tpl layout.txt.tpl activation.html.tpl activation.txt.tpl password_reset.html.tpl password_reset.txt.tpl contact.html.tpl contact.txt.tpl

6.2. Variables globales (à garantir)

Variable Type Usage
APP array {$APP.name}, {$APP.env}, etc.
CURRENT_YEAR int Footer : {$CURRENT_YEAR} (si tu le calcules côté PHP)
AUTH array|null Utilisateur courant (pages)
TXT_* string Traductions injectées dans Smarty (ex : {$TXT_LOGIN})

7) JSON & Validation

Objectif

Validation centralisée : InputValidator (codes techniques par champ) + DefaultFormErrors (mapping scope → TXT_*).

L’API renvoie uniquement des TXT_... pour que le front décide de l’affichage (toasts, inline, etc.).

Contrat JSON (référence)

{ "ok": false, "errors": { "email": "TXT_ERR_EMAIL_INVALID", "password": "TXT_ERR_PASSWORD_TOO_SHORT" } }

Erreurs validation renvoyées en HTTP 200 (contrat homogène).

7.1. InputValidator

InputValidator est fluide et enregistre la première erreur par champ. Il ne dépend ni d’i18n ni HTTP.

Codes d’erreur (validator-only)

Code Signification Exemple
EMPTY Requis vide required('email', $email)
TOO_SHORT Trop court minLen('password', $pw, 10)
TOO_LONG Trop long maxLen('username', $u, 30)
INVALID Format invalide pattern('slug', $slug, '/.../')
ALREADY_USED Unicité (métier) error('email', ALREADY_USED)
MISMATCH Non identique same('password_confirm', $a, $b)
EMAIL_INVALID Email invalide email('email', $email)

Règles importantes

  • First error wins : si un champ a déjà une erreur, les suivantes sont ignorées.
  • required() gère le vide ; minLen()/maxLen() n’ajoutent rien sur une chaîne vide (évite double erreur).
  • InputValidator ne renvoie pas de TXT_ : uniquement des codes techniques.

7.2. DefaultFormErrors (mapping UX)

DefaultFormErrors transforme les codes techniques en clés i18n (TXT_...) selon un scope.

Scopes (exemples)

  • auth.register, auth.login, auth.forgot, auth.reset
  • profile.email_change, profile.password_change, etc.
  • contact.send

8) Sécurité

8.1. CSP + nonce

  • CSP configurée via config/security.php (enforce / report-only / off).
  • Le Kernel applique la CSP et les autres headers (XFO, XCTO, Referrer-Policy, etc.).
  • Éviter les handlers inline (ex:) → JS externe.

8.2. CSRF

  • Token CSRF injecté dans les formulaires.
  • Middleware CSRF sur routes POST.

8.3. Auth + remember-me

  • Session sécurisée + cookie httpOnly/secure/sameSite.
  • Remember-me sécurisé (selector + validator), révocation au logout.

8.4. Throttling & anti-spam

  • LoginThrottleService (login + pwreset)
  • ContactSpamGuard : honeypot, timing gate, throttle, liens, profanity
  • UX : honeypot → répondre OK silencieusement

9) Modules

Objectif

Activer/désactiver des blocs fonctionnels (auth, admin, analytics…) de manière déclarative, sans toucher au Kernel.

Chaque module peut enregistrer services, routes, et dépendances.

Note (alignée avec ton fix)

  • En admin “Modules”, ne pas utiliser de fallback “defaultEnabled()” en vue : afficher le vrai état (fallback neutre).
  • Typique : enabled = $ms->enabled($slug, false) dans la vue admin.
  • core peut être verrouillé (toujours ON) si tu l’assumes.

9.1. Déclaration (config)

// config/modules.php return [ 'core' => true, 'i18n' => true, 'auth' => true, 'admin' => true, 'profile' => true, 'analytics' => false, ];

9.2. Structure d’un module

src/Modules/Pages/ PagesModule.php services.php routes.php

Rappel : si services.php ou routes.php existe, il doit retourner un callable, sinon boot fail-fast.

10) Pages CMS

Objectif

Publier des pages “contenu” (multi-lang) sans créer un contrôleur par page, avec une UI admin.

Le CMS est DB-first : tables cms_pages + cms_page_translations.

Conventions clés

  • Slug : unique par page (ex: about)
  • Traductions : 1 ligne par langue (title/content/publish)
  • Publish par langue : is_published + published_at sur la traduction
  • Param admin : utiliser page_lang (pas lang, réservé au router)

10.1. Modèle DB (résumé)

Table Rôle Champs clés
cms_pages Page logique id, slug, (meta éventuelles)
cms_page_translations Contenu par langue page_id, lang, title, content, is_published, published_at, updated_at

10.2. Admin (gestion)

  • /admin/pages : liste, recherche, quick-nav par page/lang.
  • /admin/pages/{slug} : édition du contenu ; changement de langue via dropdown.
  • Publish toggle par traduction (langue), via page_lang.
  • Auto-slug à la création (dérivé du titre).

10.3. Permissions (admin)

Permission Effet
admin.pages.view Accès liste/édition
admin.pages.add Créer une page
admin.pages.edit Modifier title/content
admin.pages.publish Publier/dépublier une traduction
admin.pages.delete Supprimer une page
admin.pages.sync Optionnel : sync/cron selon implémentation

UX : désactiver “Publier/Supprimer” si la page ou la traduction n’existe pas encore (création au save).

11) Mails

11.1. Flux supportés

  • Activation compte : envoi + resend (non-enumeration + throttle)
  • Password reset : génération lien + envoi
  • Contact : envoi au support / admin

11.2. i18n mails

i18n/{lang}/mails.php

11.3. Templates mails

storage/templates/mails/ layout.html.tpl layout.txt.tpl activation.html.tpl activation.txt.tpl password_reset.html.tpl password_reset.txt.tpl ...

11.4. PHPMailer

  • From verrouillé (alignement SPF/DKIM) pour éviter les rejets.
  • Reply-To optionnel pour permettre réponses vers l’adresse utilisateur.

12) Logging

12.1. Loggers unifiés

  • logger.core : messages framework (préfixe [core])
  • logger.project : messages projet (préfixe [project])

12.2. Access log middleware

[core] method=GET path=/fr/profile status=200 ms=12 rid=abc123

13) Dev / Deploy

13.1. Front controller

  • Le serveur web pointe sur project/public (DocumentRoot).
  • Les assets sont servis depuis public/assets (pas via PHP).

13.2. Réécriture (Apache / Nginx)

# Principe - servir fichiers/dirs existants - sinon réécrire vers /index.php

13.3. Environnements

  • dev : debug activé, logs verbeux, mailer log/sandbox.
  • prod : debug off, logs dans storage/logs, HSTS seulement sur HTTPS.

14) Rôles & permissions

Objectif

Contrôle d’accès basé sur rôles (hiérarchie) + permissions (clés type admin.users.view).

Règle de priorité

  • deny utilisateur > grant utilisateur > rôle
  • Permission inconnue ou désactivée (PER_IS_ENABLED=0) → refus par défaut

14.1. i18n des labels de permissions

Le label est dérivé de PER_KEY (pas stocké en TXT_* en DB).

PER_KEY = "admin.users.view" Label key = "TXT_PERM_ADMIN_USERS_VIEW"

15) Admin — gestion des rôles & permissions

15.1. Dictionnaire i18n admin

Les pages /admin chargent un dictionnaire dédié : i18n/{lang}/admin.php.

15.2. Pages

Page But Actions
/admin/permissions Catalogue permissions search, create, toggle enabled, update
/admin/roles Catalogue rôles list, create
/admin/roles/{id} Édition rôle update role, assign permissions, delete (si permis)

Annexes

A) Nommage & conventions

  • Indentation code : 2 espaces.
  • Tables DB : minuscule. Champs/PK/FK/index : MAJ avec préfixes.
  • Templates : layout via {extends}, pas de display() direct côté web.

B) Points d’extension côté Project

  • Surcharger user_mailer (SMTP), provider permissions DB, services spécifiques.
  • Ajouter routes/pages, assets, templates.
  • Conserver le contrat JSON de validation et la locale canonique.

© 2026 natora.net — Framework PHP + Project (doc interne)