sopheos / pebble_validation
Form validation library: typed fields, chainable rules, error codes and messages
Requires
- php: >=8.1.0
- ext-fileinfo: *
- ext-filter: *
- ext-mbstring: *
Requires (Dev)
- phpunit/phpunit: ^9.5
Suggests
- ext-imagick: Used by Helper::getImageSize() (image min/max size rules) when loaded, instead of getimagesize()
Provides
None
Conflicts
None
Replaces
None
README
Validation de formulaires pour PHP 8.1+ : des champs typés qui nettoient et convertissent la saisie, des règles chaînables, et un Form qui expose valeurs, codes d'erreur et messages.
La lib ne lit pas les superglobales, ne traduit pas les messages et ne produit pas de HTML : on lui passe un tableau ($_POST, JSON décodé…), on récupère des valeurs typées et des codes d'erreur.
Installation
composer require sopheos/pebble_validation
Extensions requises : mbstring, fileinfo, filter. imagick est facultative : si elle est chargée, elle mesure les images à la place de getimagesize().
Claude Code
Ce package fournit un skill Claude Code dans skills/pebble-validation/. Il documente les patterns d'usage et les pièges de la librairie : codes d'erreur égaux aux noms de règles, defaultValue() non validée, custom() qui n'échoue qu'en levant une exception, conversions du mode auto de Table, IsVatNumber et IsPostalCode mal ancrés, etc.
Dans un projet qui dépend de sopheos/pebble_validation, 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_validation/skills/pebble-validation .claude/skills/pebble-validation
Pour la maintenance de la lib elle-même, voir CLAUDE.md. Les bugs connus sont listés dans TODO.md.
Exemple
use Pebble\Validation\Form; use Pebble\Validation\Fields\Integer; use Pebble\Validation\Fields\Text; use Pebble\Validation\Rules\IsEmail; $form = new Form(); Text::create('email')->required()->addRule(IsEmail::create())->addTo($form); Integer::create('age')->min(18)->addTo($form); $form->field('email')->setMessage('required', 'E-mail obligatoire'); if (!$form->validate($_POST)) { $form->errors(); // ['email' => 'required', 'age' => 'num_min'] $form->messages(); // ['email' => 'E-mail obligatoire', 'age' => 'default'] } $form->values(); // ['email' => 'john@doe.fr', 'age' => 42]
Form
\Pebble\Validation\Form regroupe des champs indexés par leur nom.
addField(FieldInterface $field) : staticAjoute un champ. Un champ de même nom remplace le précédent. Équivalent :$field->addTo($form).field(string $name) : ?FieldInterface/fields() : arrayUn champ, ou tous.validate(array $data) : boolValide chaque champ avec$data[$nom] ?? null. Tous les champs sont validés, même après un échec.isValid() : boolRésultat de la dernière validation.values() : arrayValeurs nettoyées et converties de tous les champs, y compris invalides.inputs() : arraySaisies après nettoyage, avant les règles. Les saisies falsy ("0",0,false) sont omises (voirTODO.md).errors() : arrayCodes d'erreur des champs invalides.messages() : arrayMessages des champs invalides.value(string $field)/input(string $field)/error(string $field)/message(string $field)Accès à un champ.nullsi le champ n'existe pas.setName(string $name) : static/name() : stringNom libre du formulaire.
Fields
Tous les champs héritent de \Pebble\Validation\Fields\Field et se construisent avec Champ::create('nom').
Cycle de validate($value) :
prepare()nettoie et convertit la saisie. Si elle n'est pas convertible, l'erreur estdefault.- Si la valeur est vide (
null,'',[]) : erreurrequiredsi le champ est requis, sinondefaultValue()est appliquée sans passer par les règles. - Les règles s'exécutent dans l'ordre d'ajout. Chacune peut transformer la valeur. La première qui échoue donne son nom comme code d'erreur.
Méthodes communes :
required() : staticRend le champ obligatoire (erreurrequired).defaultValue($value) : staticValeur utilisée si la saisie est vide.addRule(RuleInterface $rule) : staticAjoute une règle.custom(string $name, callable $callable, ...$params) : staticRègle maison :$callable($value, ...$params)renvoie la nouvelle valeur. Elle échoue uniquement si elle lève une exception.fakeRule(string $name) : staticRègle qui passe toujours, pour réserver un code d'erreur posé ensuite parsetError().setMessage(string $rule, ?string $message = null) : staticMessage pour un code d'erreur. Sans message, le code lui-même.setDefaultMessage(string $message) : staticMessage des codes sans message (par défautdefault).setError(string $error) : static/setValue($value) : staticForcent l'erreur ou la valeur après validation.value()/input()/error() : string/message() : string/isValid() : bool/rules() : array.
Textarea, Text, Password
TextareaTexte multiligne. Décode les entités HTML, retire les balises, les caractères de contrôle et les espaces spéciaux, réduit les espaces et garde au plus une ligne vide.TextCommeTextarea, sur une seule ligne. AjouteisFile(string $prefix = '', string $suffix = '')etisDir(...).PasswordCommeText, mais ni balises retirées ni trim. Refuse les espaces (whitespace) et les espaces spéciaux (special_space).
Règles : min(int) (len_min), max(int) (len_max), range(int, int) (len_range), equal(int) (len_len), match(string) (match), differ(string) (differ), includes(array) (includes), excludes(array) (excludes), regexMatch(string $name, string $pattern) et regexDiff(...) (code $name).
Textarea::sanitize(string $input, bool $multiline = false, bool $striptags = true) : string est utilisable seule.
Url, Uuid
UrlTextnettoyé parFILTER_SANITIZE_URL(les espaces sont supprimés), avec la règleis_url.UuidTextavec la règleformat.
Integer, Number, Timestamp
IntegerCast(int)de toute valeur numérique :"1.9"donne1,"1e3"donne1000.NumberCast(float). Le séparateur décimal est le point.TimestampIntegerqui accepte aussi une date ISO 8601, convertie parstrtotime().
Règles : min() (num_min), max() (num_max), range() (num_range), equal() (match), diff() (differ), includes(), excludes().
Boolean
Accepte true/false, 0/1 et les chaînes de FILTER_VALIDATE_BOOLEAN (on, yes, off, no…). false n'est pas une valeur vide.
isTrue()/isFalse()Règlematch, par exemple pour des CGU à accepter.
Table
Tableau PHP ou chaîne JSON. Chaque élément est converti selon le mode :
- auto (par défaut) Les chaînes numériques deviennent des
float(voirTODO.md), les autres chaînes sont nettoyées comme unTextarea. none()Aucune conversion.integer()/number()/text()/textarea()/timestamp()Conversion comme le champ du même nom.
Règles : min(int) (array_min), max(int) (array_max), range(int, int) (array_range), map(Rule $rule) (applique une règle à chaque élément), includes(array), excludes(array), customMap(string $name, callable $callable, ...$params).
Sous-formulaires :
child(Form $form) : staticValide un objet avec$form(erreurchild). Les erreurs détaillées se lisent sur$form.children(Form $form) : staticValide une liste d'objets (erreurchildren).childrenErrors() : array/childrenMessages() : arrayErreurs des éléments invalides, indexées par position.
Upload
Entrée de $_FILES. Les erreurs PHP sont traduites : taille (file_size), envoi partiel ou absent (corrupted), autre (default, avec une notice). Un champ facultatif sans fichier échoue avec corrupted : passer null dans ce cas (voir TODO.md).
mimes(array $mimes)Types MIME ou extensions (['jpg', 'png', 'application/pdf']), lus dans le contenu du fichier (file_type).size(int $limit)Taille maximale en octets (file_size). Un fichier vide échoue.min(int $width, int $height, bool $ignoreOrientation = true)/max(...)Dimensions d'image (image_min_size,image_max_size).
Rules
Toutes les règles sont dans \Pebble\Validation\Rules, se construisent avec create(...) et s'ajoutent par $field->addRule(). Le nom de la règle est le code d'erreur.
- Longueur :
LenMin,LenMax,LenRange,LenEqual(len_len). - Nombres :
NumMin,NumMax,NumRange. - Tableaux :
ArrayMin,ArrayMax,ArrayRange,ArrayMap,Child,Children. - Comparaison :
Exact(match),Differ,Includes,Excludes(comparaison non stricte). - Formats :
Regex(string $name, string $pattern, bool $match = true),IsEmail(met en minuscules),IsUrl,IsIP(int $flags = 0),Uuid(format),IsPostalCode(string $country)(code pays ISO en majuscules),IsVatNumber(numéro de TVA intracommunautaire),CharList(caractères autorisés, voir ci-dessous). - Fichiers :
IsFile,IsDir,FileType,FileSize,ImageMinSize,ImageMaxSize. - Code utilisateur :
CallableRule(échoue si une exception est levée, c'estcustom()),Callback(échoue si le callable renvoienull),FakeRule.
CharList::create(string $name = 'charlist') se compose avec letters(), numbers(), accents(), ponctuations(), currencies(), indices(), text() (tout cela), emoji() et add(string $chars) (fragment de classe de caractères regex, non échappé). Les espaces sont toujours acceptés.
IsVatNumber et IsPostalCode (GB, CR, LI) acceptent du texte autour d'une valeur valide : voir TODO.md.
TestHelper
\Pebble\Validation\TestHelper vérifie la configuration d'un formulaire dans les tests d'un projet. Il appelle les assertions de PHPUnit, qui doit donc être installé (ce n'est qu'une dépendance de développement de la lib).
fields(FormInterface $form, array $tests, array $required = [])$tests:['nom' => Classe::class]. Vérifie la liste exacte des champs, leur classe et les champs requis.rules(FieldInterface $field, array $tests)$tests:['nom_regle' => ['propriete' => valeur]]. Vérifie la liste exacte des règles et de leurs propriétés.formRules(FormInterface $form, array $tests)rules()pour chaque champ :['champ' => ['nom_regle' => [...]]].
Tests
composer install vendor/bin/phpunit
Les bugs connus sont figés par des tests annotés // BUG: qui vérifient le comportement actuel.