sopheos / pebble_swagger
OpenAPI 3 document generator from oa-* docblock tags
Requires
- php: >=8.1.0
- ext-mbstring: *
Requires (Dev)
- phpunit/phpunit: ^9.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Génération d'un document OpenAPI 3 (Swagger) à partir de tags oa-* placés dans les docblocks des contrôleurs et des classes de résultat, pour PHP 8.1+.
Parser scanne un répertoire de contrôleurs, lit les docblocks de leurs méthodes et renvoie un tableau PHP prêt à passer à json_encode(). Les schémas référencés sont résolus dans un ou plusieurs namespaces de classes « résultat ».
Installation
composer require sopheos/pebble_swagger
Claude Code
Ce package fournit un skill Claude Code dans skills/pebble-swagger/. Il documente la syntaxe des tags oa-*, les patterns d'usage et les pièges de la librairie : classes final/abstract/readonly ignorées, oa- détecté n'importe où dans un docblock, oa-query ignoré hors GET/DELETE, schémas récursifs qui bouclent, motifs coupés au :, etc.
Dans un projet qui dépend de sopheos/pebble_swagger, 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_swagger/skills/pebble-swagger .claude/skills/pebble-swagger
Pour la maintenance de la lib elle-même, voir CLAUDE.md. Les bugs connus sont listés dans TODO.md.
Exemple
use Pebble\Swagger\Parser; $doc = Parser::create(__DIR__ . '/src/Controllers') ->parser('App/Results') ->title('Mon API') ->version('1.0.0') ->servers('https://api.example.com') ->run(); header('Content-Type: application/json; charset=UTF-8'); echo json_encode($doc);
namespace App\Controllers; class User { /** * oa-url /api/users/{id} * oa-method get * oa-tags Users * oa-summary Détail d'un utilisateur * oa-private accessToken * oa-path id integer Identifiant * oa-required id * oa-res 200 UserResult * oa-res 404 ErrorResult */ public function detail() {} }
namespace App\Results; /** * oa-desc Utilisateur * oa-field id integer Identifiant * oa-field email string:email * oa-ref location Sub/LocationResult * oa-refs points Sub/PointResult * oa-required id email */ class UserResult {}
Le répertoire demo/ contient une page Swagger UI (php demo/server.php, puis http://localhost:8080) qui affiche le document généré à partir des fixtures de tests/ressources/.
Tags
Les valeurs sont séparées par des espaces. Le dernier argument d'un tag (description) peut contenir des espaces.
Méthode de contrôleur
oa-url /chemin/{param}Obligatoire.oa-method get|post|put|patch|delete|optionsObligatoire, en minuscules.oa-tags Tag1 Tag2Tags Swagger (un mot chacun).oa-summary TexteRésumé.oa-scope adminle préfixe par[admin].oa-desc TexteDescription, une ligne par tag.oa-publicAucune authentification.oa-private nomDuSchémaAuthentification par ce schéma.oa-path nom type DescriptionParamètre de chemin.oa-query nom type DescriptionParamètre de requête. Ignoré sauf pourgetetdelete.oa-required nom1 nom2Paramètres et champsoa-dataobligatoires. Les paramètres de chemin doivent y figurer.oa-json Schéma DescriptionCorps JSON (ignoré pourget/delete).oa-data nom type DescriptionChamp d'un corpsmultipart/form-data(si pas d'oa-json, ignoré pourget/delete).oa-code 404 DescriptionRéponse sans corps. Répété pour un même code, les descriptions sont jointes par<br>.oa-res 200 Schéma DescriptionRéponse JSON.Schéma[]pour un tableau. Remplace unoa-codedu même code.
Classe de résultat (schéma)
oa-desc TexteDescription, une ligne par tag.oa-field nom type DescriptionPropriété. Un|dans la description est un saut de ligne.oa-ref nom SchémaPropriété objet.oa-refs nom SchémaPropriété tableau d'objets.oa-required nom1 nom2Propriétés obligatoires.
Types
integer,number,string,boolean… : type simple.type:format:string:date-time,string:email,integer:int64,string:binary…type:/regex/: motif (sans:dans la regex, voirTODO.md).array(tableau de chaînes),array:integer,array:string:email.
Un nom de schéma est relatif au namespace passé à parser(), avec / comme séparateur : Sub/PointResult désigne App\Results\Sub\PointResult et devient le composant Sub_PointResult.
Parser
\Pebble\Swagger\Parser assemble le document.
create(string $path) : static/__construct(string $path)Répertoire des contrôleurs, scanné récursivement.title(string $title) : staticDéfautTitle.description(string $value) : staticDéfautDescription.version(string $value) : staticDéfaut0.0.1.servers(mixed ...$values) : staticRemplace la liste des serveurs (défauthttp://127.0.0.1).jwtTokens(bool $global = true, mixed ...$names) : staticRemplace les schémas de sécurité « bearer JWT ». La sécurité globale n'est posée que si$globalest vrai et qu'il y a un seul nom. Défaut :jwtTokens(true, 'accessToken').parser(string $namespace) : staticAjoute un namespace de schémas (App/ResultsouApp\Results). Les namespaces sont essayés dans l'ordre d'ajout.run() : arrayScanne, construitpathsetcomponents.schemas(uniquement les schémas utilisés).
ApiParser
\Pebble\Swagger\ApiParser construit paths. Utilisé par Parser.
__construct(string $path, SchemaParsers $parsers)run() : arrayChemins triés par URL.parseClass(string $classname)Analyse les méthodes (y compris héritées) d'une classe.scanClasses(string $folder) : array(statique) Classes trouvées dans les fichiers.phpdu répertoire.getClass(string $filename) : ?string(statique) Première classe déclarée par\nclass Nomdans le fichier, si elle existe (autoload).
Une erreur de syntaxe lève \Pebble\Swagger\Exception avec la classe et la méthode en cause, par exemple \App\Controllers\User:detail oa-url not found.
SchemaParser / SchemaParsers
new SchemaParser(string $namespace)Résout les schémas d'un namespace.get(string $name) : ?arraySchéma de la classe$namespace\$name,nullsi elle n'existe pas ou n'a pas de tagoa-*. Mis en cache.cache() : arraySchémas résolus, indexés par nom de composant.
SchemaParsers::create()Collection deSchemaParser.add(SchemaParser $parser) : staticget(string $name) : ?arrayPremier résultat non nul.cache() : arrayFusion des caches.
DocCollection / DocEntity
Lecture bas niveau d'un docblock.
DocCollection::create(string $doc) : staticUneDocEntitypar ligne contenantoa-.has(string $name) : bool,one(string $name) : ?DocEntity,all(string $name) : array,count() : int.parseMultiline(string $name, $sep = "\n") : stringJoint les valeurs des tags répétés.DocCollection::parseType(string $type, array $schema = []) : arrayConvertit la syntaxe de type ci-dessus en schéma OpenAPI.DocEntity:$name,$value,value(int $pos = 0) : string,values(int $start = 0, ?int $len = null) : array,text(int $start = 0, ?int $len = null) : string.
Tests
composer install vendor/bin/phpunit
Les fixtures sont dans tests/ressources/ (chargées par tests/bootstrap.php). Controllers/ et Results/ servent aussi à la démo. Les bugs connus sont figés par des tests annotés // BUG: qui vérifient le comportement actuel.