ray / web-form-module
Web Form module for Ray.Di
Requires
- php: >=8.0.0
- aura/filter: ^2.3|3.x-dev
- aura/html: ^2.5
- aura/input: ^1.2
- aura/session: ^2.1 || ^4.0
- ray/aop: ^2.14
- ray/aura-session-module: ^1.1
- ray/di: ^2.16
Requires (Dev)
- doctrine/coding-standard: ^14.0
- maglnet/composer-require-checker: ^4.0
- phpmd/phpmd: ^2.13
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^4.0
- vimeo/psalm: ^5.0 || ^6.0
- 2.x-dev
- 1.x-dev
- 1.0.1
- 1.0.0
- 0.6.0
- 0.5.5
- 0.5.4
- 0.5.3
- 0.5.2
- 0.5.1
- 0.5.0
- 0.4.0
- 0.3.3
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.1
- 0.2.0
- 0.1.1
- 0.1.0
- dev-claude/review-csrf-protection-yjrZA
- dev-rename-to-webform-module
- dev-dependabot/composer/phpstan/phpstan-tw-2.1
- dev-dependabot/github_actions/actions/cache-5
- dev-dependabot/github_actions/actions/checkout-6
- dev-release-prep-1.0.0
- dev-claude/review-item-24-9tucR
- dev-migrate-attribute
- dev-fix/composer-test
- dev-refactor
This package is auto-updated.
Last update: 2026-05-19 14:37:26 UTC
README
An aspect oriented web form module powered by Aura.Input and Ray.Di.
Getting Started
Installation
Composer install
$ composer require ray/web-form-module
Module install
use Ray\Di\AbstractModule; use Ray\WebFormModule\WebFormModule; class AppModule extends AbstractModule { protected function configure() { $this->install(new WebFormModule()); } }
The legacy
Ray\WebFormModule\AuraInputModuleclass is still available as a thin subclass ofWebFormModulefor backwards compatibility. New code should preferWebFormModule.
Usage
Form class
We provide two methods on self-initializing form class, one is init() method where we add an input field on form and apply fileters and rules. The other method method is submit() where it submit data. See more detail at Aura.Input self-initializing forms.
use Ray\WebFormModule\AbstractForm; use Ray\WebFormModule\SetAntiCsrfTrait; class MyForm extends AbstractForm { // for anti CSRF use SetAntiCsrfTrait; /** * {@inheritdoc} */ public function init() { $this->setField('name', 'text') ->setAttribs([ 'id' => 'name' ]); $this->filter->validate('name')->is('alnum'); $this->filter->useFieldMessage('name', 'Name must be alphabetic only.'); } /** * {@inheritdoc} */ public function submit() { return $_POST; } /** * {@inheritdoc} */ public function __toString() { $form = $this->form(); // name $form .= $this->helper->tag('div', ['class' => 'form-group']); $form .= $this->helper->tag('label', ['for' => 'name']); $form .= 'Name:'; $form .= $this->helper->tag('/label') . PHP_EOL; $form .= $this->input('name'); $form .= $this->error('name'); $form .= $this->helper->tag('/div') . PHP_EOL; // submit $form .= $this->input('submit'); $form .= $this->helper->tag('/form'); return $form; } }
Controller
We annotate the methods which web form validation is required with #[FormValidation]. We can specify form object property name with form and failure method name with 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 // More detail for `vnd.error+json` can be added with `#[VndError]`. } public function badRequestAction() { // validation faild } }
View
You can render entire form html when __toString is given.
echo $form; // render entire form html
or render input element basis.
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 Protections
CSRF protection is opt-in. A form that uses SetAntiCsrfTrait is wired
with an AntiCsrfInterface, but the token is only verified when the
validated method is annotated with #[CsrfProtection]. Methods without
#[CsrfProtection] perform no CSRF check even if the form supports it.
use Ray\WebFormModule\AbstractAuraForm; use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; use Ray\WebFormModule\SetAntiCsrfTrait; class MyForm extends AbstractAuraForm { use SetAntiCsrfTrait; } class MyController { #[FormValidation(form: "contactForm")] #[CsrfProtection] public function createAction() { } }
You can provide your custom AntiCsrf class. See more detail at Aura.Input
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) / public function error($input) |
public function input(string $input): string / error(string $input): string |
See CHANGELOG.md for the full list of breaking changes.
Automated migration with Claude Code
The repository ships a Claude Code skill at
.claude/skills/migrate-to-1.0/SKILL.md
that walks an AI assistant through the rewrites above (annotations →
attributes, antiCsrf=true split into #[CsrfProtection], Reader
argument removal, FormInterface signature updates). Copy the directory
into your consuming project's .claude/skills/ and invoke it via
/migrate-to-1.0.
Validation Exception
When we install Ray\WebFormModule\FormVndErrorModule as following,
use Ray\Di\AbstractModule; class FakeVndErrorModule extends AbstractModule { protected function configure() { $this->install(new WebFormModule()); $this->override(new FormVndErrorModule()); }
A Ray\WebFormModule\Exception\ValidationException will be thrown.
We can echo catched exception to get application/vnd.error+json media type.
echo $e->error; //{ // "message": "Validation failed", // "path": "/path/to/error", // "validation_messages": { // "name": [ // "Name must be alphabetic only." // ] // } //}
More detail for vnd.error+json can be added with the #[VndError] attribute.
#[FormValidation(form: "contactForm")] #[VndError(message: "foo validation failed", logref: "a1000", path: "/path/to/error", href: ["_self" => "/path/to/error", "help" => "/path/to/help"])]
This optional module is handy for API application.
Demo
$ php -S docs/demo/1.csrf/web.php