PHPackages                             jrm/request-bundle - 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. [API Development](/categories/api)
4. /
5. jrm/request-bundle

ActiveSymfony-bundle[API Development](/categories/api)

jrm/request-bundle
==================

Makes it easy to get your own request as a controller argument

0.3.3(1y ago)23.1kMITPHPPHP ^8.2 || ^8.3CI passing

Since Apr 26Pushed 1y ago1 watchersCompare

[ Source](https://github.com/VladGapanovich/request-bundle)[ Packagist](https://packagist.org/packages/jrm/request-bundle)[ RSS](/packages/jrm-request-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (19)Versions (8)Used By (0)

[JustReserve](https://justreserve.me) RequestBundle
===================================================

[](#justreserve-requestbundle)

This is an implementation of hydrating data from symfony requests in narrow request for specific controller/action.

Installation
============

[](#installation)

1. Require this bundle in your application:

```
composer require jrm/request-bundle
```

2. Enable the bundle in your application:

```
return [
    # ...
    Jrm\RequestBundle\JrmRequestBundle::class => ['all' => true],
    # ...
];
```

Usage
=====

[](#usage)

Create request using some sources of data:

- `Body` (take data from request body or form)
- `Collection` (Needed for hydrate of collection some sub objects)
- `Cookie` (take data from cookies)
- `EmbeddableRequest` (Needed for hydrate of some sub object)
- `File` (take data from files)
- `Header` (take data from headers)
- `PathAttribute` (take data from path attributes)
- `Query` (take data from query string)

### Request

[](#request)

```
use Jrm\RequestBundle\Model\Source;
use Jrm\RequestBundle\Attribute\Collection;
use Jrm\RequestBundle\Attribute\Header;
use Jrm\RequestBundle\Attribute\PathAttribute;

final class MyRequest
{
    public function __construct(
        #[PathAttribute()]
        public readonly int $id,
        #[Body('pos_id')]
        private readonly string $posId,
        #[Header('Content-Type')]
        public readonly string $contentType,
        #[Assert\Valid]
        #[Collection(
            type: ProductItem::class,
            source: Source::BODY,
            path: 'products',
        )]
        public readonly array $products,
    ) {
    }
}
```

### Controller

[](#controller)

This example with invokable controller, but you can use it with regular controller.

```
use Jrm\RequestBundle\MapRequest;

#[Route(
    '/do-something/{id}',
    name: 'app.do.something',
    methods: [Request::METHOD_POST],
)]
final class MyAction
{
    public function __invoke(#[MapRequest] MyRequest $request): JsonResponse
    {
        //do something

        return new JsonResponse(null);
    }
}
```

Nested fields
-------------

[](#nested-fields)

Your data, for example request body, may have some nesting.

```
{
  "request": {
    "some_field": "some_value",
    "next_field": "next_value"
  }
}
```

You can pass path to this filed.

```
use Jrm\RequestBundle\Attribute\Body;

final class MyRequest
{
    public function __construct(
        #[Body('request.some_field')]
        public readonly string $someField,
        #[Body('request.next_field')]
        public readonly string $nextField,
    ) {
    }
}
```

Validation
----------

[](#validation)

You can validate your request by symfony constraints, if validation will be failed, Jrm\\RequestBundle\\Listener\\RequestValidationFailedExceptionListener will send response with all failed fields and error messages for them

```
use Jrm\RequestBundle\Attribute\Query;
use Symfony\Component\Validator\Constraints as Assert;

final class MyRequest
{
    public function __construct(
        #[Assert\NotBlank]
        #[Query('some_field')]
        public readonly string $field,
    ) {
    }
}
```

```
{
  "message": "Validation failed.",
  "errors": [
    {
      "code": "48b70abd-a021-4ce7-9662-616cd58eeaee",
      "message": "This value should not be blank.",
      "parameters": [],
      "property_path": "some_field"
    }
  ]
}
```

Collection
----------

[](#collection)

In some cases you may need to hydrate collection of data, you can use Collection attribute and "describe" this collection items as a separate object.

```
use Jrm\RequestBundle\Attribute\Internal\Item;
use Symfony\Component\Validator\Constraints as Assert;

final class MyCollectionItem
{
    public function __construct(
        #[Assert\Uuid]
        #[Item()]
        public readonly string $id,
    ) {
    }
}
```

```
use Jrm\RequestBundle\Model\Source;
use Jrm\RequestBundle\Attribute\Collection;
use Symfony\Component\Validator\Constraints as Assert;

final class MyRequest
{
    public function __construct(
        #[Assert\Valid]
        #[Collection(
            type: MyCollectionItem::class,
            source: Source::BODY,
            path: 'sub_ids',
        )]
        public readonly array $items,
    ) {
    }
}
```

> ***NOTE:*** You should use #\[Assert\\Valid\] for your collection as in the example above for validating your collection, because without this constraint, symfony validator ignore it

Custom Resolver
---------------

[](#custom-resolver)

You can create your custom resolver to define new way to get of data for request
For this you need to create:

### Parameter

[](#parameter)

```
use Jrm\RequestBundle\Attribute\RequestAttribute;

#[Attribute(Attribute::TARGET_PARAMETER, Attribute::TARGET_PROPERTY)]
final class UserId implements RequestAttribute
{
    /**
     * @return class-string
     */
    public function resolvedBy(): string
    {
        return UserIdResolver::class;
    }
}
```

### ParameterResolver

[](#parameterresolver)

```
use App\Domain\User\Exception\UserNotAuthorizedException;
use App\Domain\User\Model\User;
use Jrm\RequestBundle\Exception\UnexpectedAttributeException;
use Jrm\RequestBundle\Model\Metadata;
use Jrm\RequestBundle\Attribute\RequestAttribute;
use Jrm\RequestBundle\Attribute\ValueResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

final class UserIdResolver implements ValueResolver
{
    public function __construct(
        private readonly TokenStorageInterface $tokenStorage,
    ) {
    }

    public function resolve(
        Request $request,
        Metadata $metadata,
        RequestAttribute $attribute,
    ): int {
        if (!$attribute instanceof UserId) {
            throw new UnexpectedAttributeException(UserId::class, $attribute::class);
        }

        try {
            $user = $this->tokenStorage->getToken()?->getUser();

            if ($user === null) {
                throw new UserNotAuthorizedException();
            }

            return $user->id();
        } catch (Throwable $throwable) {
            if ($parameter->isOptional()) {
                return $parameter->defaultValue();
            }

            throw $throwable;
        }
    }
}
```

Plans:
------

[](#plans)

- Make automation conversion to Open Api Doc
- Make the `Item` attribute optional
- Add validation tests that all requests are valid classes with supported attributes and types
- Fix issue with validation, when your request haven't any required params
- Add bundle to symfony flex
- Add more unit and integration tests

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance43

Moderate activity, may be stable

Popularity22

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 69.2% 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 ~111 days

Recently: every ~126 days

Total

7

Last Release

449d ago

PHP version history (2 changes)0.1.0PHP ^8.0

0.3PHP ^8.2 || ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/3949ded28efbd439c63866f3b8e9c2a74c8f0e2f046bf2ba81dc3eb66fed0837?d=identicon)[vladgapa](/maintainers/vladgapa)

---

Top Contributors

[![vadim-gapanovich](https://avatars.githubusercontent.com/u/116637201?v=4)](https://github.com/vadim-gapanovich "vadim-gapanovich (9 commits)")[![vadim-gap](https://avatars.githubusercontent.com/u/128401533?v=4)](https://github.com/vadim-gap "vadim-gap (4 commits)")

---

Tags

apihttpphprequestsymfonyrequestphpapisymfony

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/jrm-request-bundle/health.svg)

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

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[api-platform/core

Build a fully-featured hypermedia or GraphQL API in minutes!

2.6k48.1M236](/packages/api-platform-core)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[nelmio/api-doc-bundle

Generates documentation for your REST API from attributes

2.3k63.6M233](/packages/nelmio-api-doc-bundle)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)

PHPackages © 2026

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