nelexa/request-dto-bundle

This Symfony Bundle provides request objects support for Symfony controller actions

Maintainers

👁 Ne-Lexa

Package info

github.com/Ne-Lexa/RequestDtoBundle

Type:symfony-bundle

pkg:composer/nelexa/request-dto-bundle

Statistics

Installs: 23 468

Dependents: 0

Suggesters: 0

Stars: 9

Open Issues: 0

1.3.4 2022-06-21 07:01 UTC

Requires

Requires (Dev)

Suggests

Provides

None

Conflicts

Replaces

None

MIT aa572d1d2505baf27706c8561e8ae6e0e2cb8cc9

bundlerequestdto

This package is auto-updated.

Last update: 2026-06-21 15:46:46 UTC


README

RequestDtoBundle

This Symfony Bundle provides request objects support for Symfony controller actions.

👁 Packagist Version
👁 Packagist PHP Version Support
👁 Build Status
👁 Scrutinizer Code Quality
👁 Code Coverage
👁 Packagist License

Installation

Require the bundle with composer:

composer require nelexa/request-dto-bundle

Versions & Dependencies

Bundle version Symfony version PHP version(s)
1.0.*
1.1.*
1.2.0
^5.0 ^7.4
~1.2.1 ^5.0 ^7.4 | ^8.0
1.3.0 - 1.3.1 ^5.1 ^7.4 | ^8.0 | ^8.1
~1.3.2 ^5.1 | ^6.0 ^7.4 | ^8.0 | ^8.1
~1.3.3 ^4.4 |^5.1 | ^6.0 ^7.4 | ^8.0 | ^8.1

Examples of using

To specify an object as an argument of a controller action, an object must implement one of 4 interfaces:

  • \Nelexa\RequestDtoBundle\Dto\QueryObjectInterface query parameters for GET or HEAD request methods.
  • \Nelexa\RequestDtoBundle\Dto\RequestObjectInterface request parameters for POST, PUT or DELETE request methods (ex. Content-Type: application/x-www-form-urlencoded) or query parameters for GET and HEAD request methods.
  • \Nelexa\RequestDtoBundle\Dto\RequestBodyObjectInterface for POST, PUT, DELETE request body contents (ex. Content-Type: application/json).
  • \Nelexa\RequestDtoBundle\Dto\ConstructRequestObjectInterface for mapping a request for a data transfer object in the class constructor.

Create request DTO:

use Nelexa\RequestDtoBundle\Dto\RequestObjectInterface;
use Symfony\Component\Validator\Constraints as Assert;

class UserRegistrationRequest implements RequestObjectInterface
{
 /** @Assert\NotBlank() */
 public ?string $login = null;

 /**
 * @Assert\NotBlank()
 * @Assert\Length(min="6")
 */
 public ?string $password = null;

 /**
 * @Assert\NotBlank()
 * @Assert\Email()
 */
 public ?string $email = null;
}

Use in the controller:

<?php

declare(strict_types=1);

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\ConstraintViolationListInterface;

class AppController extends AbstractController
{
 /**
 * @Route("/sign-up", methods={"POST"})
 */
 public function registration(
 UserRegistrationRequest $userRegistrationRequest,
 ConstraintViolationListInterface $errors
 ): Response {
 $data = ['success' => $errors->count() === 0];
 
 if ($errors->count() > 0){
 $data['errors'] = $errors;
 }
 else{
 $data['data'] = $userRegistrationRequest;
 }
 
 return $this->json($data);
 }
}

If you declare an argument with type \Symfony\Component\Validator\ConstraintViolationListInterface as nullable, then if there are no errors, it will be null.

...

 /**
 * @Route("/sign-up", methods={"POST"})
 */
 public function registration(
 UserRegistrationRequest $userRegistrationRequest,
 ?ConstraintViolationListInterface $errors
 ): Response {
 return $this->json(
 [
 'success' => $errors === null,
 'errors' => $errors,
 ]
 );
 }

...

If the argument \Symfony\Component\Validator\ConstraintViolationListInterface is not declare, then the exception \Nelexa\RequestDtoBundle\Exception\RequestDtoValidationException will be thrown, which will be converted to the json or xml format.

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class AppController extends AbstractController{
 /**
 * @Route("/sign-up", methods={"POST"})
 */
 public function registration(UserRegistrationRequest $userRegistrationRequest): Response {
 return $this->json(['success' => true]);
 }
}

Send POST request:

curl 'https://127.0.0.1/registration' -H 'Accept: application/json' -H 'Content-Type: application/x-www-form-urlencoded' --data-raw 'login=johndoe'

Response:

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

Content response:

{
 "type": "https://tools.ietf.org/html/rfc7807",
 "title": "Validation Failed",
 "detail": "password: This value should not be blank.\nemail: This value should not be blank.",
 "violations": [
 {
 "propertyPath": "password",
 "title": "This value should not be blank.",
 "parameters": {
 "{{ value }}": "null"
 },
 "type": "urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3"
 },
 {
 "propertyPath": "email",
 "title": "This value should not be blank.",
 "parameters": {
 "{{ value }}": "null"
 },
 "type": "urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3"
 }
 ]
}

Construct DTO from Request (version 1.1.0+)

use Nelexa\RequestDtoBundle\Dto\ConstructRequestObjectInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\ConstraintViolationListInterface;

class ExampleDTO implements ConstructRequestObjectInterface
{
 /** @Assert\Range(min=1) */
 private int $page;

 /**
 * @Assert\NotBlank
 * @Assert\Regex("~^\d{10,13}$~", message="Invalid phone number")
 */
 private string $phone;

 public function __construct(Request $request)
 {
 $this->page = $request->request->getInt('p', 1);

 // sanitize phone number
 $phone = (string) $request->request->get('phone');
 $phone = preg_replace('~\D~', '', $phone);
 $this->phone = (string) $phone;
 }

 public function getPage(): int
 {
 return $this->page;
 }

 public function getPhone(): string
 {
 return $this->phone;
 }
}

class AppController extends AbstractController
{
 public function exampleAction(
 ExampleDTO $dto,
 ConstraintViolationListInterface $errors
 ): Response {
 $data = [
 'page' => $dto->getPage(),
 'phone' => $dto->getPhone(),
 'errors' => $errors,
 ];

 return $this->json($data, $errors->count() === 0 ? 200 : 400);
 }
}

Changelog

Changes are documented in the releases page.

License

The MIT License (MIT). Please see LICENSE for more information.