|
|
@ -2,5 +2,124 @@ |
|
|
|
[![coverage report](https://git.rinsvent.ru/symfony/bundles/request-bundle/badges/master/coverage.svg)](https://git.rinsvent.ru/symfony/bundles/request-bundle/-/commits/master) |
|
|
|
[![coverage report](https://git.rinsvent.ru/symfony/bundles/request-bundle/badges/master/coverage.svg)](https://git.rinsvent.ru/symfony/bundles/request-bundle/-/commits/master) |
|
|
|
|
|
|
|
|
|
|
|
Request bundle |
|
|
|
Request bundle |
|
|
|
= |
|
|
|
=== |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bundle умеет конвертировать request в DTO |
|
|
|
|
|
|
|
Полученная DTO валидируется. |
|
|
|
|
|
|
|
В случае ошибок выполнение прекращается и возвращаются ошибки. |
|
|
|
|
|
|
|
В случае успеха DTO присваиваются в атрибуты и доступны в методе контроллера. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Пример запроса |
|
|
|
|
|
|
|
```json |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
"signin": { |
|
|
|
|
|
|
|
"transport": "phone", |
|
|
|
|
|
|
|
"value": "8888888888", |
|
|
|
|
|
|
|
"code": "password" |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
### Пример DTO |
|
|
|
|
|
|
|
```php |
|
|
|
|
|
|
|
namespace App\DTO\Request; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use Rinsvent\Data2DTO\Attribute\HandleTags; |
|
|
|
|
|
|
|
use Rinsvent\Data2DTO\Attribute\VirtualProperty; |
|
|
|
|
|
|
|
use Symfony\Component\Validator\Constraints as Assert; |
|
|
|
|
|
|
|
use App\Validator as ProjectAssert; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use Rinsvent\Data2DTO\Attribute\PropertyPath; |
|
|
|
|
|
|
|
use Rinsvent\Data2DTOBundle\Service\Transformer\Request\Headers\Header; |
|
|
|
|
|
|
|
use Rinsvent\Data2DTOBundle\Service\Transformer\Request\Headers\UserAgent; |
|
|
|
|
|
|
|
use Rinsvent\Data2DTOBundle\Service\Transformer\Request\Server\Ip; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[HandleTags(method: 'getTags')] |
|
|
|
|
|
|
|
class SigninRequest |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.transport.empty")] |
|
|
|
|
|
|
|
public string $transport; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.value.empty")] |
|
|
|
|
|
|
|
#[Assert\Email(message: "error.email.wrong", groups: "email")] |
|
|
|
|
|
|
|
#[ProjectAssert\Phone(message: "error.phone.wrong", groups: "phone")] |
|
|
|
|
|
|
|
public string $value; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.code.empty")] |
|
|
|
|
|
|
|
public string $code; |
|
|
|
|
|
|
|
#[VirtualProperty] |
|
|
|
|
|
|
|
public Device $device; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getTags(array $data, array $tags) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$transport = $data['transport'] ?? null; |
|
|
|
|
|
|
|
if ($transport) { |
|
|
|
|
|
|
|
$tags[] = $transport; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return $tags; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Device |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.device.id.empty")] |
|
|
|
|
|
|
|
#[Header(property: 'X-Device-Id')] |
|
|
|
|
|
|
|
public string $deviceId; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.device.source.empty")] |
|
|
|
|
|
|
|
#[Header(property: 'X-Source')] |
|
|
|
|
|
|
|
public string $source; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.device.ip.empty")] |
|
|
|
|
|
|
|
#[Ip] |
|
|
|
|
|
|
|
public ?string $ip = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Assert\NotBlank(message: "error.device.user_agent.empty")] |
|
|
|
|
|
|
|
#[UserAgent] |
|
|
|
|
|
|
|
public string $userAgent; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
### Использование |
|
|
|
|
|
|
|
```php |
|
|
|
|
|
|
|
namespace App\Controller; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use App\Form\Type\User\DTO\SigninRequest; |
|
|
|
|
|
|
|
use App\Service\Entity\UserService; |
|
|
|
|
|
|
|
use Rinsvent\RequestBundle\Annotation\RequestDTO; |
|
|
|
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; |
|
|
|
|
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse; |
|
|
|
|
|
|
|
use Symfony\Component\HttpFoundation\Response; |
|
|
|
|
|
|
|
use Symfony\Component\Routing\Annotation\Route; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserController extends AbstractController |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
public function __construct( |
|
|
|
|
|
|
|
private UserService $us |
|
|
|
|
|
|
|
) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Route('/v1/signin', name: 'signin', methods: ['POST'])] |
|
|
|
|
|
|
|
#[RequestDTO(className: SigninRequest::class, jsonPath: '$.signin')] |
|
|
|
|
|
|
|
public function signin(SigninRequest $signinRequest) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$signinResponse = $this->us->signin($signinRequest); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new JsonResponse( |
|
|
|
|
|
|
|
[], |
|
|
|
|
|
|
|
Response::HTTP_OK, |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
'X-Access-Token' => $signinResponse->getAccessToken(), |
|
|
|
|
|
|
|
'X-Refresh-Token' => $signinResponse->getRefreshToken(), |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Вариант с несколькими DTO |
|
|
|
|
|
|
|
#[Route('/v1/signin', name: 'signin', methods: ['POST'])] |
|
|
|
|
|
|
|
#[RequestDTO(className: SigninRequest::class, jsonPath: '$.signin')] |
|
|
|
|
|
|
|
#[RequestDTO(className: Device::class)] |
|
|
|
|
|
|
|
public function signin2(SigninRequest $signinRequest, Device $device) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$signinResponse = $this->us->signin2($signinRequest, $device); |
|
|
|
|
|
|
|
return new JsonResponse(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|