[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CSZ9DXMYZ9HTRE8A324AWG":3,"skill-same:01M6CSZ9DXMYZ9HTRE8A324AWG":68},{"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":26,"linkOnly":27,"markdownContent":28,"markdownBody":29,"frontMatter":30,"refName":40,"commitSha":41,"skillDirectory":42,"forksCount":14,"repositoryHtmlUrl":43,"repositoryHomepageUrl":44,"ownerHtmlUrl":45,"ownerBlogUrl":6,"ownerDescription":46,"updatedAt":47,"install":48,"resources":61},"01M6CSZ9DXMYZ9HTRE8A324AWG","symfony:form",null,"Genere un FormType Symfony avec contraintes de validation et options","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\u002Fform\u002FSKILL.md",[],[5,19,20,21,22,23,24,25],"validation","Bash","grep","read","write","edit","options","2026-11-10 10:12:30",false,"---\nname: symfony:form\ndescription: Genere un FormType Symfony avec contraintes de validation et options\nmodel: sonnet\nallowed-tools: [AskUserQuestion, Bash, Read, Write, Edit, Grep, Glob]\nversion: 1.0.0\nlicense: MIT\n---\n\n# Symfony Form Skill\n\nGenere un FormType Symfony complet avec champs types, contraintes de validation, options et bonnes pratiques.\n\n## Variables\n- **{FormName}** - Nom du formulaire en PascalCase (ex: ProductType)\n- **{namespace}** - Namespace du projet (defaut: App)\n- **{fields}** - Liste des champs avec types et contraintes\n\n## Outputs\n- `src\u002FForm\u002F{FormName}.php`\n\n## Instructions a Executer\n\n**IMPORTANT : Execute ce workflow etape par etape :**\n\n### 1. Demander le nom du formulaire\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quel est le nom du formulaire ? (ex: Product, UserRegistration)\"\n  Header: \"Formulaire\"\n  ```\n- Ajoute le suffixe `Type` si absent\n- Stocke dans FormName\n\n### 2. Demander les champs\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quels champs ? Format: name:TextType,email:EmailType,price:MoneyType,category:EntityType:Category,description:TextareaType:nullable\"\n  Header: \"Champs\"\n  ```\n- Parse la liste des champs :\n  - `name:FieldType` — champ simple\n  - `name:EntityType:TargetEntity` — champ relation Doctrine\n  - `name:Type:nullable` — champ nullable\n\n### 3. Demander les options avancees\n\n- Utilise AskUserQuestion (multiSelect: true) pour demander :\n  ```\n  Question: \"Quelles options activer ?\"\n  Header: \"Options\"\n  Options:\n    - \"Data class binding\" : \"Lier le formulaire a une classe PHP (entite\u002FDTO)\"\n    - \"CSRF protection\" : \"Protection CSRF explicite (active par defaut dans Symfony)\"\n    - \"Validation groups\" : \"Groupes de validation pour valider conditionnellement\"\n  ```\n\n### 4. Si Data class : demander la classe\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quelle est la classe de donnees liee ? (ex: App\\Entity\\Product, App\\Dto\\ProductInput)\"\n  Header: \"Data class\"\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 le FormType\n\n- Cree le fichier `src\u002FForm\u002F{FormName}.php` avec Write\n- Structure de classe :\n\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\Form;\n\nuse Symfony\\Component\\Form\\AbstractType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\TextType;\nuse Symfony\\Component\\Form\\FormBuilderInterface;\nuse Symfony\\Component\\OptionsResolver\\OptionsResolver;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\n\nfinal class {FormName} extends AbstractType\n{\n    public function buildForm(FormBuilderInterface $builder, array $options): void\n    {\n        $builder\n            ->add('name', TextType::class, [\n                'label' => 'Nom',\n                'constraints' => [\n                    new Assert\\NotBlank(),\n                    new Assert\\Length(max: 255),\n                ],\n            ])\n        ;\n    }\n\n    public function configureOptions(OptionsResolver $resolver): void\n    {\n        $resolver->setDefaults([\n            'data_class' => EntityClass::class,\n        ]);\n    }\n}\n```\n\n**Regles de generation :**\n- Classe `final` etendant `AbstractType`\n- Chaque champ a un type explicite (pas de devinette)\n- Contraintes de validation inline via `constraints` (pas d'annotations sur l'entite)\n- Types de champs Symfony utilises :\n  - `TextType`, `EmailType`, `PasswordType`, `TextareaType`\n  - `IntegerType`, `MoneyType`, `NumberType`, `PercentType`\n  - `ChoiceType`, `EntityType`, `EnumType`\n  - `DateType`, `DateTimeType`, `TimeType`\n  - `CheckboxType`, `FileType`, `HiddenType`\n  - `CollectionType`, `RepeatedType`\n- Pour `EntityType` : ajouter `class`, `choice_label`, `query_builder` si necessaire\n- Pour `ChoiceType` : ajouter `choices` avec les valeurs\n- Si validation groups : ajouter `'validation_groups'` dans `configureOptions`\n- Labels explicites pour chaque champ\n\n### 7. Afficher le resume\n\nAffiche :\n```\nFormType {FormName} genere avec succes\n\nFichiers crees :\n- src\u002FForm\u002F{FormName}.php\n\nChamps :\n{liste des champs avec types}\n\nUtilisation dans un controleur :\n  $form = $this->createForm({FormName}::class, $entity);\n  $form->handleRequest($request);\n  if ($form->isSubmitted() && $form->isValid()) {\n      \u002F\u002F Traitement\n  }\n\nProchaines etapes :\n- Ajuster les contraintes de validation\n- Personnaliser les labels et placeholders\n- Ajouter un template Twig si necessaire\n```\n\n## Patterns appliques\n\n### FormType\n- Classe `final`, extends `AbstractType`\n- Types de champs explicites\n- Contraintes de validation inline (`constraints` option)\n- `configureOptions()` pour data_class et defaults\n- Labels explicites\n\n## Notes\n- Preferer les contraintes inline (`constraints` dans les options du champ) aux annotations sur l'entite\n- Toujours specifier le type de champ explicitement (pas de type-guessing)\n- Utiliser `Assert\\` alias pour les contraintes\n- Pour les relations Doctrine, utiliser `EntityType` avec `query_builder` pour filtrer\n- `CollectionType` pour les relations one-to-many editables\n","# Symfony Form Skill\n\nGenere un FormType Symfony complet avec champs types, contraintes de validation, options et bonnes pratiques.\n\n## Variables\n- **{FormName}** - Nom du formulaire en PascalCase (ex: ProductType)\n- **{namespace}** - Namespace du projet (defaut: App)\n- **{fields}** - Liste des champs avec types et contraintes\n\n## Outputs\n- `src\u002FForm\u002F{FormName}.php`\n\n## Instructions a Executer\n\n**IMPORTANT : Execute ce workflow etape par etape :**\n\n### 1. Demander le nom du formulaire\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quel est le nom du formulaire ? (ex: Product, UserRegistration)\"\n  Header: \"Formulaire\"\n  ```\n- Ajoute le suffixe `Type` si absent\n- Stocke dans FormName\n\n### 2. Demander les champs\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quels champs ? Format: name:TextType,email:EmailType,price:MoneyType,category:EntityType:Category,description:TextareaType:nullable\"\n  Header: \"Champs\"\n  ```\n- Parse la liste des champs :\n  - `name:FieldType` — champ simple\n  - `name:EntityType:TargetEntity` — champ relation Doctrine\n  - `name:Type:nullable` — champ nullable\n\n### 3. Demander les options avancees\n\n- Utilise AskUserQuestion (multiSelect: true) pour demander :\n  ```\n  Question: \"Quelles options activer ?\"\n  Header: \"Options\"\n  Options:\n    - \"Data class binding\" : \"Lier le formulaire a une classe PHP (entite\u002FDTO)\"\n    - \"CSRF protection\" : \"Protection CSRF explicite (active par defaut dans Symfony)\"\n    - \"Validation groups\" : \"Groupes de validation pour valider conditionnellement\"\n  ```\n\n### 4. Si Data class : demander la classe\n\n- Utilise AskUserQuestion pour demander :\n  ```\n  Question: \"Quelle est la classe de donnees liee ? (ex: App\\Entity\\Product, App\\Dto\\ProductInput)\"\n  Header: \"Data class\"\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 le FormType\n\n- Cree le fichier `src\u002FForm\u002F{FormName}.php` avec Write\n- Structure de classe :\n\n```php\n\u003C?php\n\ndeclare(strict_types=1);\n\nnamespace {namespace}\\Form;\n\nuse Symfony\\Component\\Form\\AbstractType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\TextType;\nuse Symfony\\Component\\Form\\FormBuilderInterface;\nuse Symfony\\Component\\OptionsResolver\\OptionsResolver;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\n\nfinal class {FormName} extends AbstractType\n{\n    public function buildForm(FormBuilderInterface $builder, array $options): void\n    {\n        $builder\n            ->add('name', TextType::class, [\n                'label' => 'Nom',\n                'constraints' => [\n                    new Assert\\NotBlank(),\n                    new Assert\\Length(max: 255),\n                ],\n            ])\n        ;\n    }\n\n    public function configureOptions(OptionsResolver $resolver): void\n    {\n        $resolver->setDefaults([\n            'data_class' => EntityClass::class,\n        ]);\n    }\n}\n```\n\n**Regles de generation :**\n- Classe `final` etendant `AbstractType`\n- Chaque champ a un type explicite (pas de devinette)\n- Contraintes de validation inline via `constraints` (pas d'annotations sur l'entite)\n- Types de champs Symfony utilises :\n  - `TextType`, `EmailType`, `PasswordType`, `TextareaType`\n  - `IntegerType`, `MoneyType`, `NumberType`, `PercentType`\n  - `ChoiceType`, `EntityType`, `EnumType`\n  - `DateType`, `DateTimeType`, `TimeType`\n  - `CheckboxType`, `FileType`, `HiddenType`\n  - `CollectionType`, `RepeatedType`\n- Pour `EntityType` : ajouter `class`, `choice_label`, `query_builder` si necessaire\n- Pour `ChoiceType` : ajouter `choices` avec les valeurs\n- Si validation groups : ajouter `'validation_groups'` dans `configureOptions`\n- Labels explicites pour chaque champ\n\n### 7. Afficher le resume\n\nAffiche :\n```\nFormType {FormName} genere avec succes\n\nFichiers crees :\n- src\u002FForm\u002F{FormName}.php\n\nChamps :\n{liste des champs avec types}\n\nUtilisation dans un controleur :\n  $form = $this->createForm({FormName}::class, $entity);\n  $form->handleRequest($request);\n  if ($form->isSubmitted() && $form->isValid()) {\n      \u002F\u002F Traitement\n  }\n\nProchaines etapes :\n- Ajuster les contraintes de validation\n- Personnaliser les labels et placeholders\n- Ajouter un template Twig si necessaire\n```\n\n## Patterns appliques\n\n### FormType\n- Classe `final`, extends `AbstractType`\n- Types de champs explicites\n- Contraintes de validation inline (`constraints` option)\n- `configureOptions()` pour data_class et defaults\n- Labels explicites\n\n## Notes\n- Preferer les contraintes inline (`constraints` dans les options du champ) aux annotations sur l'entite\n- Toujours specifier le type de champ explicitement (pas de type-guessing)\n- Utiliser `Assert\\` alias pour les contraintes\n- Pour les relations Doctrine, utiliser `EntityType` avec `query_builder` pour filtrer\n- `CollectionType` pour les relations one-to-many editables\n",{"name":5,"model":31,"license":15,"version":32,"description":7,"allowed-tools":33},"sonnet","1.0.0",[34,20,35,36,37,38,39],"AskUserQuestion","Read","Write","Edit","Grep","Glob","main","bb0335112ea0991dc1dc6a29fa5a861397a5a6f6","symfony\u002Fskills\u002Fform","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":49,"prompt":59,"zipAvailable":60},[50,53,56],{"tool":51,"command":52},"npx","npx skills add atournayre\u002Fclaude-personas --skill \"symfony:form\"",{"tool":54,"command":55},"bunx","bunx skills add atournayre\u002Fclaude-personas --skill \"symfony:form\"",{"tool":57,"command":58},"pnpm","pnpm dlx skills add atournayre\u002Fclaude-personas --skill \"symfony:form\"","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fform\u002FSKILL.md",true,[62],{"path":63,"resourceType":64,"resourceTypeDesc":65,"sizeBytes":66,"sourceHtmlUrl":67},"evals\u002Ftriggers.json","REFERENCE","参考文档",1624,"https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Fsrc\u002Fskills\u002Fskill-improvement-pipeline\u002Fevals\u002Ftriggers.json",[69,81,120,127,135,146],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":26},"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",[],[76,77,78,20,79,80,21,22,23,24],"twig:make component","component","ux","php","template",{"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":26},"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,20,19,110,111,112,113,114,115,116,22,23,117,118,119],"tester","ui test","tester:ui test","ui","test","messages","update","plan","tool","page","chrome","create","find","debug","MCP","javascript",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":126,"publishedAt":26},"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",[],[122,20,21,22,23,24],{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":133,"publishedAt":26},"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",[],[129,134,21,20,22,23,24],"message",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":144,"publishedAt":26},"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",[141],{"categoryNo":142,"categoryName":143,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000005","邮件与沟通",[137,145,20,80,21,22,23,24],"email",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":152,"publishedAt":26},"01M6CSZ73A0RY9G0WY091HJGYV","symfony:event","Genere un Event Symfony + EventSubscriber ou EventListener","https:\u002F\u002Fgithub.com\u002Fatournayre\u002Fclaude-personas\u002Fblob\u002Fmain\u002Fsymfony\u002Fskills\u002Fevent\u002FSKILL.md",[],[148,21,22,23,24,20]]