nelexa / request-dto-bundle

此Symfony扩展为Symfony控制器操作提供请求对象支持

安装次数: 12,101

依赖者: 0

建议者: 0

安全: 0

星级: 9

关注者: 2

分支: 3

开放问题: 0

类型:symfony-bundle

1.3.4 2022-06-21 07:01 UTC

This package is auto-updated.

Last update: 2024-09-21 11:48:15 UTC


README

RequestDtoBundle

此Symfony扩展为Symfony控制器操作提供请求对象支持。

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

安装

使用composer安装此扩展

composer require nelexa/request-dto-bundle

版本和依赖

使用示例

要指定一个对象作为控制器动作的参数,该对象必须实现以下4个接口之一

  • \Nelexa\RequestDtoBundle\Dto\QueryObjectInterface 用于GET或HEAD请求方法的查询参数。
  • \Nelexa\RequestDtoBundle\Dto\RequestObjectInterface 用于POST、PUT或DELETE请求方法的请求参数(例如,Content-Type: application/x-www-form-urlencoded)或GET和HEAD请求方法的查询参数。
  • \Nelexa\RequestDtoBundle\Dto\RequestBodyObjectInterface 用于POST、PUT、DELETE请求体的内容(例如,Content-Type: application/json)。
  • \Nelexa\RequestDtoBundle\Dto\ConstructRequestObjectInterface 用于在类构造函数中将请求映射到数据传输对象。

创建请求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;
}

在控制器中使用

<?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);
    }
}

如果您将类型为 \Symfony\Component\Validator\ConstraintViolationListInterface 的参数声明为可空,则如果没有错误,它将为 null

...

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

...

如果未声明 \Symfony\Component\Validator\ConstraintViolationListInterface 参数,则将抛出 \Nelexa\RequestDtoBundle\Exception\RequestDtoValidationException 异常,该异常将被转换为 jsonxml 格式。

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]);
    }
}

发送POST请求

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

响应

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

内容响应

{
    "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"
        }
    ]
}

从请求构建DTO(版本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);
    }
}

变更日志

变更记录在 发布页面 中。

许可

MIT许可(MIT)。有关更多信息,请参阅 LICENSE