PHPackages                             ray/web-form-module - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. ray/web-form-module

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

ray/web-form-module
===================

Web Form module for Ray.Di

1.0.1(1mo ago)322.6k↓22.2%4[3 PRs](https://github.com/ray-di/Ray.WebFormModule/pulls)MITPHPPHP &gt;=8.0.0CI passing

Since Mar 24Pushed 5d ago1 watchersCompare

[ Source](https://github.com/ray-di/Ray.WebFormModule)[ Packagist](https://packagist.org/packages/ray/web-form-module)[ RSS](/packages/ray-web-form-module/feed)WikiDiscussions 1.x Synced 3w ago

READMEChangelog (10)Dependencies (20)Versions (31)Used By (0)

Ray.WebFormModule
=================

[](#raywebformmodule)

[![Continuous Integration](https://github.com/ray-di/Ray.WebFormModule/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/ray-di/Ray.WebFormModule/actions/workflows/continuous-integration.yml)[![Coding Standards](https://github.com/ray-di/Ray.WebFormModule/actions/workflows/coding-standards.yml/badge.svg)](https://github.com/ray-di/Ray.WebFormModule/actions/workflows/coding-standards.yml)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/3c6cc0024c0e09135a02661d0287ce7d87f2eb015bf2ba7ebbb7236ab611284c/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f7261792d64692f5261792e576562466f726d4d6f64756c652f6261646765732f7175616c6974792d73636f72652e706e673f623d312e78)](https://scrutinizer-ci.com/g/ray-di/Ray.WebFormModule/?branch=1.x)

An aspect oriented web form module powered by [Aura.Input](https://github.com/auraphp/Aura.Input) and [Ray.Di](https://github.com/ray-di/Ray.Di).

Getting Started
===============

[](#getting-started)

Installation
------------

[](#installation)

### Composer install

[](#composer-install)

```
$ composer require ray/web-form-module

```

### Module install

[](#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\AuraInputModule` class is still available as a thin subclass of `WebFormModule` for backwards compatibility. New code should prefer `WebFormModule`.

Usage
-----

[](#usage)

### Form class

[](#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](https://github.com/auraphp/Aura.Input/blob/1.x/README.md#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

[](#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

[](#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'); //
  echo $form->error('name'); // "Name must be alphabetic only." or blank.
```

### CSRF Protections

[](#csrf-protections)

CSRF protection is **opt-in** and can be enabled through either of two independent paths:

- **Per-form**: add `use SetAntiCsrfTrait;` to the form. `AntiCsrfInterface`is injected by Ray.Di through the trait's `#[Inject]` setter, the token field is added in `postConstruct()`, and every `apply()` call verifies the token.
- **Per-action**: annotate the validated controller method with `#[CsrfProtection]`. `AuraInputInterceptor` then injects `AntiCsrfInterface` into the form before `apply()` runs.

Either path causes `AbstractForm::apply()` to throw `CsrfViolationException`on token mismatch. Without either path, no CSRF check is performed. Combining both paths is harmless but redundant — pick whichever fits your use case.

Per-action — declare CSRF on the controller method:

```
use Ray\WebFormModule\Annotation\CsrfProtection;
use Ray\WebFormModule\Annotation\FormValidation;

class MyController
{
    #[FormValidation(form: "contactForm")]
    #[CsrfProtection]
    public function createAction()
    {
    }
}
```

Per-form — declare CSRF on the form itself:

```
use Ray\WebFormModule\AbstractForm;
use Ray\WebFormModule\SetAntiCsrfTrait;

class MyForm extends AbstractForm
{
    use SetAntiCsrfTrait;
}
```

You can provide your custom `AntiCsrf` class. See more detail at [Aura.Input](https://github.com/auraphp/Aura.Input#applying-csrf-protections)

Migration from 0.x
------------------

[](#migration-from-0x)

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](CHANGELOG.md) for the full list of breaking changes.

### Automated migration with Claude Code

[](#automated-migration-with-claude-code)

The repository ships a Claude Code skill at [`.claude/skills/migrate-to-1.0/SKILL.md`](.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
--------------------

[](#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](https://tools.ietf.org/html/rfc6906) 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
----

[](#demo)

```
$ php -S docs/demo/1.csrf/web.php

```

###  Health Score

59

—

FairBetter than 98% of packages

Maintenance96

Actively maintained with recent releases

Popularity31

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity79

Established project with proven stability

 Bus Factor1

Top contributor holds 86.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~214 days

Recently: every ~821 days

Total

20

Last Release

35d ago

Major Versions

0.5.4 → 2.x-dev2017-05-22

0.6.0 → 1.0.02026-05-17

PHP version history (2 changes)0.6.0PHP &gt;=7.0.0

1.0.0PHP &gt;=8.0.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/db4fc75ffc631168d0d7143b6f2c24b1534dfb921212bd851c026c5cbbb1344d?d=identicon)[koriym](/maintainers/koriym)

---

Top Contributors

[![koriym](https://avatars.githubusercontent.com/u/529021?v=4)](https://github.com/koriym "koriym (133 commits)")[![apple-x-co](https://avatars.githubusercontent.com/u/8497012?v=4)](https://github.com/apple-x-co "apple-x-co (13 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (7 commits)")[![kumamidori](https://avatars.githubusercontent.com/u/384567?v=4)](https://github.com/kumamidori "kumamidori (1 commits)")

---

Tags

ray-moduleweb-formRay.Di moduleweb form

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ray-web-form-module/health.svg)

```
[![Health](https://phpackages.com/badges/ray-web-form-module/health.svg)](https://phpackages.com/packages/ray-web-form-module)
```

###  Alternatives

[bear/package

BEAR.Sunday application framework package

30553.3k25](/packages/bear-package)[bear/resource

Hypermedia framework for object as a service

46672.7k38](/packages/bear-resource)[ray/media-query

PHP interface-based SQL framework

11242.8k2](/packages/ray-media-query)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
