[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CSWC8MQYFMASQYSX16MPWM":3,"skill-same:01M6CSWC8MQYFMASQYSX16MPWM":67},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":25,"linkOnly":26,"markdownContent":27,"markdownBody":28,"frontMatter":29,"refName":39,"commitSha":40,"skillDirectory":41,"forksCount":14,"repositoryHtmlUrl":42,"repositoryHomepageUrl":43,"ownerHtmlUrl":44,"ownerBlogUrl":6,"ownerDescription":45,"updatedAt":46,"install":47,"resources":60},"01M6CSWC8MQYFMASQYSX16MPWM","implementer:log",null,"Ajouter LoggableInterface à une classe PHP","atournayre\u002Fclaude-personas","atournayre","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F4262077?v=4","01M6CSSGYW0E0D0M3E2T6J9X2Z","Aurélien Tournayre","01M6CSSH3DENJF2XWZ41H0F43K",0,"MIT","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fimplementer\u002Fskills\u002Flog\u002FSKILL.md",[],[19,20,5,21,22,23,24],"implementer","log","php","grep","read","edit","2026-11-10 10:12:30",false,"---\nname: implementer:log\ndescription: Ajouter LoggableInterface à une classe PHP\nargument-hint: [FICHIER]\nmodel: sonnet\nallowed-tools: [Read, Edit, Grep, Glob]\nversion: 1.0.0\nlicense: MIT\n---\n\n# Ajout de logging avec LoggableInterface\n\nAjouter l'interface `LoggableInterface` et la méthode `toLog()` à une classe PHP.\n\n## Instructions à Exécuter\n\n**IMPORTANT : Exécute ce workflow étape par étape :**\n\nFichier cible : $ARGUMENTS\n\n### 1. Lire et analyser le fichier\n\n- Lire le contenu du fichier PHP\n- Identifier la classe principale et ses propriétés\n- Vérifier si `LoggableInterface` est déjà implémentée\n\n### 2. Chercher les dépendances LoggableInterface\n\nPour chaque type-hint de propriété ou paramètre :\n- Utiliser Grep pour chercher si la classe implémente `LoggableInterface`\n- Noter les classes qui l'implémentent pour appeler `->toLog()` dessus\n\n### 3. Ajouter LoggableInterface\n\nSi la classe n'implémente pas encore `LoggableInterface` :\n\n**Ajouter l'import :**\n```php\nuse Atournayre\\Contracts\\Log\\LoggableInterface;\n```\n\n**Ajouter l'interface à la déclaration de classe :**\n```php\nfinal class NomClasse implements LoggableInterface\n```\n\n**Ajouter la méthode toLog() :**\n```php\n\u002F**\n * @return array\u003Cstring, mixed>\n *\u002F\npublic function toLog(): array\n{\n    return [\n        \u002F\u002F Propriétés clés de l'objet\n    ];\n}\n```\n\n### 4. Règles pour le contenu de toLog()\n\n**Propriétés à inclure :**\n- `id` (si présent)\n- Identifiants métier (email, code, référence...)\n- États\u002Fstatuts importants\n- Dates clés (createdAt, updatedAt...)\n\n**Propriétés à exclure :**\n- Mots de passe, tokens, secrets\n- Données personnelles sensibles\n- Propriétés volumineuses (blobs, textes longs)\n\n**Pour les objets imbriqués :**\n- Si l'objet implémente `LoggableInterface` : `'relation' => $this->relation->toLog()`\n- Sinon : `'relationId' => $this->relation->getId()` ou ignorer\n\n**Pour les collections :**\n```php\n\u002F**\n * @return array{count: int, items: array\u003Cint, array\u003Cstring, mixed>>}\n *\u002F\npublic function toLog(): array\n{\n    return [\n        'count' => $this->count(),\n        'items' => array_map(fn ($item) => $item->toLog(), $this->items),\n    ];\n}\n```\n\n### 5. Vérification PHPStan\n\n- Toujours ajouter `@return array\u003Cstring, mixed>` sur la méthode\n- Pour les collections : utiliser le type array shape approprié\n\n## Exemple de résultat\n\n```php\nuse Atournayre\\Contracts\\Log\\LoggableInterface;\n\nfinal class Commande implements LoggableInterface\n{\n    private Uuid $id;\n    private string $reference;\n    private Client $client;\n    private \\DateTimeImmutable $createdAt;\n    private string $password; \u002F\u002F Sensible, à exclure\n\n    \u002F**\n     * @return array\u003Cstring, mixed>\n     *\u002F\n    public function toLog(): array\n    {\n        return [\n            'id' => $this->id->toRfc4122(),\n            'reference' => $this->reference,\n            'client' => $this->client->toLog(),\n            'createdAt' => $this->createdAt->format('c'),\n            \u002F\u002F password exclu intentionnellement\n        ];\n    }\n}\n```\n","# Ajout de logging avec LoggableInterface\n\nAjouter l'interface `LoggableInterface` et la méthode `toLog()` à une classe PHP.\n\n## Instructions à Exécuter\n\n**IMPORTANT : Exécute ce workflow étape par étape :**\n\nFichier cible : $ARGUMENTS\n\n### 1. Lire et analyser le fichier\n\n- Lire le contenu du fichier PHP\n- Identifier la classe principale et ses propriétés\n- Vérifier si `LoggableInterface` est déjà implémentée\n\n### 2. Chercher les dépendances LoggableInterface\n\nPour chaque type-hint de propriété ou paramètre :\n- Utiliser Grep pour chercher si la classe implémente `LoggableInterface`\n- Noter les classes qui l'implémentent pour appeler `->toLog()` dessus\n\n### 3. Ajouter LoggableInterface\n\nSi la classe n'implémente pas encore `LoggableInterface` :\n\n**Ajouter l'import :**\n```php\nuse Atournayre\\Contracts\\Log\\LoggableInterface;\n```\n\n**Ajouter l'interface à la déclaration de classe :**\n```php\nfinal class NomClasse implements LoggableInterface\n```\n\n**Ajouter la méthode toLog() :**\n```php\n\u002F**\n * @return array\u003Cstring, mixed>\n *\u002F\npublic function toLog(): array\n{\n    return [\n        \u002F\u002F Propriétés clés de l'objet\n    ];\n}\n```\n\n### 4. Règles pour le contenu de toLog()\n\n**Propriétés à inclure :**\n- `id` (si présent)\n- Identifiants métier (email, code, référence...)\n- États\u002Fstatuts importants\n- Dates clés (createdAt, updatedAt...)\n\n**Propriétés à exclure :**\n- Mots de passe, tokens, secrets\n- Données personnelles sensibles\n- Propriétés volumineuses (blobs, textes longs)\n\n**Pour les objets imbriqués :**\n- Si l'objet implémente `LoggableInterface` : `'relation' => $this->relation->toLog()`\n- Sinon : `'relationId' => $this->relation->getId()` ou ignorer\n\n**Pour les collections :**\n```php\n\u002F**\n * @return array{count: int, items: array\u003Cint, array\u003Cstring, mixed>>}\n *\u002F\npublic function toLog(): array\n{\n    return [\n        'count' => $this->count(),\n        'items' => array_map(fn ($item) => $item->toLog(), $this->items),\n    ];\n}\n```\n\n### 5. Vérification PHPStan\n\n- Toujours ajouter `@return array\u003Cstring, mixed>` sur la méthode\n- Pour les collections : utiliser le type array shape approprié\n\n## Exemple de résultat\n\n```php\nuse Atournayre\\Contracts\\Log\\LoggableInterface;\n\nfinal class Commande implements LoggableInterface\n{\n    private Uuid $id;\n    private string $reference;\n    private Client $client;\n    private \\DateTimeImmutable $createdAt;\n    private string $password; \u002F\u002F Sensible, à exclure\n\n    \u002F**\n     * @return array\u003Cstring, mixed>\n     *\u002F\n    public function toLog(): array\n    {\n        return [\n            'id' => $this->id->toRfc4122(),\n            'reference' => $this->reference,\n            'client' => $this->client->toLog(),\n            'createdAt' => $this->createdAt->format('c'),\n            \u002F\u002F password exclu intentionnellement\n        ];\n    }\n}\n```\n",{"name":5,"model":30,"license":15,"version":31,"description":7,"allowed-tools":32,"argument-hint":37},"sonnet","1.0.0",[33,34,35,36],"Read","Edit","Grep","Glob",[38],"FICHIER","main","bb0335112ea0991dc1dc6a29fa5a861397a5a6f6","implementer\u002Fskills\u002Flog","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas","https:\u002F\u002Fatournayre.github.io\u002Fclaude-personas\u002F","https:\u002F\u002Fgithub.com\u002Fatournayre","🔵, Back End Developer, @symfony  :heart:, @rectorphp :heart:,  \r\n:bug: fixer (creator sometimes 🤫), member of @afup","2026-03-02 23:42:20",{"source":8,"skillName":5,"commands":48,"prompt":58,"zipAvailable":59},[49,52,55],{"tool":50,"command":51},"npx","npx skills add atournayre\u002Fclaude-personas --skill \"implementer:log\"",{"tool":53,"command":54},"bunx","bunx skills add atournayre\u002Fclaude-personas --skill \"implementer:log\"",{"tool":56,"command":57},"pnpm","pnpm dlx skills add atournayre\u002Fclaude-personas --skill \"implementer:log\"","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fimplementer\u002Fskills\u002Flog\u002FSKILL.md",true,[61],{"path":62,"resourceType":63,"resourceTypeDesc":64,"sizeBytes":65,"sourceHtmlUrl":66},"references\u002Fspec-workflow.md","REFERENCE","参考文档",5898,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Favivsinai\u002Fagent-message-queue\u002Fskills\u002Famq-spec\u002Freferences\u002Fspec-workflow.md",[68,81,121,128,136,147],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":74,"publishedAt":25},"01M6CSZPR0W1K1S9BX3247CZJ1","twig:make-component","Génère un Twig Component Symfony UX (classe PHP + template Twig)","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Ftwig\u002Fskills\u002Fmake-component\u002FSKILL.md",[],[75,76,23,24,77,78,22,79,21,80],"twig:make component","component","write","ux","template","Bash",{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":103,"publishedAt":25},"01M6CSZKCYYT4EAW4CDSTS3TSH","tester:ui-test","Teste automatiquement une interface utilisateur dans Chrome : navigation, clics, validation visuelle, tests fonctionnels, responsive, comportement et debug. Génère un rapport détaillé avec screenshots et optionnellement un GIF du parcours.","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Ftester\u002Fskills\u002Fui-test\u002FSKILL.md",[87,92,95,98],{"categoryNo":88,"categoryName":89,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":93,"categoryName":94,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":96,"categoryName":97,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":99,"categoryName":100,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[104,105,106,107,108,109,110,111,112,113,114,80,115,116,117,118,23,77,119,120],"test","ui","tester","ui test","tester:ui test","MCP","debug","create","update","validation","messages","plan","tool","page","find","javascript","chrome",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":127,"publishedAt":25},"01M6CSZGQ8X9XNXRBYX0AA3CYE","symfony:voter","Genere un Voter de securite Symfony pour le controle d'acces granulaire","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fvoter\u002FSKILL.md",[],[123,80,22,23,77,24],{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":25},"01M6CSZEJ3BNHCNZT18SYFGDME","symfony:message","Genere un Message Symfony Messenger avec son Handler pour traitement asynchrone","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fmessage\u002FSKILL.md",[],[130,135,80,22,23,77,24],"message",{"skillNo":137,"name":138,"nameZh":6,"description":139,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":140,"categories":141,"keywords":145,"publishedAt":25},"01M6CSZBWSK9M6YMJX886BVWYF","symfony:mailer","Genere un email Symfony (TemplatedEmail ou Notification) avec template Twig","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fmailer\u002FSKILL.md",[142],{"categoryNo":143,"categoryName":144,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000005","邮件与沟通",[138,24,146,80,79,22,23,77],"email",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":25},"01M6CSZ9DXMYZ9HTRE8A324AWG","symfony:form","Genere un FormType Symfony avec contraintes de validation et options","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fform\u002FSKILL.md",[],[149,80,22,23,77,24,154,113],"options"]