Ray.WebFormModuleはアスペクト指向でフォームのバリデーションを行うモジュールです。 フォームライブラリにはAura.Inputを使い、 特定のアプリケーションフレームワークの依存なしで利用できます。
$ composer require ray/web-form-module
use Ray\Di\AbstractModule;
use Ray\WebFormModule\WebFormModule;
class AppModule extends AbstractModule
{
protected function configure()
{
$this->install(new WebFormModule());
}
}互換性のため
Ray\WebFormModule\AuraInputModuleクラスもWebFormModuleの薄い サブクラスとして残されています。新規コードではWebFormModuleを使ってください。
init()メソッドでフォームのinput要素を登録とルールの設定を行います。
use Ray\WebFormModule\AbstractForm;
use Ray\WebFormModule\SetAntiCsrfTrait;
class MyForm extends AbstractForm
{
/**
* {@inheritdoc}
*/
public function init()
{
// set input fields
$this->setField('name', 'text')
->setAttribs([
'id' => 'name'
]);
// set input filters
$this->filter->validate('name')->is('alnum');
$this->filter->useFieldMessage('name', 'Name must be alphabetic only.');
}
}メソッドの引数を名前付き引数にしたものがフォームオブジェクトに渡されバリデーションされます。
// このメソッドの場合['id' => $id, 'name' => $name]配列が渡されます
public function createAction($id, $name, $body)
{Ray\WebFormModule\WebFormModule\SubmitInterfaceを実装するとsubmit()メソッドで返された値がフォームオブジェクトに渡されます。
/**
* {@inheritdoc}
*/
public function submit()
{
return $_POST;
}
}init()メソッドでで利用できるメソッドについて詳しく`はAura.Inputをご覧ください
コントローラークラスにフォームをインジェクトします。フォームのバリデーションを行うメソッドを#[FormValidation]で
アノテートします。この時フォームのプロパティ名をformで、バリデーションが失敗したときのメソッドをonFailureで指定します。
use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;
use Ray\WebFormModule\Annotation\FormValidation;
use Ray\WebFormModule\FormInterface;
class MyController
{
/**
* @var FormInterface
*/
protected $contactForm;
#[Inject]
public function setForm(#[Named("contact_form")] FormInterface $form)
{
$this->contactForm = $form;
}
#[FormValidation(form: "contactForm", onFailure: "badRequestAction")]
public function createAction()
{
// validation success
}
public function badRequestAction()
{
// validation faild
}
}フォームのinput要素やエラーメッセージを取得するには要素名を指定します。
echo $form->input('name'); // <input id="name" type="text" name="name" size="20" maxlength="20" />
echo $form->error('name'); // "Name must be alphabetic only." or blank.CSRF対策は opt-in で、独立した 2 つの経路のいずれかで有効化できます。
- フォーム単位: フォームに
use SetAntiCsrfTrait;を追加します。 Ray.Di がトレイトの#[Inject]setter 経由でAntiCsrfInterfaceを注入し、postConstruct()でトークンフィールドが追加され、apply()の呼び出しごとに トークンが検証されます。 - アクション単位: バリデーション対象のコントローラメソッドに
#[CsrfProtection]を付与します。AuraInputInterceptorがapply()実行前にAntiCsrfInterfaceをフォームへ注入します。
どちらの経路でも、トークン不一致時には AbstractForm::apply() が
CsrfViolationException を throw します。どちらも使わない場合は CSRF 検証は
行われません。両方を併用しても害はありませんが冗長なので、用途に合わせて
どちらか一方を選んでください。
アクション単位 — コントローラのメソッドで宣言:
use Ray\WebFormModule\Annotation\CsrfProtection;
use Ray\WebFormModule\Annotation\FormValidation;
class MyController
{
#[FormValidation(form: "contactForm")]
#[CsrfProtection]
public function createAction()
{
}
}フォーム単位 — フォーム自身で宣言:
use Ray\WebFormModule\AbstractForm;
use Ray\WebFormModule\SetAntiCsrfTrait;
class MyForm extends AbstractForm
{
use SetAntiCsrfTrait;
}セキュリティレベルを高めるためにはユーザーの認証を含んだカスタムCsrfクラスを作成してフォームクラスにセットします。 詳しくはAura.InputのApplying CSRF Protectionsをご覧ください。
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) / public function error($input) |
public function input(string $input): string / error(string $input): string |
破壊的変更の完全なリストは CHANGELOG.md を参照してください。
リポジトリ同梱の Claude Code skill
.claude/skills/migrate-to-1.0/SKILL.md
が上記の書き換え (アノテーション → アトリビュート、antiCsrf=true の
#[CsrfProtection] 分割、Reader 引数削除、FormInterface 署名更新) を
AI アシスタントに案内します。利用側プロジェクトの .claude/skills/ に
ディレクトリをコピーして /migrate-to-1.0 で起動してください。
#[FormValidation]の代わりに#[InputValidation]とアノテートするとバリデーションが失敗したときにRay\WebFormModule\Exception\ValidationExceptionが投げられるよになります。この場合はHTML表現は使われません。Web APIアプリケーションなどに便利です。
use Ray\WebFormModule\Annotation\InputValidation;
class Foo
{
#[InputValidation(form: "form1")]
public function createAction($name)
{
// ...
}以下のように Ray\WebFormModule\FormVndErrorModuleをインストールするとフォームのバリデーションが失敗したときにRay\WebFormModule\Exception\ValidationException例外が投げられるよになります。
use Ray\Di\AbstractModule;
class FakeVndErrorModule extends AbstractModule
{
protected function configure()
{
$this->install(new WebFormModule());
$this->override(new FormVndErrorModule());
}キャッチした例外のerrorプロパティをechoするとapplication/vnd.error+jsonメディアタイプの表現が出力されます。
http_response_code(400);
echo $e->error;
//{
// "message": "Validation failed",
// "path": "/path/to/error",
// "validation_messages": {
// "name": [
// "Name must be alphabetic only."
// ]
// }
//}#[VndError]属性でvnd.error+jsonに必要な情報を加えることができます。
#[FormValidation(form: "contactForm")]
#[VndError(message: "foo validation failed", logref: "a1000", path: "/path/to/error", href: ["_self" => "/path/to/error", "help" => "/path/to/help"])]このオプションのモジュールはAPIアプリケーションの時に有用です。
$ php -S docs/demo/1.csrf/web.php
