Vues
Vues
Des fichiers .php ordinaires dans resources/views/, sans moteur de
template séparé — cette page de documentation elle-même en est un exemple.
Vues PHP natives
Niang\Core\View ne fait rien d'exotique : renderView() extrait le
tableau de données dans la portée locale (extract($data, EXTR_SKIP)), inclut le
fichier avec ob_start()/ob_get_clean(), et retourne le HTML capturé.
Aucune compilation, aucun cache de bytecode de template : c'est du PHP, exécuté comme du PHP.
public function index(): Response
{
return $this->view('home', ['title' => 'Bienvenue']);
}
\$this->view() (dans un contrôleur, via Niang\Core\Controller) et le
helper global view() font tous deux la même chose : View::make($view,
$data), qui enveloppe renderView() dans une Response::html().
Le chemin est résolu par convention : 'home' → resources/views/home.php,
et 'admin.posts.index' (points comme séparateurs) →
resources/views/admin/posts/index.php. Une vue introuvable ne lève pas d'exception :
elle rend simplement le texte "Vue introuvable : nom", à la place du contenu.
layout() : composer une page dans un gabarit
Appelé en haut d'une vue, layout($vue, $donnees) ne rend rien immédiatement : il
mémorise le gabarit visé. Une fois la vue entièrement rendue, son HTML est injecté dans
$content du gabarit, qui est alors rendu à son tour — un aller-retour géré par
View::renderView(), invisible depuis la vue elle-même.
layout('layouts.app', ['title' => $title]); ?>
<h1><?= e($framework) ?></h1>
<p>Votre framework tourne. Bienvenue !</p>
Le gabarit reçoit ses propres données plus $content :
<title><?= e($title ?? 'NiangPro') ?></title>
...
<div class="card">
<?= $content ?>
</div>
Cette page de documentation applique exactement ce schéma : chaque vue
resources/views/docs/fr/*.php (et docs/en/*.php pour l'anglais) commence par
layout('layouts.docs', [...]), et le gabarit ajoute la barre latérale, le
sommaire et la recherche autour du contenu.
component() : inclure une vue partielle
component($vue, $donnees) rend une vue et retourne directement le HTML sous forme
de chaîne (au lieu d'une Response) — pour l'insérer dans une autre vue :
<?= component('components/icon', ['name' => 'check']) ?>
Chaque icône de cette documentation (le bouton copier, la recherche, le sommaire mobile...) est
un component('components/icon', ['name' => '...']) — un SVG inline choisi dans
resources/views/components/icon-paths.php, jamais une police d'icônes chargée à
distance.
field() : un champ de formulaire complet
field($name, $label, $options = []) est un raccourci pour
component('components/field', [...]) : name et label
reviennent, obligatoires, dans presque toutes les vues de formulaire — les répéter en tableau
associatif à chaque champ est le principal bruit visuel d'un formulaire.
<?= field('email', 'Adresse email', ['type' => 'email', 'autocomplete' => 'email']) ?>
plutôt que :
<?= component('components/field', ['name' => 'email', 'label' => 'Adresse email', 'type' => 'email', 'autocomplete' => 'email']) ?>
$options accepte les mêmes clés que le composant
(type — texte par défaut, rows pour un <textarea>,
value, autocomplete, required). Ce n'est qu'un raccourci
d'appel, pas un nouveau mécanisme : resources/views/components/field.php reste le
seul endroit qui décide du HTML produit — label, ancienne saisie via old() après
une erreur de validation (jamais pour un password, toujours vidé), et message
d'erreur via components/field-errors, déjà câblés.
e() : échapper l'affichage
e($valeur) est htmlspecialchars((string) $valeur, ENT_QUOTES, 'UTF-8')
— à utiliser explicitement à chaque affichage d'une donnée qui n'est pas déjà du HTML de
confiance (pas d'échappement automatique implicite, puisqu'il n'y a pas de moteur de template) :
<h1><?= e($titre) ?></h1>
e() échappe pour un contexte HTML. Pour injecter des données dans un attribut
consommé par du JavaScript (ex. data-props pour Alpine.js), utilisez plutôt
json_for_html() — voir le tableau ci-dessous — qui échappe spécifiquement contre
une évasion de balise </script> ou d'attribut.
Langues : __() et lang/
Les textes que voit un visiteur — messages de validation, erreurs d'upload, pages d'erreur,
messages 401/403/419/429, pagination — viennent de lang/<langue>/*.php à la
racine du projet, livrés en français (défaut) et en anglais. La langue se choisit dans
.env (APP_LOCALE=en) ou pour une requête avec
Lang::setLocale('en') :
__('validation.required', ['attribute' => 'email']); // « Le champ email est requis. »
__('http.404'); // « Page introuvable. »
__('pagination.next');
Lang::setLocale('en');
__('http.404'); // « Page not found. »
| Fichier | Contient |
|---|---|
validation.php | Un message par règle, et la section attributes : libellés lisibles des champs ('items.*.name' => "nom de l'article"). |
upload.php | Les raisons d'un upload invalide (taille dépassée, envoi partiel...). |
http.php | Messages des erreurs HTTP, des middlewares d'authentification et des pages d'erreur. |
pagination.php | Liens « Précédent » / « Suivant » de Paginator::links(). |
Ces fichiers appartiennent à votre projet : modifiez un message directement, ou ajoutez une langue en
copiant lang/en/ vers lang/es/. :attribute, :min...
sont remplacés, :Attribute met la première lettre en majuscule. Une clé absente de la
langue courante est cherchée dans APP_FALLBACK_LOCALE (fr), puis affichée
telle quelle. La CLI et les exceptions destinées au développeur restent en français.
Pluriels
// lang/fr/panier.php
'articles' => 'un article|:count articles',
'etat' => '{0} Votre panier est vide|{1} Un article|[2,9] :count articles|[10,*] Plus de :count articles',
trans_choice('panier.articles', 3); // « 3 articles »
Lang::choice('panier.etat', 0); // « Votre panier est vide »
Les formes {n} et [min,max] sont testées d'abord, sinon la règle de la langue : en
français, 0 et 1 sont au singulier ; en anglais, seul 1 l'est.
Tous les helpers globaux
Chargés automatiquement sur chaque requête (composer.json les déclare en
autoload.files) : aucun use à écrire, ils sont disponibles partout.
Liste complète (packages/core/src/helpers.php et packages/http/src/helpers.php) :
| Helper | Rôle |
|---|---|
base_path(string $path = '') | Chemin absolu depuis la racine du projet. |
env(string $key, mixed $default = null) | Lit une variable de .env. |
config(string $key, mixed $default = null) | Lit config/*.php, ex. config('app.providers'). |
route(string $name, array $params = []) | URL d'une route nommée. Voir Routing. |
signedRoute(string $name, array $params = [], ?int $expiresInSeconds = null) | route() + signature expirable (UrlSignature::sign()) — lien cliquable sans authentification préalable. |
view(string $view, array $data = []) | Équivalent global de $this->view() dans un contrôleur. |
layout(string $view, array $data = []) | Voir ci-dessus. |
component(string $view, array $data = []) | Voir ci-dessus. |
field(string $name, string $label, array $options = []) | Voir ci-dessus. |
e(mixed $value) | Voir ci-dessus. |
__(string $key, array $replace = []) | Traduction dans la langue courante, ex. __('http.404'). Voir Langues. |
json_response(mixed $data, int $status = 200) | Équivalent global de Response::json(). |
csrf_token() | Jeton CSRF courant (Niang\Core\Csrf::token()). |
csrf_field() | Le <input type="hidden"> CSRF prêt à insérer dans un <form>. |
old(string $key, mixed $default = null) | Ancienne saisie après une redirection de validation échouée. Voir Validation. |
flashed(string $key, mixed $default = null) | Lit une valeur flash de session (ex. message de succès après redirection). |
errors(?string $key = null) | Erreurs de validation flashées ; avec $key, celles d'un seul champ. |
abort(int $status, string $message = '') | Lève une HttpException, interceptée par Handler (ex. abort(404)). |
json_for_html(mixed $data) | JSON échappé pour un attribut HTML (JSON_HEX_*) — hydrater un composant Alpine.js/Vue/React côté client sans risque XSS. |
uuid() | UUID version 4 aléatoire, ex. pour une colonne $table->uuid(). |
url(string $path = '') | URL absolue construite avec APP_URL (jamais l'en-tête Host) : pour les liens envoyés par email. |
trans_choice(string $key, int|float $count, array $replace = []) | Traduction au pluriel (voir Pluriels). |
trigger_deprecation(string $package, string $version, string $message) | Signale une API dépréciée ; consigné dans les logs en production (voir stabilité de l'API). |
vite_asset(string $entry) | URL réelle d'un asset Vite (Niang\Core\ViteAssets) : bascule sur public/hot en dev, lit public/build/manifest.json en prod. |
dd(mixed ...$vars) | Affiche chaque valeur (var_dump) et arrête l'exécution — debug uniquement. |
<div data-props="<?= json_for_html($props) ?>" x-data="JSON.parse($el.dataset.props)"></div>