From ba942a1a413fb17f3aac79681fa7ffc8518bef02 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 18 May 2026 16:54:37 +0900 Subject: [PATCH 1/5] Document Ray.WebFormModule 1.0.0 #[CsrfProtection] attribute Reflect the BC break in Ray.WebFormModule 1.0.0 where CSRF protection is now opt-in via a separate #[CsrfProtection] attribute, instead of the removed antiCsrf=true option on #[FormValidation]. Also fix the legacy AuraInputModule references in the English manual to match the current WebFormModule name. --- manuals/1.0/en/form.md | 20 +++++++++++++++++--- manuals/1.0/ja/form.md | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/manuals/1.0/en/form.md b/manuals/1.0/en/form.md index e67680ec..e0a1c1d8 100644 --- a/manuals/1.0/en/form.md +++ b/manuals/1.0/en/form.md @@ -18,7 +18,7 @@ Install `ray/web-form-module` via composer to add form using Aura.Input composer require ray/web-form-module ``` -Install `AuraInputModule` in our application module `src/Module/AppModule.php` +Install `WebFormModule` in our application module `src/Module/AppModule.php` ```php use BEAR\Package\AbstractAppModule; @@ -29,7 +29,7 @@ class AppModule extends AbstractAppModule protected function configure() { // ... - $this->install(new AuraInputModule); + $this->install(new WebFormModule); } } ``` @@ -137,6 +137,20 @@ class MyForm extends AbstractForm use SetAntiCsrfTrait; ``` +CSRF verification is opt-in: it runs only on methods annotated with the `#[CsrfProtection]` attribute. Methods without the attribute perform no CSRF check even when the form has an `AntiCsrf` object set. + +```php +use Ray\WebFormModule\Annotation\CsrfProtection; +use Ray\WebFormModule\Annotation\FormValidation; + +#[FormValidation(form: 'contactForm')] +#[CsrfProtection] +public function onPost($name, $age) +{ + // executed only when the CSRF token is valid +} +``` + In order to increase the security level, add a custom CSRF class that contains the user authentication to the form class. Please refer to the [Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections) of Aura.Input for more information. @@ -186,7 +200,7 @@ class FooModule extends AbstractModule { protected function configure() { - $this->install(new AuraInputModule); + $this->install(new WebFormModule); $this->override(new FormVndErrorModule); } } diff --git a/manuals/1.0/ja/form.md b/manuals/1.0/ja/form.md index e98f87c4..145ec6be 100644 --- a/manuals/1.0/ja/form.md +++ b/manuals/1.0/ja/form.md @@ -17,7 +17,7 @@ Aura.Inputを使用したフォーム処理を追加するために、composer composer require ray/web-form-module ``` -アプリケーションモジュール`src/Module/AppModule.php`で`AuraInputModule`をインストールします: +アプリケーションモジュール`src/Module/AppModule.php`で`WebFormModule`をインストールします: ```php use BEAR\Package\AbstractAppModule; @@ -136,6 +136,20 @@ class MyForm extends AbstractForm } ``` +CSRFチェックはオプトインで、`#[CsrfProtection]`アトリビュートを付与したメソッドに対してのみ実行されます。アトリビュートが無いメソッドでは、フォームに`AntiCsrf`オブジェクトがセットされていてもCSRF検証は行われません: + +```php +use Ray\WebFormModule\Annotation\CsrfProtection; +use Ray\WebFormModule\Annotation\FormValidation; + +#[FormValidation(form: 'contactForm')] +#[CsrfProtection] +public function onPost($name, $age) +{ + // CSRFトークンが正しい場合のみ実行される +} +``` + セキュリティレベルを高めるには、ユーザーの認証を含んだカスタムCsrfクラスを作成してフォームクラスにセットします。詳しくはAura.Inputの[Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections)をご覧ください。 ## #[InputValidation] From 0086776942adce002d214ed9c4c1ab0dfcc152f6 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 18 May 2026 16:58:51 +0900 Subject: [PATCH 2/5] Refine form manual to match Ray.WebFormModule 1.0.0 Refresh both the Japanese and English form manuals to align with the 1.0.0 source of truth and README: - Revert the previous WebFormModule rename: the real class is still AuraInputModule (no rename happened in 1.0.0). - Document the actual #[FormValidation] parameters (form, onFailure) instead of the obsolete onValidationFailed name, and keep the default ValidationFailed suffix behaviour. - Use the modern method-injection style for the form (#[Inject] setForm(#[Named] FormInterface) with typed properties), matching the README and tests. - Tighten init()/onPost() signatures with explicit return types and parameter types to match PHP 8 typed APIs. - Note that the entire form can be rendered with echo when the form implements ToStringInterface. - Replace the standalone CSRF section with the opt-in #[CsrfProtection] explanation from the README. - Add a 'Migration from 0.x' table summarising the BC breaks (Doctrine annotations to attributes, antiCsrf=true to #[CsrfProtection], Reader argument removal, FormInterface signature updates) and link to the migrate-to-1.0 Claude Code skill. --- manuals/1.0/en/form.md | 160 +++++++++++++++++++++++------------------ manuals/1.0/ja/form.md | 135 ++++++++++++++++++++-------------- 2 files changed, 171 insertions(+), 124 deletions(-) diff --git a/manuals/1.0/en/form.md b/manuals/1.0/en/form.md index e0a1c1d8..84009511 100644 --- a/manuals/1.0/en/form.md +++ b/manuals/1.0/en/form.md @@ -7,37 +7,35 @@ permalink: /manuals/1.0/en/form.html # Form -Each related function of Web Forms using [Aura.Input](https://github.com/auraphp/Aura.Input) and [Aura.Filter](https://github.com/auraphp/Aura.Filter) is aggregated to a single class so that it is easy to test and change. -We can use a corresponding class for the use of Web Forms and validation. +Web form handling powered by [Aura.Input](https://github.com/auraphp/Aura.Input) and [Aura.Filter](https://github.com/auraphp/Aura.Filter) aggregates related functionality into a single class, making it easy to test and modify. A single form class can serve both rendering and validation. ## Install -Install `ray/web-form-module` via composer to add form using Aura.Input +Install `ray/web-form-module` with composer: ```bash composer require ray/web-form-module ``` -Install `WebFormModule` in our application module `src/Module/AppModule.php` +Install `AuraInputModule` in your application module at `src/Module/AppModule.php`: ```php use BEAR\Package\AbstractAppModule; -use Ray\WebFormModule\WebFormModule; +use Ray\WebFormModule\AuraInputModule; class AppModule extends AbstractAppModule { protected function configure() { // ... - $this->install(new WebFormModule); + $this->install(new AuraInputModule()); } } ``` -## Web Form +## Form Class -Create **a form class** that defines the registration and the rules of form elements, then bind it to a method using `#[FormValidation]` attribute. -The method runs only when the sent data is validated. +Create a **form class** that defines input elements and validation rules, then bind it to a method with the `#[FormValidation]` attribute. The method only runs when validation succeeds. ```php use Ray\WebFormModule\AbstractForm; @@ -45,33 +43,31 @@ use Ray\WebFormModule\SetAntiCsrfTrait; class MyForm extends AbstractForm { - /** - * {@inheritdoc} - */ - public function init() + use SetAntiCsrfTrait; + + public function init(): void { - // set input fields + // register input fields $this->setField('name', 'text') - ->setAttribs([ - 'id' => 'name' - ]); - // set rules and user defined error message + ->setAttribs(['id' => 'name']); + + // set validation rules and user-defined error messages $this->filter->validate('name')->is('alnum'); $this->filter->useFieldMessage('name', 'Name must be alphabetic only.'); } } ``` -We can register the input elements in the `init()` method of the form class and apply the rules of validation and sanitation. -Please refer to [Rules To Validate Fields](https://github.com/auraphp/Aura.Filter/blob/2.x/docs/validate.md) of Aura.Filter with respect to validation rules, and [Rules To Sanitize Fields](https://github.com/auraphp/Aura.Filter/blob/2.x/docs/sanitize.md) with respect to sanitize rules. +Register input elements inside `init()` and apply validation and sanitization rules. See: -We validate an associative array of the argument of the method. -If we want to change the input, we can set the values by implementing `submit()` method of `SubmitInterface` interface. +- [Rules To Validate Fields](https://github.com/auraphp/Aura.Filter/blob/2.x/docs/validate.md) +- [Rules To Sanitize Fields](https://github.com/auraphp/Aura.Filter/blob/2.x/docs/sanitize.md) + +The associative array of method arguments is validated. To change the input, implement `SubmitInterface::submit()` and return the values to use. ## #[FormValidation] Attribute -Annotate the method that we want to validate with the `#[FormValidation]`, so that the validation is done in the form object specified by the `form` property before execution. -When validation fails, the method with the `ValidationFailed` suffix is called. +A method annotated with `#[FormValidation]` is validated before execution against the form object referenced by the `form` property. When validation fails, the method whose name is suffixed with `ValidationFailed` is invoked instead: ```php use Ray\Di\Di\Inject; @@ -81,85 +77,93 @@ use Ray\WebFormModule\FormInterface; class MyController { - protected FormInterface $form; + protected FormInterface $contactForm; #[Inject] - #[Named('contact_form')] - public function setForm(FormInterface $form) + public function setForm(#[Named('contact_form')] FormInterface $form): void { - $this->form = $form; + $this->contactForm = $form; } - #[FormValidation] - // or - // #[FormValidation(form: 'form', onFailure: 'onPostValidationFailed')] - public function onPost($name, $age) + #[FormValidation(form: 'contactForm')] + public function onPost(string $name, int $age): ResourceObject { // validation success } - public function onPostValidationFailed($name, $age) + public function onPostValidationFailed(string $name, int $age): ResourceObject { - // validation failed + // validation failure } } ``` -We can explicitly specify the name and the method by changing the `form` property of `#[FormValidation]` attribute or the `onValidationFailed` property. +Use the `form` property of `#[FormValidation]` to point to a different form property, and `onFailure` to specify a custom failure-handler method name: + +```php +#[FormValidation(form: 'contactForm', onFailure: 'badRequestAction')] +public function onPost(string $name, int $age): ResourceObject +{ +} +``` -The submit parameters will be passed to the `onPostValidationFailed` method. +The submitted arguments are forwarded to the failure-handler method. ## View -Specify the element name to get the `input` elements and error messages +Pass the element name to render the `input` markup or to fetch the error message: ```php - $form->input('name'); // - $form->error('name'); // "Please enter a double-byte characters or letters in the name." or blank +$form->input('name'); // e.g. +$form->error('name'); // e.g. "Name must be alphabetic only." ``` -The same applies to Twig template +The same works in Twig templates: -```php +```twig {% raw %}{{ form.input('name') }} {{ form.error('name') }}{% endraw %} ``` +If the form class implements `ToStringInterface`, the whole form can be rendered by casting it to string: + +```php +echo $form; // render the entire form HTML +``` + ## CSRF Protections -We can add a CSRF(Cross site request forgeries) object to the form to apply CSRF protections. +CSRF protection is **opt-in**. A form that uses `SetAntiCsrfTrait` is wired with an `AntiCsrfInterface`, but the token is only verified on methods annotated with `#[CsrfProtection]`. Methods without `#[CsrfProtection]` perform no CSRF check even if the form has an `AntiCsrf` object set. ```php +use Ray\WebFormModule\AbstractForm; +use Ray\WebFormModule\Annotation\CsrfProtection; +use Ray\WebFormModule\Annotation\FormValidation; use Ray\WebFormModule\SetAntiCsrfTrait; class MyForm extends AbstractForm { use SetAntiCsrfTrait; -``` - -CSRF verification is opt-in: it runs only on methods annotated with the `#[CsrfProtection]` attribute. Methods without the attribute perform no CSRF check even when the form has an `AntiCsrf` object set. - -```php -use Ray\WebFormModule\Annotation\CsrfProtection; -use Ray\WebFormModule\Annotation\FormValidation; +} -#[FormValidation(form: 'contactForm')] -#[CsrfProtection] -public function onPost($name, $age) +class MyController { - // executed only when the CSRF token is valid + #[FormValidation(form: 'contactForm')] + #[CsrfProtection] + public function onPost(string $name, int $age): ResourceObject + { + // executed only when the CSRF token is valid + } } ``` -In order to increase the security level, add a custom CSRF class that contains the user authentication to the form class. -Please refer to the [Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections) of Aura.Input for more information. +To raise the security level, provide a custom CSRF class that incorporates user authentication and set it on the form. See [Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections) in Aura.Input for details. -## #[InputValidation] attribute +## #[InputValidation] -If we annotate the method with `#[InputValidation]` instead of `#[FormValidation]`, the exception `Ray\WebFormModule\Exception\ValidationException` is thrown when validation fails. -For convenience, HTML representation is not used in this case. +If a method is annotated with `#[InputValidation]` instead of `#[FormValidation]`, a `Ray\WebFormModule\Exception\ValidationException` is thrown when validation fails. No HTML representation is used, which is convenient for Web APIs. -When we `echo` the `error` property of the caught exception, we can see the representation of the media type [application/vnd.error+json](https://github.com/blongden/vnd.error). +`echo`ing the `error` property of the caught exception outputs an [application/vnd.error+json](https://github.com/blongden/vnd.error) representation: ```php http_response_code(400); @@ -170,13 +174,13 @@ echo $e->error; // "path": "/path/to/error", // "validation_messages": { // "name": [ -// "Please enter a double-byte characters or letters in the name." +// "Name must be alphabetic only." // ] // } // } ``` -We can add the necessary information to `vnd.error+json` using `#[VndError]` attribute. +Use the `#[VndError]` attribute to enrich the `vnd.error+json` payload: ```php #[FormValidation(form: 'contactForm')] @@ -186,27 +190,45 @@ We can add the necessary information to `vnd.error+json` using `#[VndError]` att path: '/path/to/error', href: ['_self' => '/path/to/error', 'help' => '/path/to/help'] )] -public function onPost() +public function onPost(): ResourceObject +{ +} ``` ## FormVndErrorModule -If we install `Ray\WebFormModule\FormVndErrorModule`, the method annotated with `#[FormValidation]` -will throw an exception in the same way as the method annotated with `#[InputValidation]`. -We can use the page resources as API. +Install `Ray\WebFormModule\FormVndErrorModule` to make `#[FormValidation]` methods throw the same exception as `#[InputValidation]` methods. Page resources can then be reused as API endpoints: ```php +use Ray\Di\AbstractModule; +use Ray\WebFormModule\AuraInputModule; +use Ray\WebFormModule\FormVndErrorModule; + class FooModule extends AbstractModule { protected function configure() { - $this->install(new WebFormModule); - $this->override(new FormVndErrorModule); + $this->install(new AuraInputModule()); + $this->override(new FormVndErrorModule()); } } ``` +## Migration from 0.x + +Version 1.0 drops Doctrine Annotations in favour of native PHP 8 Attributes and tightens type declarations. The most common rewrites: + +| Before (0.x) | After (1.0) | +| --- | --- | +| `@FormValidation(form="f", onFailure="badRequest")` | `#[FormValidation(form: 'f', onFailure: 'badRequest')]` | +| `@FormValidation(form="f", antiCsrf=true)` | `#[FormValidation(form: 'f')]` + `#[CsrfProtection]` | +| `@InputValidation(form="f")` | `#[InputValidation(form: 'f')]` | +| `@VndError(message="...", logref="...")` | `#[VndError(message: '...', logref: '...')]` | +| `new AuraInputInterceptor($injector, $reader)` | `new AuraInputInterceptor($injector)` (no `Reader` argument) | +| `public function input($input)` / `error($input)` | `public function input(string $input): string` / `error(string $input): string` | + +See the [CHANGELOG](https://github.com/ray-di/Ray.WebFormModule/blob/1.x/CHANGELOG.md) for the full list of breaking changes. A Claude Code skill `migrate-to-1.0` is shipped in the same repository to automate these rewrites. + ## Demo -Try the demo app [MyVendor.ContactForm](https://github.com/bearsunday/MyVendor.ContactForm) to get an idea on how forms such as -a confirmation form and multiple forms in a single page work. +Try the demo app [MyVendor.ContactForm](https://github.com/bearsunday/MyVendor.ContactForm) to see how a confirmation form and multiple forms on a single page work. diff --git a/manuals/1.0/ja/form.md b/manuals/1.0/ja/form.md index 145ec6be..a2b11b5b 100644 --- a/manuals/1.0/ja/form.md +++ b/manuals/1.0/ja/form.md @@ -7,35 +7,35 @@ permalink: /manuals/1.0/ja/form.html # フォーム -[Aura.Input](https://github.com/auraphp/Aura.Input)と[Aura.Filter](https://github.com/auraphp/Aura.Filter)を使用したWebフォーム機能は、関連する機能が単一のクラスに集約され、テストや変更が容易です。1つのクラスでWebフォームとバリデーションの両方の用途に使用できます。 +[Aura.Input](https://github.com/auraphp/Aura.Input)と[Aura.Filter](https://github.com/auraphp/Aura.Filter)を使ったWebフォーム機能は、関連する処理を単一のクラスに集約するため、テストや変更が容易です。1つのフォームクラスをWebフォームの表示とバリデーションの両方に使用できます。 ## インストール -Aura.Inputを使用したフォーム処理を追加するために、composerで`ray/web-form-module`をインストールします: +composerで`ray/web-form-module`をインストールします: ```bash composer require ray/web-form-module ``` -アプリケーションモジュール`src/Module/AppModule.php`で`WebFormModule`をインストールします: +アプリケーションモジュール`src/Module/AppModule.php`で`AuraInputModule`をインストールします: ```php use BEAR\Package\AbstractAppModule; -use Ray\WebFormModule\WebFormModule; +use Ray\WebFormModule\AuraInputModule; class AppModule extends AbstractAppModule { protected function configure() { // ... - $this->install(new WebFormModule); + $this->install(new AuraInputModule()); } } ``` -## Webフォーム +## フォームクラス -フォーム要素の登録やルールを定めた**フォームクラス**を作成して、`#[FormValidation]`アトリビュートを使用して特定のメソッドと束縛します。メソッドは送信されたデータがバリデーションOKのときのみ実行されます。 +フォーム要素の登録とバリデーションルールを定義する**フォームクラス**を作成し、`#[FormValidation]`アトリビュートで特定のメソッドに束縛します。バリデーションが成功したときだけ、そのメソッドが実行されます。 ```php use Ray\WebFormModule\AbstractForm; @@ -43,16 +43,13 @@ use Ray\WebFormModule\SetAntiCsrfTrait; class MyForm extends AbstractForm { - /** - * {@inheritdoc} - */ - public function init() + use SetAntiCsrfTrait; + + public function init(): void { - // フォームフィールドの設定 + // フォームフィールドの登録 $this->setField('name', 'text') - ->setAttribs([ - 'id' => 'name' - ]); + ->setAttribs(['id' => 'name']); // バリデーションルールとエラーメッセージの設定 $this->filter->validate('name')->is('alnum'); @@ -61,17 +58,16 @@ class MyForm extends AbstractForm } ``` -フォームクラスの`init()`メソッドでフォームのinput要素を登録し、バリデーションのフィルターやサニタイズのルールを適用します。 +`init()`メソッドでフォームの入力要素を登録し、バリデーションフィルターやサニタイズルールを適用します。詳しいルールは以下を参照してください: -バリデーションルールについては以下を参照してください: - [Rules To Validate Fields](https://github.com/auraphp/Aura.Filter/blob/2.x/docs/validate.md) - [Rules To Sanitize Fields](https://github.com/auraphp/Aura.Filter/blob/2.x/docs/sanitize.md) -メソッドの引数を連想配列にしたものをバリデーションします。入力を変更したい場合は`SubmitInterface`インターフェイスの`submit()`メソッドを実装して入力する値を返します。 +メソッドの引数を連想配列にしたものをバリデーションします。入力値を加工したい場合は`SubmitInterface::submit()`を実装して値を返します。 ## #[FormValidation]アトリビュート -フォームのバリデーションを行うメソッドを`#[FormValidation]`でアノテートすると、実行前に`form`プロパティのフォームオブジェクトでバリデーションが行われます。バリデーションに失敗するとメソッド名に`ValidationFailed`サフィックスをつけたメソッドが呼ばれます: +`#[FormValidation]`アトリビュートを付けたメソッドは、実行前に`form`プロパティのフォームオブジェクトでバリデーションされます。バリデーションが失敗すると、メソッド名に`ValidationFailed`サフィックスを付けたメソッドが呼び出されます: ```php use Ray\Di\Di\Inject; @@ -81,82 +77,93 @@ use Ray\WebFormModule\FormInterface; class MyController { - protected FormInterface $form; + protected FormInterface $contactForm; #[Inject] - #[Named('contact_form')] - public function setForm(FormInterface $form) + public function setForm(#[Named('contact_form')] FormInterface $form): void { - $this->form = $form; + $this->contactForm = $form; } - #[FormValidation] - // または - // #[FormValidation(form: 'form', onFailure: 'onPostValidationFailed')] - public function onPost($name, $age) + #[FormValidation(form: 'contactForm')] + public function onPost(string $name, int $age): ResourceObject { // バリデーション成功時の処理 } - public function onPostValidationFailed($name, $age) + public function onPostValidationFailed(string $name, int $age): ResourceObject { // バリデーション失敗時の処理 } } ``` -`#[FormValidation]`アトリビュートの`form`と`onValidationFailed`プロパティを変更して、`form`プロパティの名前やメソッドの名前を明示的に指定することもできます。`onPostValidationFailed`にはサブミットされた値が渡されます。 +`#[FormValidation]`の`form`プロパティでフォームプロパティ名を、`onFailure`プロパティで失敗時に呼び出すメソッド名を明示できます: + +```php +#[FormValidation(form: 'contactForm', onFailure: 'badRequestAction')] +public function onPost(string $name, int $age): ResourceObject +{ +} +``` + +失敗時メソッドにはサブミットされた引数がそのまま渡されます。 ## ビュー フォームの`input`要素やエラーメッセージを取得するには要素名を指定します: ```php -$form->input('name'); // 出力例: -$form->error('name'); // 出力例:名前は英数字のみ使用できます。 +$form->input('name'); // 例: +$form->error('name'); // 例:名前は英数字のみ使用できます。 ``` -Twigテンプレートを使用する場合も同様です: +Twigテンプレートでも同様です: ```twig {% raw %}{{ form.input('name') }} {{ form.error('name') }}{% endraw %} ``` +フォームクラスが`ToStringInterface`を実装していれば、フォーム全体を文字列として出力できます: + +```php +echo $form; // フォーム全体のHTMLを描画 +``` + ## CSRF -CSRF(クロスサイトリクエストフォージェリ)対策を行うためには、フォームにCSRFオブジェクトをセットします: +CSRF(クロスサイトリクエストフォージェリ)保護はopt-inです。フォームに`SetAntiCsrfTrait`を使うと`AntiCsrfInterface`が組み込まれますが、トークンの検証は`#[CsrfProtection]`アトリビュートを付けたメソッドでのみ実行されます。アトリビュートが無いメソッドでは、フォームが`AntiCsrf`オブジェクトを持っていてもCSRF検証は行われません。 ```php +use Ray\WebFormModule\AbstractForm; +use Ray\WebFormModule\Annotation\CsrfProtection; +use Ray\WebFormModule\Annotation\FormValidation; use Ray\WebFormModule\SetAntiCsrfTrait; class MyForm extends AbstractForm { use SetAntiCsrfTrait; } -``` -CSRFチェックはオプトインで、`#[CsrfProtection]`アトリビュートを付与したメソッドに対してのみ実行されます。アトリビュートが無いメソッドでは、フォームに`AntiCsrf`オブジェクトがセットされていてもCSRF検証は行われません: - -```php -use Ray\WebFormModule\Annotation\CsrfProtection; -use Ray\WebFormModule\Annotation\FormValidation; - -#[FormValidation(form: 'contactForm')] -#[CsrfProtection] -public function onPost($name, $age) +class MyController { - // CSRFトークンが正しい場合のみ実行される + #[FormValidation(form: 'contactForm')] + #[CsrfProtection] + public function onPost(string $name, int $age): ResourceObject + { + // CSRFトークンが正しい場合のみ実行される + } } ``` -セキュリティレベルを高めるには、ユーザーの認証を含んだカスタムCsrfクラスを作成してフォームクラスにセットします。詳しくはAura.Inputの[Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections)をご覧ください。 +セキュリティレベルを高めるには、ユーザー認証を組み込んだカスタムCsrfクラスを作成してフォームクラスにセットします。詳しくはAura.Inputの[Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections)を参照してください。 ## #[InputValidation] -`#[FormValidation]`の代わりに`#[InputValidation]`とアノテートすると、バリデーションが失敗したときに`Ray\WebFormModule\Exception\ValidationException`が投げられます。この場合はHTML表現は使用されません。Web APIに便利です。 +`#[FormValidation]`の代わりに`#[InputValidation]`を使うと、バリデーション失敗時に`Ray\WebFormModule\Exception\ValidationException`が投げられます。HTML表現を使用しないのでWeb APIに便利です。 -キャッチした例外の`error`プロパティを`echo`すると[application/vnd.error+json](https://github.com/blongden/vnd.error)メディアタイプの表現が出力されます: +キャッチした例外の`error`プロパティを`echo`すると、[application/vnd.error+json](https://github.com/blongden/vnd.error)メディアタイプの表現が出力されます: ```php http_response_code(400); @@ -174,7 +181,7 @@ echo $e->error; // } ``` -`#[VndError]`アトリビュートで`vnd.error+json`に必要な情報を追加できます: +`#[VndError]`アトリビュートで`vnd.error+json`に追加情報を付与できます: ```php #[FormValidation(form: 'contactForm')] @@ -184,27 +191,45 @@ echo $e->error; path: '/path/to/error', href: ['_self' => '/path/to/error', 'help' => '/path/to/help'] )] -public function onPost() +public function onPost(): ResourceObject +{ +} ``` -## Vnd Error +## FormVndErrorModule -`Ray\WebFormModule\FormVndErrorModule`をインストールすると、`#[FormValidation]`でアノテートしたメソッドも`#[InputValidation]`とアノテートしたメソッドと同じように例外を投げるようになります。作成したPageリソースをAPIとして使用することができます: +`Ray\WebFormModule\FormVndErrorModule`をインストールすると、`#[FormValidation]`を付けたメソッドも`#[InputValidation]`と同様に例外を投げるようになります。Pageリソースをそのまま API として利用できます: ```php -use BEAR\Package\AbstractAppModule; +use Ray\Di\AbstractModule; +use Ray\WebFormModule\AuraInputModule; use Ray\WebFormModule\FormVndErrorModule; class FooModule extends AbstractModule { protected function configure() { - $this->install(new WebFormModule); - $this->override(new FormVndErrorModule); + $this->install(new AuraInputModule()); + $this->override(new FormVndErrorModule()); } } ``` +## 0.x からの移行 + +1.0 では Doctrine Annotations から PHP 8 Attributes に移行し、型宣言が強化されました。主な書き換えは次のとおりです: + +| Before (0.x) | After (1.0) | +| --- | --- | +| `@FormValidation(form="f", onFailure="badRequest")` | `#[FormValidation(form: 'f', onFailure: 'badRequest')]` | +| `@FormValidation(form="f", antiCsrf=true)` | `#[FormValidation(form: 'f')]` + `#[CsrfProtection]` | +| `@InputValidation(form="f")` | `#[InputValidation(form: 'f')]` | +| `@VndError(message="...", logref="...")` | `#[VndError(message: '...', logref: '...')]` | +| `new AuraInputInterceptor($injector, $reader)` | `new AuraInputInterceptor($injector)`(`Reader`引数なし) | +| `public function input($input)` / `error($input)` | `public function input(string $input): string` / `error(string $input): string` | + +詳しい破壊的変更の一覧は[CHANGELOG](https://github.com/ray-di/Ray.WebFormModule/blob/1.x/CHANGELOG.md)を参照してください。Claude Code 用の自動移行スキル `migrate-to-1.0` も同リポジトリに同梱されています。 + ## デモ -[MyVendor.ContactForm](https://github.com/bearsunday/MyVendor.ContactForm)アプリケーションでフォームのデモを実行して試すことができます。確認付きのフォームページや、複数のフォームを1ページに設置したときの例などが用意されています。 +[MyVendor.ContactForm](https://github.com/bearsunday/MyVendor.ContactForm)で、確認画面付きフォームや複数フォームを1ページに設置した例などを試すことができます。 From 91fbcad57f685ae4a4fb776a2b9933bbb417fcbd Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 18 May 2026 17:02:02 +0900 Subject: [PATCH 3/5] Trim 0.x migration section in form manual to a brief pointer The detailed migration table belongs in the library's README and CHANGELOG, not in the framework manual. Replace the table with a short note that links to both, keeping the manual focused on how to use Ray.WebFormModule 1.0.0. --- manuals/1.0/en/form.md | 13 +------------ manuals/1.0/ja/form.md | 13 +------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/manuals/1.0/en/form.md b/manuals/1.0/en/form.md index 84009511..4546e135 100644 --- a/manuals/1.0/en/form.md +++ b/manuals/1.0/en/form.md @@ -216,18 +216,7 @@ class FooModule extends AbstractModule ## Migration from 0.x -Version 1.0 drops Doctrine Annotations in favour of native PHP 8 Attributes and tightens type declarations. The most common rewrites: - -| Before (0.x) | After (1.0) | -| --- | --- | -| `@FormValidation(form="f", onFailure="badRequest")` | `#[FormValidation(form: 'f', onFailure: 'badRequest')]` | -| `@FormValidation(form="f", antiCsrf=true)` | `#[FormValidation(form: 'f')]` + `#[CsrfProtection]` | -| `@InputValidation(form="f")` | `#[InputValidation(form: 'f')]` | -| `@VndError(message="...", logref="...")` | `#[VndError(message: '...', logref: '...')]` | -| `new AuraInputInterceptor($injector, $reader)` | `new AuraInputInterceptor($injector)` (no `Reader` argument) | -| `public function input($input)` / `error($input)` | `public function input(string $input): string` / `error(string $input): string` | - -See the [CHANGELOG](https://github.com/ray-di/Ray.WebFormModule/blob/1.x/CHANGELOG.md) for the full list of breaking changes. A Claude Code skill `migrate-to-1.0` is shipped in the same repository to automate these rewrites. +Version 1.0 drops Doctrine Annotations in favour of native PHP 8 Attributes and turns CSRF protection into opt-in via `#[CsrfProtection]`, among other breaking changes. See the [Ray.WebFormModule README](https://github.com/ray-di/Ray.WebFormModule#migration-from-0x) and the [CHANGELOG](https://github.com/ray-di/Ray.WebFormModule/blob/1.x/CHANGELOG.md) for the upgrade steps. ## Demo diff --git a/manuals/1.0/ja/form.md b/manuals/1.0/ja/form.md index a2b11b5b..022971ad 100644 --- a/manuals/1.0/ja/form.md +++ b/manuals/1.0/ja/form.md @@ -217,18 +217,7 @@ class FooModule extends AbstractModule ## 0.x からの移行 -1.0 では Doctrine Annotations から PHP 8 Attributes に移行し、型宣言が強化されました。主な書き換えは次のとおりです: - -| Before (0.x) | After (1.0) | -| --- | --- | -| `@FormValidation(form="f", onFailure="badRequest")` | `#[FormValidation(form: 'f', onFailure: 'badRequest')]` | -| `@FormValidation(form="f", antiCsrf=true)` | `#[FormValidation(form: 'f')]` + `#[CsrfProtection]` | -| `@InputValidation(form="f")` | `#[InputValidation(form: 'f')]` | -| `@VndError(message="...", logref="...")` | `#[VndError(message: '...', logref: '...')]` | -| `new AuraInputInterceptor($injector, $reader)` | `new AuraInputInterceptor($injector)`(`Reader`引数なし) | -| `public function input($input)` / `error($input)` | `public function input(string $input): string` / `error(string $input): string` | - -詳しい破壊的変更の一覧は[CHANGELOG](https://github.com/ray-di/Ray.WebFormModule/blob/1.x/CHANGELOG.md)を参照してください。Claude Code 用の自動移行スキル `migrate-to-1.0` も同リポジトリに同梱されています。 +1.0 では Doctrine Annotations から PHP 8 Attributes へ移行し、CSRF 保護が `#[CsrfProtection]` による opt-in に変わるなどの破壊的変更があります。移行手順は[Ray.WebFormModule README](https://github.com/ray-di/Ray.WebFormModule#migration-from-0x)と[CHANGELOG](https://github.com/ray-di/Ray.WebFormModule/blob/1.x/CHANGELOG.md)を参照してください。 ## デモ From fcd550d94f1102167d88fc16136bba4837a707cf Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 18 May 2026 17:15:46 +0900 Subject: [PATCH 4/5] Use Page Resource style in form manual examples Self-review found that the controller examples returned ResourceObject without extending it (and without importing it), so they would not run as-is. Rewrite the controller examples as Page resources, which is the native style for a BEAR.Sunday manual: - class MyPage extends ResourceObject with the matching import - constructor promotion to inject the named form - method signatures return static and end with return $this - drop init(): void so the form class matches the parent Aura\Input\Fieldset::init() signature used in the library and tests --- manuals/1.0/en/form.md | 33 ++++++++++++++++++--------------- manuals/1.0/ja/form.md | 33 ++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/manuals/1.0/en/form.md b/manuals/1.0/en/form.md index 4546e135..f57446a2 100644 --- a/manuals/1.0/en/form.md +++ b/manuals/1.0/en/form.md @@ -45,7 +45,7 @@ class MyForm extends AbstractForm { use SetAntiCsrfTrait; - public function init(): void + public function init() { // register input fields $this->setField('name', 'text') @@ -70,30 +70,29 @@ The associative array of method arguments is validated. To change the input, imp A method annotated with `#[FormValidation]` is validated before execution against the form object referenced by the `form` property. When validation fails, the method whose name is suffixed with `ValidationFailed` is invoked instead: ```php -use Ray\Di\Di\Inject; +use BEAR\Resource\ResourceObject; use Ray\Di\Di\Named; use Ray\WebFormModule\Annotation\FormValidation; use Ray\WebFormModule\FormInterface; -class MyController +class MyPage extends ResourceObject { - protected FormInterface $contactForm; - - #[Inject] - public function setForm(#[Named('contact_form')] FormInterface $form): void - { - $this->contactForm = $form; + public function __construct( + #[Named('contact_form')] private FormInterface $contactForm, + ) { } #[FormValidation(form: 'contactForm')] - public function onPost(string $name, int $age): ResourceObject + public function onPost(string $name, int $age): static { // validation success + return $this; } - public function onPostValidationFailed(string $name, int $age): ResourceObject + public function onPostValidationFailed(string $name, int $age): static { // validation failure + return $this; } } ``` @@ -102,8 +101,9 @@ Use the `form` property of `#[FormValidation]` to point to a different form prop ```php #[FormValidation(form: 'contactForm', onFailure: 'badRequestAction')] -public function onPost(string $name, int $age): ResourceObject +public function onPost(string $name, int $age): static { + return $this; } ``` @@ -136,6 +136,7 @@ echo $form; // render the entire form HTML CSRF protection is **opt-in**. A form that uses `SetAntiCsrfTrait` is wired with an `AntiCsrfInterface`, but the token is only verified on methods annotated with `#[CsrfProtection]`. Methods without `#[CsrfProtection]` perform no CSRF check even if the form has an `AntiCsrf` object set. ```php +use BEAR\Resource\ResourceObject; use Ray\WebFormModule\AbstractForm; use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; @@ -146,13 +147,14 @@ class MyForm extends AbstractForm use SetAntiCsrfTrait; } -class MyController +class MyPage extends ResourceObject { #[FormValidation(form: 'contactForm')] #[CsrfProtection] - public function onPost(string $name, int $age): ResourceObject + public function onPost(string $name, int $age): static { // executed only when the CSRF token is valid + return $this; } } ``` @@ -190,8 +192,9 @@ Use the `#[VndError]` attribute to enrich the `vnd.error+json` payload: path: '/path/to/error', href: ['_self' => '/path/to/error', 'help' => '/path/to/help'] )] -public function onPost(): ResourceObject +public function onPost(): static { + return $this; } ``` diff --git a/manuals/1.0/ja/form.md b/manuals/1.0/ja/form.md index 022971ad..63e58fd8 100644 --- a/manuals/1.0/ja/form.md +++ b/manuals/1.0/ja/form.md @@ -45,7 +45,7 @@ class MyForm extends AbstractForm { use SetAntiCsrfTrait; - public function init(): void + public function init() { // フォームフィールドの登録 $this->setField('name', 'text') @@ -70,30 +70,29 @@ class MyForm extends AbstractForm `#[FormValidation]`アトリビュートを付けたメソッドは、実行前に`form`プロパティのフォームオブジェクトでバリデーションされます。バリデーションが失敗すると、メソッド名に`ValidationFailed`サフィックスを付けたメソッドが呼び出されます: ```php -use Ray\Di\Di\Inject; +use BEAR\Resource\ResourceObject; use Ray\Di\Di\Named; use Ray\WebFormModule\Annotation\FormValidation; use Ray\WebFormModule\FormInterface; -class MyController +class MyPage extends ResourceObject { - protected FormInterface $contactForm; - - #[Inject] - public function setForm(#[Named('contact_form')] FormInterface $form): void - { - $this->contactForm = $form; + public function __construct( + #[Named('contact_form')] private FormInterface $contactForm, + ) { } #[FormValidation(form: 'contactForm')] - public function onPost(string $name, int $age): ResourceObject + public function onPost(string $name, int $age): static { // バリデーション成功時の処理 + return $this; } - public function onPostValidationFailed(string $name, int $age): ResourceObject + public function onPostValidationFailed(string $name, int $age): static { // バリデーション失敗時の処理 + return $this; } } ``` @@ -102,8 +101,9 @@ class MyController ```php #[FormValidation(form: 'contactForm', onFailure: 'badRequestAction')] -public function onPost(string $name, int $age): ResourceObject +public function onPost(string $name, int $age): static { + return $this; } ``` @@ -136,6 +136,7 @@ echo $form; // フォーム全体のHTMLを描画 CSRF(クロスサイトリクエストフォージェリ)保護はopt-inです。フォームに`SetAntiCsrfTrait`を使うと`AntiCsrfInterface`が組み込まれますが、トークンの検証は`#[CsrfProtection]`アトリビュートを付けたメソッドでのみ実行されます。アトリビュートが無いメソッドでは、フォームが`AntiCsrf`オブジェクトを持っていてもCSRF検証は行われません。 ```php +use BEAR\Resource\ResourceObject; use Ray\WebFormModule\AbstractForm; use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; @@ -146,13 +147,14 @@ class MyForm extends AbstractForm use SetAntiCsrfTrait; } -class MyController +class MyPage extends ResourceObject { #[FormValidation(form: 'contactForm')] #[CsrfProtection] - public function onPost(string $name, int $age): ResourceObject + public function onPost(string $name, int $age): static { // CSRFトークンが正しい場合のみ実行される + return $this; } } ``` @@ -191,8 +193,9 @@ echo $e->error; path: '/path/to/error', href: ['_self' => '/path/to/error', 'help' => '/path/to/help'] )] -public function onPost(): ResourceObject +public function onPost(): static { + return $this; } ``` From ba3ccd3b18b5d373baad38e7d16294cd8382d45a Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 18 May 2026 20:24:59 +0900 Subject: [PATCH 5/5] Use WebFormModule in form manual examples Ray.WebFormModule 1.0.1 ships Ray\WebFormModule\WebFormModule whose name lines up with the package and namespace. Update the form manual samples to install the new class. The legacy AuraInputModule remains as a thin subclass for backwards compatibility, so no behaviour changes for existing apps. --- manuals/1.0/en/form.md | 10 +++++----- manuals/1.0/ja/form.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manuals/1.0/en/form.md b/manuals/1.0/en/form.md index f57446a2..fd76fb4c 100644 --- a/manuals/1.0/en/form.md +++ b/manuals/1.0/en/form.md @@ -17,18 +17,18 @@ Install `ray/web-form-module` with composer: composer require ray/web-form-module ``` -Install `AuraInputModule` in your application module at `src/Module/AppModule.php`: +Install `WebFormModule` in your application module at `src/Module/AppModule.php`: ```php use BEAR\Package\AbstractAppModule; -use Ray\WebFormModule\AuraInputModule; +use Ray\WebFormModule\WebFormModule; class AppModule extends AbstractAppModule { protected function configure() { // ... - $this->install(new AuraInputModule()); + $this->install(new WebFormModule()); } } ``` @@ -204,14 +204,14 @@ Install `Ray\WebFormModule\FormVndErrorModule` to make `#[FormValidation]` metho ```php use Ray\Di\AbstractModule; -use Ray\WebFormModule\AuraInputModule; +use Ray\WebFormModule\WebFormModule; use Ray\WebFormModule\FormVndErrorModule; class FooModule extends AbstractModule { protected function configure() { - $this->install(new AuraInputModule()); + $this->install(new WebFormModule()); $this->override(new FormVndErrorModule()); } } diff --git a/manuals/1.0/ja/form.md b/manuals/1.0/ja/form.md index 63e58fd8..f09c9d55 100644 --- a/manuals/1.0/ja/form.md +++ b/manuals/1.0/ja/form.md @@ -17,18 +17,18 @@ composerで`ray/web-form-module`をインストールします: composer require ray/web-form-module ``` -アプリケーションモジュール`src/Module/AppModule.php`で`AuraInputModule`をインストールします: +アプリケーションモジュール`src/Module/AppModule.php`で`WebFormModule`をインストールします: ```php use BEAR\Package\AbstractAppModule; -use Ray\WebFormModule\AuraInputModule; +use Ray\WebFormModule\WebFormModule; class AppModule extends AbstractAppModule { protected function configure() { // ... - $this->install(new AuraInputModule()); + $this->install(new WebFormModule()); } } ``` @@ -205,14 +205,14 @@ public function onPost(): static ```php use Ray\Di\AbstractModule; -use Ray\WebFormModule\AuraInputModule; +use Ray\WebFormModule\WebFormModule; use Ray\WebFormModule\FormVndErrorModule; class FooModule extends AbstractModule { protected function configure() { - $this->install(new AuraInputModule()); + $this->install(new WebFormModule()); $this->override(new FormVndErrorModule()); } }