sopheos / pebble_template
PHP view renderer, data bag and HTML tag helpers
Requires
- php: >=8.1.0
Requires (Dev)
- phpunit/phpunit: ^9.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Rendu de vues PHP (.phtml) et helpers de génération de balises HTML, pour PHP 8.1+.
Les vues sont du PHP pur : pas de syntaxe propre, pas de layout, et pas d'auto-échappement. C'est à la vue d'appeler self::xss() sur chaque donnée affichée.
Installation
composer require sopheos/pebble_template
Claude Code
Ce package fournit un skill Claude Code dans skills/pebble-template/. Il documente les patterns d'usage et les pièges de la librairie : variables non échappées, contenu de tag() brut, noms d'attributs non échappés, jsVars() sans déclaration, PlainText qui écrit directement sur la sortie, etc.
Dans un projet qui dépend de sopheos/pebble_template, copie-le une fois dans .claude/skills/ après composer install pour que Claude Code le charge automatiquement. Le nom du dossier doit correspondre au name déclaré dans SKILL.md :
cp -r vendor/sopheos/pebble_template/skills/pebble-template .claude/skills/pebble-template
Pour la maintenance de la lib elle-même, voir CLAUDE.md. Les bugs connus sont listés dans TODO.md.
View
\Pebble\Template\View associe un fichier et des données. Elle utilise BagTrait et HelperTrait.
__construct(string $file, array $data = [])/create(string $file, array $data = []) : staticCrée la vue. Le fichier n'est vérifié qu'au rendu.include(string $file, array $data = []) : staticNouvelle vue qui hérite des données de la vue courante.$datal'emporte en cas de conflit. Elle n'est pas rendue tant qu'on ne l'affiche pas.load() : stringRend le fichier : les données sont extraites en variables locales, puis le fichier est inclus dans un tampon de sortie. LèveInvalidArgumentExceptionsi le fichier n'existe pas. Une exception levée par la vue vide le tampon et est relancée.__toString() : stringÉquivaut àload().
Dans la vue, $this est l'objet View : $this->get(), $this->include(), et les helpers via self:: ou $this->.
use Pebble\Template\View; echo View::create(__DIR__ . '/views/page.phtml', ['title' => 'Accueil', 'items' => $items]);
<!-- views/page.phtml --> <h1><?= self::xss($title) ?></h1> <?= $this->include(__DIR__ . '/list.phtml', ['class' => 'items']) ?>
Une donnée nommée this fait échouer le rendu (Error: Cannot re-assign $this).
BagTrait
import(array $data) : staticRemplace toutes les données.set(string $name, mixed $value) : staticDéfinit une valeur.add(string $name, mixed $value, ?string $index = null) : staticAjoute à un tableau, en fin ou à l'index donné. Sans effet si la valeur existante n'est pas un tableau. L'index'0'est traité comme absent (voirTODO.md).get(string $name) : mixedUne valeur, ounull.export() : arrayToutes les données.
HelperTrait
Toutes les méthodes sont statiques.
tag(string $tag, string|array $arg1 = '', string|array $arg2 = []) : stringBalise complète suivie de\n. Contenu et attributs dans n'importe quel ordre. Le contenu n'est pas échappé. Les éléments vides (br,img,input,link,meta…) se ferment en<br />et perdent leur contenu. La comparaison est sensible à la casse.openTag(string $tag, array $attrs = []) : stringBalise ouvrante, sans\n.closeTag(string $tag) : stringBalise fermante suivie de\n, chaîne vide pour un élément vide.attrToString(array $attributes) : stringAttributs préfixés d'un espace.truedonne un attribut booléen,false,null,''et[]sont omis,0et'0'sont conservés, un tableau est encodé en JSON. Les valeurs sont échappées, pas les noms.xss(mixed $value) : stringÉchappe une valeur pour le HTML (htmlspecialchars,ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5).nulldonne'', un booléen'1'/'0', un tableau ou un objet son JSON échappé (unStringabledonne donc{}).meta(array $meta) : stringUne balise par entrée :<link>si l'entrée a une clérel, sinon<meta>.scripts(array $urls, bool $module = false) : stringUne balise<script src>par URL, avectype="module"si demandé.styles(array $urls) : stringUne balise<link rel="stylesheet">par URL.jsVars(string $name, mixed $value) : string<script>name = json;</script>. Pas devar/const: c'est une affectation globale implicite. VoirTODO.mdpour l'échappement du JSON.
echo View::tag('a', 'Accueil', ['href' => '/', 'class' => 'nav', 'data-active' => true]); // <a href="/" class="nav" data-active>Accueil</a> echo View::meta([ ['charset' => 'utf-8'], ['name' => 'description', 'content' => $description], ['rel' => 'canonical', 'href' => $url], ]);
PlainText
Écrit du texte brut directement sur la sortie (pas de valeur de retour textuelle). Chaque méthode est statique et renvoie un singleton pour pouvoir chaîner. Utile dans une vue texte (e-mail, CSV) rendue par View.
add(string $text, mixed ...$items) : staticvprintf()si des items sont donnés, sinonprint.%n'est donc interprété qu'avec des items.eol(int $nb = 1)/tab(int $nb = 1)/space(int $nb = 1)Retours à la ligne, tabulations, espaces.repeat(string $str, int $nb = 1) : staticRépète$str, rien si$nb <= 0.getInstance() : staticLe singleton. Ne pas sous-classerPlainText(voirTODO.md).
PlainText::add('Bonjour %s,', $name)->eol(2)->add('Total : %d €', $total)->eol();
Tests
composer install vendor/bin/phpunit
Les vues de test sont dans tests/fixtures/. Les bugs connus sont figés par des tests annotés // BUG: qui vérifient le comportement actuel.