[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CSZ73A0RY9G0WY091HJGYV":3,"skill-same:01M6CSZ73A0RY9G0WY091HJGYV":66},{"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":24,"linkOnly":25,"markdownContent":26,"markdownBody":27,"frontMatter":28,"refName":38,"commitSha":39,"skillDirectory":40,"forksCount":14,"repositoryHtmlUrl":41,"repositoryHomepageUrl":42,"ownerHtmlUrl":43,"ownerBlogUrl":6,"ownerDescription":44,"updatedAt":45,"install":46,"resources":59},"01M6CSZ73A0RY9G0WY091HJGYV","symfony:event",null,"Genere un Event Symfony + EventSubscriber ou EventListener","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\u002Fsymfony\u002Fskills\u002Fevent\u002FSKILL.md",[],[5,19,20,21,22,23],"Bash","grep","read","write","edit","2026-11-10 10:12:30",false,"---\nname: symfony:event\ndescription: Genere un Event Symfony + EventSubscriber ou EventListener\nmodel: sonnet\nallowed-tools: [AskUserQuestion, Bash, Read, Write, Edit, Grep, Glob]\nversion: 1.0.0\nlicense: MIT\n---\n\n# Symfony Event Skill\n\nGenere un Event personnalise et son EventSubscriber ou EventListener selon les bonnes pratiques Symfony.\n\n## Variables\n- **{EventName}** - Nom de l'event en PascalCase (ex: OrderPlaced)\n- **{HandlerName}** - Nom du subscriber\u002Flistener\n- **{namespace}** - Namespace du projet (defaut: App)\n\n## Outputs\n- `src\u002FEvent\u002F{EventName}.php`\n- `src\u002FEventSubscriber\u002F{HandlerName}Subscriber.php` ou `src\u002FEventListener\u002F{HandlerName}Listener.php`\n\n## Instructions a Executer\n\n**IMPORTANT : Execute ce workflow etape par etape :**\n\n### 1. Demander le nom de l'event\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quel est le nom de l'evenement ? (ex: OrderPlaced, UserRegistered, InvoiceGenerated)\"\n  Header: \"Event\"\n  ```\n- Stocke dans EventName\n\n### 2. Demander les proprietes de l'event\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quelles donnees porte l'evenement ? Format: order:Order,user:User,amount:float (laisser vide si aucune)\"\n  Header: \"Donnees\"\n  ```\n\n### 3. Demander le type de handler\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quel type de handler pour cet evenement ?\"\n  Header: \"Handler\"\n  Options:\n    - \"EventSubscriber (Recommande)\" : \"Classe qui s'abonne a un ou plusieurs events via getSubscribedEvents()\"\n    - \"EventListener\" : \"Classe avec attribut #[AsEventListener] sur la methode de traitement\"\n  ```\n\n### 4. Demander si l'event est stoppable\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"L'evenement peut-il etre stoppe par un listener ?\"\n  Header: \"Stoppable\"\n  Options:\n    - \"Non (Recommande)\" : \"Tous les listeners seront toujours executes\"\n    - \"Oui\" : \"Un listener peut stopper la propagation (StoppableEventInterface)\"\n  ```\n\n### 5. Detecter le namespace du projet\n\n- Lis `composer.json` avec Read\n- Extrais le namespace depuis `autoload.psr-4`\n- Si non trouve, utilise `App` par defaut\n\n### 6. Generer la classe Event\n\n- Cree le fichier `src\u002FEvent\u002F{EventName}.php` avec Write\n\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\Event;\n\nuse Symfony\\Contracts\\EventDispatcher\\Event;\n\nfinal class {EventName} extends Event\n{\n    public function __construct(\n        private readonly Order $order,\n        private readonly User $user,\n    ) {\n    }\n\n    public function getOrder(): Order\n    {\n        return $this->order;\n    }\n\n    public function getUser(): User\n    {\n        return $this->user;\n    }\n}\n```\n\n**Si stoppable :**\n```php\nuse Psr\\EventDispatcher\\StoppableEventInterface;\n\nfinal class {EventName} extends Event implements StoppableEventInterface\n{\n    private bool $propagationStopped = false;\n\n    public function isPropagationStopped(): bool\n    {\n        return $this->propagationStopped;\n    }\n\n    public function stopPropagation(): void\n    {\n        $this->propagationStopped = true;\n    }\n}\n```\n\n**Regles de generation :**\n- Classe `final`, extends `Symfony\\Contracts\\EventDispatcher\\Event`\n- Proprietes `private readonly` via promoted constructor\n- Getters pour chaque propriete\n- Pas de setters (event immuable apres creation)\n\n### 7. Generer le handler\n\n**EventSubscriber :**\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\EventSubscriber;\n\nuse {namespace}\\Event\\{EventName};\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\n\nfinal class {HandlerName}Subscriber implements EventSubscriberInterface\n{\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            {EventName}::class => 'on{EventName}',\n        ];\n    }\n\n    public function on{EventName}({EventName} $event): void\n    {\n        \u002F\u002F Logique de traitement\n    }\n}\n```\n\n**EventListener :**\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\EventListener;\n\nuse {namespace}\\Event\\{EventName};\nuse Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener;\n\nfinal class {HandlerName}Listener\n{\n    #[AsEventListener]\n    public function on{EventName}({EventName} $event): void\n    {\n        \u002F\u002F Logique de traitement\n    }\n}\n```\n\n### 8. Afficher le resume\n\nAffiche :\n```\nEvent {EventName} genere avec succes\n\nFichiers crees :\n- src\u002FEvent\u002F{EventName}.php\n- src\u002FEventSubscriber\u002F{HandlerName}Subscriber.php (ou Listener)\n\nDispatch de l'event :\n  $this->eventDispatcher->dispatch(new {EventName}($order, $user));\n\nProchaines etapes :\n- Implementer la logique dans le handler\n- Injecter les services necessaires\n- Dispatcher l'event depuis le service\u002Fcontroleur concerne\n```\n\n## Patterns appliques\n\n### Event\n- Classe `final`, immuable (readonly properties)\n- Extends `Symfony\\Contracts\\EventDispatcher\\Event`\n- Constructeur avec promoted properties\n- Getters uniquement, pas de setters\n\n### EventSubscriber\n- Implements `EventSubscriberInterface`\n- `getSubscribedEvents()` retourne un tableau statique\n- Peut s'abonner a plusieurs events\n\n### EventListener\n- Attribut `#[AsEventListener]` (Symfony 6.2+)\n- Une methode par event ecoute\n\n## Notes\n- Preferer `EventSubscriber` quand un handler ecoute plusieurs events\n- Preferer `EventListener` avec `#[AsEventListener]` pour un handler simple\n- Utiliser `Symfony\\Contracts\\EventDispatcher\\Event` (pas `Symfony\\Component\\EventDispatcher\\Event`)\n- Les events doivent etre immuables apres creation\n- Nommer les events au passe : `OrderPlaced`, `UserRegistered` (pas `OrderPlace`)\n","# Symfony Event Skill\n\nGenere un Event personnalise et son EventSubscriber ou EventListener selon les bonnes pratiques Symfony.\n\n## Variables\n- **{EventName}** - Nom de l'event en PascalCase (ex: OrderPlaced)\n- **{HandlerName}** - Nom du subscriber\u002Flistener\n- **{namespace}** - Namespace du projet (defaut: App)\n\n## Outputs\n- `src\u002FEvent\u002F{EventName}.php`\n- `src\u002FEventSubscriber\u002F{HandlerName}Subscriber.php` ou `src\u002FEventListener\u002F{HandlerName}Listener.php`\n\n## Instructions a Executer\n\n**IMPORTANT : Execute ce workflow etape par etape :**\n\n### 1. Demander le nom de l'event\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quel est le nom de l'evenement ? (ex: OrderPlaced, UserRegistered, InvoiceGenerated)\"\n  Header: \"Event\"\n  ```\n- Stocke dans EventName\n\n### 2. Demander les proprietes de l'event\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quelles donnees porte l'evenement ? Format: order:Order,user:User,amount:float (laisser vide si aucune)\"\n  Header: \"Donnees\"\n  ```\n\n### 3. Demander le type de handler\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quel type de handler pour cet evenement ?\"\n  Header: \"Handler\"\n  Options:\n    - \"EventSubscriber (Recommande)\" : \"Classe qui s'abonne a un ou plusieurs events via getSubscribedEvents()\"\n    - \"EventListener\" : \"Classe avec attribut #[AsEventListener] sur la methode de traitement\"\n  ```\n\n### 4. Demander si l'event est stoppable\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"L'evenement peut-il etre stoppe par un listener ?\"\n  Header: \"Stoppable\"\n  Options:\n    - \"Non (Recommande)\" : \"Tous les listeners seront toujours executes\"\n    - \"Oui\" : \"Un listener peut stopper la propagation (StoppableEventInterface)\"\n  ```\n\n### 5. Detecter le namespace du projet\n\n- Lis `composer.json` avec Read\n- Extrais le namespace depuis `autoload.psr-4`\n- Si non trouve, utilise `App` par defaut\n\n### 6. Generer la classe Event\n\n- Cree le fichier `src\u002FEvent\u002F{EventName}.php` avec Write\n\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\Event;\n\nuse Symfony\\Contracts\\EventDispatcher\\Event;\n\nfinal class {EventName} extends Event\n{\n    public function __construct(\n        private readonly Order $order,\n        private readonly User $user,\n    ) {\n    }\n\n    public function getOrder(): Order\n    {\n        return $this->order;\n    }\n\n    public function getUser(): User\n    {\n        return $this->user;\n    }\n}\n```\n\n**Si stoppable :**\n```php\nuse Psr\\EventDispatcher\\StoppableEventInterface;\n\nfinal class {EventName} extends Event implements StoppableEventInterface\n{\n    private bool $propagationStopped = false;\n\n    public function isPropagationStopped(): bool\n    {\n        return $this->propagationStopped;\n    }\n\n    public function stopPropagation(): void\n    {\n        $this->propagationStopped = true;\n    }\n}\n```\n\n**Regles de generation :**\n- Classe `final`, extends `Symfony\\Contracts\\EventDispatcher\\Event`\n- Proprietes `private readonly` via promoted constructor\n- Getters pour chaque propriete\n- Pas de setters (event immuable apres creation)\n\n### 7. Generer le handler\n\n**EventSubscriber :**\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\EventSubscriber;\n\nuse {namespace}\\Event\\{EventName};\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\n\nfinal class {HandlerName}Subscriber implements EventSubscriberInterface\n{\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            {EventName}::class => 'on{EventName}',\n        ];\n    }\n\n    public function on{EventName}({EventName} $event): void\n    {\n        \u002F\u002F Logique de traitement\n    }\n}\n```\n\n**EventListener :**\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\EventListener;\n\nuse {namespace}\\Event\\{EventName};\nuse Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener;\n\nfinal class {HandlerName}Listener\n{\n    #[AsEventListener]\n    public function on{EventName}({EventName} $event): void\n    {\n        \u002F\u002F Logique de traitement\n    }\n}\n```\n\n### 8. Afficher le resume\n\nAffiche :\n```\nEvent {EventName} genere avec succes\n\nFichiers crees :\n- src\u002FEvent\u002F{EventName}.php\n- src\u002FEventSubscriber\u002F{HandlerName}Subscriber.php (ou Listener)\n\nDispatch de l'event :\n  $this->eventDispatcher->dispatch(new {EventName}($order, $user));\n\nProchaines etapes :\n- Implementer la logique dans le handler\n- Injecter les services necessaires\n- Dispatcher l'event depuis le service\u002Fcontroleur concerne\n```\n\n## Patterns appliques\n\n### Event\n- Classe `final`, immuable (readonly properties)\n- Extends `Symfony\\Contracts\\EventDispatcher\\Event`\n- Constructeur avec promoted properties\n- Getters uniquement, pas de setters\n\n### EventSubscriber\n- Implements `EventSubscriberInterface`\n- `getSubscribedEvents()` retourne un tableau statique\n- Peut s'abonner a plusieurs events\n\n### EventListener\n- Attribut `#[AsEventListener]` (Symfony 6.2+)\n- Une methode par event ecoute\n\n## Notes\n- Preferer `EventSubscriber` quand un handler ecoute plusieurs events\n- Preferer `EventListener` avec `#[AsEventListener]` pour un handler simple\n- Utiliser `Symfony\\Contracts\\EventDispatcher\\Event` (pas `Symfony\\Component\\EventDispatcher\\Event`)\n- Les events doivent etre immuables apres creation\n- Nommer les events au passe : `OrderPlaced`, `UserRegistered` (pas `OrderPlace`)\n",{"name":5,"model":29,"license":15,"version":30,"description":7,"allowed-tools":31},"sonnet","1.0.0",[32,19,33,34,35,36,37],"AskUserQuestion","Read","Write","Edit","Grep","Glob","main","bb0335112ea0991dc1dc6a29fa5a861397a5a6f6","symfony\u002Fskills\u002Fevent","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":47,"prompt":57,"zipAvailable":58},[48,51,54],{"tool":49,"command":50},"npx","npx skills add atournayre\u002Fclaude-personas --skill \"symfony:event\"",{"tool":52,"command":53},"bunx","bunx skills add atournayre\u002Fclaude-personas --skill \"symfony:event\"",{"tool":55,"command":56},"pnpm","pnpm dlx skills add atournayre\u002Fclaude-personas --skill \"symfony:event\"","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fevent\u002FSKILL.md",true,[60],{"path":61,"resourceType":62,"resourceTypeDesc":63,"sizeBytes":64,"sourceHtmlUrl":65},"evals\u002Ftriggers.json","REFERENCE","参考文档",1642,"https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Fsrc\u002Fskills\u002Fserver-hardening\u002Fevals\u002Ftriggers.json",[67,79,119,126,134,145],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":24},"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",[],[74,75,21,23,22,76,20,77,78,19],"twig:make component","component","ux","template","php",{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":101,"publishedAt":24},"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",[85,90,93,96],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":91,"categoryName":92,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":94,"categoryName":95,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":97,"categoryName":98,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[102,103,104,105,106,107,108,109,110,111,112,19,113,114,115,116,21,22,117,118],"test","ui","tester","ui test","tester:ui test","MCP","debug","create","update","validation","messages","plan","tool","page","find","javascript","chrome",{"skillNo":120,"name":121,"nameZh":6,"description":122,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":125,"publishedAt":24},"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",[],[121,19,20,21,22,23],{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":24},"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",[],[128,133,19,20,21,22,23],"message",{"skillNo":135,"name":136,"nameZh":6,"description":137,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":138,"categories":139,"keywords":143,"publishedAt":24},"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",[140],{"categoryNo":141,"categoryName":142,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000005","邮件与沟通",[136,23,144,19,77,20,21,22],"email",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":151,"publishedAt":24},"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",[],[147,19,20,21,22,23,152,111],"options"]