PHPackages                             solophp/request-handler - 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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. solophp/request-handler

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

solophp/request-handler
=======================

Robust request validation &amp; authorization layer for HTTP inputs with type-safe handlers and modern PHP 8+ architecture

v3.1.0(1mo ago)070MITPHPPHP ^8.2CI passing

Since Sep 24Pushed 1mo agoCompare

[ Source](https://github.com/SoloPHP/Request-Handler)[ Packagist](https://packagist.org/packages/solophp/request-handler)[ RSS](/packages/solophp-request-handler/feed)WikiDiscussions main Synced today

READMEChangelog (9)Dependencies (10)Versions (10)Used By (0)

Solo Request Handler
====================

[](#solo-request-handler)

Type-safe Request DTOs for PHP 8.2+ with focused per-property attributes, declarative validation, type casting, and full IDE support.

[![Latest Version on Packagist](https://camo.githubusercontent.com/cf6b1e4e9b692f219e71597d621804b86a65cf8eb9b9bcd6fb4039b7b021d80c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736f6c6f7068702f726571756573742d68616e646c65722e737667)](https://packagist.org/packages/solophp/request-handler)[![PHP Version](https://camo.githubusercontent.com/9051b6544f57608ca691a918b38ad8c567657e0ecb6d4e960be274f287d171d8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d3838393242462e737667)](https://php.net/)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)

Features
--------

[](#features)

- **Per-property source binding** — default source comes from the handle method (`handleBody` → Body, `handleQuery` → Query); `#[FromRoute]` and `#[FromContext]` override per property. No implicit merging, no surprises.
- **Attribute-composed DTOs** — each concern is its own focused attribute: `#[Validate]`, `#[Cast]`, `#[PostProcess]`, `#[Generator]`, `#[Items]`, …
- **Convention over configuration** — every public non-static property is managed; attributes only add behaviour
- **Automatic type casting** — driven by the property's declared type; built-ins for int, float, bool, string, array, DateTime + custom casters
- **Validation rules** — passed verbatim to your `ValidatorInterface`; route and context values land in the validation payload as regular fields, so cross-field rules (`exists:…,scope_col,{field}`) work without special syntax
- **Generators** — auto-generate UUIDs, sequences, custom values via `#[Generator]`
- **Pre/post processing** — `#[PreProcess]` / `#[PostProcess]` for transformation
- **Nested items** — `#[Items]` validates arrays of nested Request DTOs with dot-notation error paths
- **Fail-fast** — every misconfiguration throws `ConfigurationException` at metadata-build time, not at first request
- **Schema export** — `schema()` emits JSON-serializable per-field metadata (type, nullability, requiredness incl. conditional `required_if`, normalized rules) so the frontend can treat the backend as the single source of truth

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

[](#installation)

```
composer require solophp/request-handler
```

Quick Example
-------------

[](#quick-example)

```
use Solo\RequestHandler\Attributes\{Validate, Generator, Items, Exclude};
use Solo\RequestHandler\Attributes\Source\{FromRoute, FromContext};
use Solo\RequestHandler\Request;

final class UpdateProductRequest extends Request
{
    // PUT /products/{id}
    #[FromRoute]
    #[Validate('required|integer|exists:products,id')]
    public int $id;

    // default body — no source attribute needed
    #[Validate('required|string|max:255')]
    public string $name;

    #[Validate('required|numeric|min:0')]
    public float $price;

    #[Validate('nullable|integer|min:0')]
    public int $stock = 0;

    #[FromContext('tenantId')]
    #[Validate('required|integer')]
    public int $tenantId;

    #[FromContext('authUserId')]
    #[Validate('required|integer')]
    public int $updatedBy;

    #[Validate('required|string|min:8')]
    #[Exclude]              // validated/processed but hidden from toArray()
    public string $newPassword;
}

// Controller
$dto = $requestHandler->handleBody(
    UpdateProductRequest::class,
    $request,
    route:   ['id' => $productId],
    context: ['tenantId' => $tenant->id(), 'authUserId' => $auth->id()],
);

$dto->id;          // int — pulled from URL path
$dto->name;        // string — from body
$dto->tenantId;    // int — from application context
$dto->updatedBy;   // int — from application context
$dto->toArray();   // ['id'=>…, 'name'=>…, 'price'=>…, 'stock'=>…, 'tenantId'=>…, 'updatedBy'=>…] — no newPassword
```

Attribute family
----------------

[](#attribute-family)

AttributePurpose`#[Validate('rules')]`Validation rules (passed to your `ValidatorInterface`)`#[FromRoute(?string $key = null)]`Read from the `$route` argument (URL path params)`#[FromContext(string $key)]`Read from the `$context` argument (auth user, tenant, …)`#[FromBody(string $path)]`Read from a nested body path (`customer.id`); flat keys may also be remapped this way`#[Cast('int'|'float'|'datetime:Y-m-d'|...)]`Explicit built-in cast`#[Caster(MoneyCaster::class)]`Custom `CasterInterface` implementation`#[PreProcess(MyProc::class)]`Run handler BEFORE validation`#[PostProcess(MyProc::class, config: [...])]`Run handler AFTER validation, with optional config`#[Generator(UuidGenerator::class, options: [...])]`Value is generated, not read from any source`#[Items(OrderItemRequest::class)]`Property is an array of nested DTOs`#[Group('criteria', mapTo: 'positions.id')]`Group membership + remap for `Request::group()``#[Exclude]``Request::toArray()` skips this property (still validated &amp; processed)`#[Ignore]`Property is invisible to the handler AND to `toArray()`/`has()`/`get()`/`group()`Properties without a source attribute read from the default-source bag (Body for `handleBody`/`handleArray`, Query for `handleQuery`) by name. For values that don't fit the four bags (Body, Query, Route, Context) — request headers, cookies, file uploads — extract them in the controller and pass them via `route: [...]` or `context: [...]`.

To opt a public property out of input processing entirely, mark it with `#[Ignore]` — the handler skips it and `toArray()`/`has()`/`get()`/`group()` will not see it either. Or change its visibility to `protected`/`private` — the handler only touches public properties.

Schema introspection
--------------------

[](#schema-introspection)

`schema()` reflects a request class into a JSON-serializable description of its input contract — without touching any HTTP input. Hand it to the frontend so validation rules live in exactly one place.

```
$schema = $requestHandler->schema(UpdateProductRequest::class);

// [
//   'id' => [
//     'type' => 'int', 'nullable' => false, 'required' => true,
//     'requiredIf' => null, 'hasDefault' => false, 'exclude' => false,
//     'source' => 'route',
//     'rules' => [['name' => 'required', 'args' => []], ['name' => 'integer', 'args' => []]],
//   ],
//   'name' => [
//     'type' => 'string', 'nullable' => false, 'required' => true,
//     'requiredIf' => null, 'hasDefault' => false, 'exclude' => false, 'source' => null,
//     'rules' => [['name' => 'required', 'args' => []], ['name' => 'string', 'args' => []], ['name' => 'max', 'args' => ['255']]],
//   ],
//   'slug' => [
//     'type' => 'string', 'nullable' => true, 'required' => false,
//     'requiredIf' => ['field' => 'status', 'value' => 'published'],
//     'hasDefault' => true, 'exclude' => false, 'source' => null,
//     'rules' => [/* … incl. ['name' => 'required_if', 'args' => ['status', 'published']] */],
//   ],
// ]

echo json_encode($schema); // round-trips losslessly — scalars and arrays only
```

Every managed property is emitted (excluded/`#[FromRoute]`/`#[FromContext]` fields included) — `exclude` and `source` are reported as flags so the consumer decides what to render. Notes:

- `required` reflects the **literal** `required` rule only. Conditional requiredness lives in `requiredIf` (the first well-formed `required_if`, as `{field, value}`), and the rule itself is still present in `rules`.
- `source` is `'body' | 'query' | 'route' | 'context'`, or `null` when the field uses the handle method's default bag.
- `rules` is the full normalized rule list, split with the same semantics the handler uses internally: `name` is the part before the first `:`, `args` is the comma-split remainder.

Documentation
-------------

[](#documentation)

**[Full Documentation](https://solophp.github.io/Request-Handler/)**

- [Installation](https://solophp.github.io/Request-Handler/guide/installation)
- [Quick Start](https://solophp.github.io/Request-Handler/guide/quick-start)
- [Configuration](https://solophp.github.io/Request-Handler/guide/configuration)
- [Attributes](https://solophp.github.io/Request-Handler/features/field-attribute)
- [Type Casting](https://solophp.github.io/Request-Handler/features/type-casting)
- [Processors](https://solophp.github.io/Request-Handler/features/processors)
- [Generators](https://solophp.github.io/Request-Handler/features/generators)
- [Nested Items](https://solophp.github.io/Request-Handler/features/nested-items)
- [Validation](https://solophp.github.io/Request-Handler/features/validation)
- [API Reference](https://solophp.github.io/Request-Handler/api/request-class)

Requirements
------------

[](#requirements)

- PHP 8.2+
- PSR-7 HTTP Message implementation
- Validator implementing `Solo\Contracts\Validator\ValidatorInterface`

We recommend [solophp/validator](https://github.com/SoloPHP/Validator).

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance93

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~31 days

Recently: every ~37 days

Total

9

Last Release

37d ago

Major Versions

v1.2.0 → v2.0.02025-12-29

v2.2.0 → v3.0.02026-05-26

### Community

Maintainers

![](https://www.gravatar.com/avatar/2f29817cec408d033cd4441c8f760e3ae40248dc0f66856a09080d282aee6959?d=identicon)[Vitaliy Olos](/maintainers/Vitaliy%20Olos)

---

Top Contributors

[![SoloPHP](https://avatars.githubusercontent.com/u/175482616?v=4)](https://github.com/SoloPHP "SoloPHP (38 commits)")

---

Tags

requestpsrphpvalidationprocessingauthorizationformphp8strict types

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/solophp-request-handler/health.svg)

```
[![Health](https://phpackages.com/badges/solophp-request-handler/health.svg)](https://phpackages.com/packages/solophp-request-handler)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.1B4.0k](/packages/guzzlehttp-psr7)[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[cakephp/cakephp

The CakePHP framework

8.9k19.5M1.8k](/packages/cakephp-cakephp)[openai-php/client

OpenAI PHP is a supercharged PHP API client that allows you to interact with the Open AI API

5.8k28.0M318](/packages/openai-php-client)[league/oauth2-server

A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.

6.7k147.0M290](/packages/league-oauth2-server)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)

PHPackages © 2026

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