# Conflicts: # src/EventListener/RequestListener.php # tests/unit/Listener/FillTest.php
108 lines
4.0 KiB
PHP
108 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace Rinsvent\RequestBundle\EventListener;
|
|
|
|
use JMS\Serializer\SerializerBuilder;
|
|
use ReflectionObject;
|
|
use Rinsvent\RequestBundle\Annotation\RequestDTO;
|
|
use Rinsvent\RequestBundle\Annotation\HeaderKey;
|
|
use Rinsvent\RequestBundle\DTO\Error;
|
|
use Rinsvent\RequestBundle\DTO\ErrorCollection;
|
|
use Rinsvent\AttributeExtractor\MethodExtractor;
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
|
use Symfony\Component\Validator\Validation;
|
|
|
|
// todo базовая заготовка. Требуется рефакторинг
|
|
class RequestListener
|
|
{
|
|
public const REQUEST_DATA = 'request_data';
|
|
|
|
public function onKernelRequest(RequestEvent $event)
|
|
{
|
|
$request = $event->getRequest();
|
|
$controller = $request->get('_controller');
|
|
if (is_string($controller)) {
|
|
$controller = explode('::', $controller);
|
|
}
|
|
if (is_callable($controller)){
|
|
if (is_object($controller[0])) {
|
|
$controller[0] = get_class($controller[0]);
|
|
}
|
|
$methodExtractor = new MethodExtractor($controller[0], $controller[1]);
|
|
}
|
|
|
|
/** @var RequestDTO $requestDTO */
|
|
if ($requestDTO = $methodExtractor->fetch(RequestDTO::class)) {
|
|
$requestDTOInstance = $this->grabRequestDTO($requestDTO->className, $request->getContent(), $request->query->all(), $request->request->all(), $request->headers->all());
|
|
|
|
$errorCollection = $this->validate($requestDTOInstance);
|
|
if ($errorCollection->hasErrors()) {
|
|
$event->setResponse(new JsonResponse(['errors' => $errorCollection->format()], Response::HTTP_BAD_REQUEST));
|
|
} else {
|
|
$request->attributes->set(self::REQUEST_DATA, $requestDTOInstance);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected function validate(object $data): ErrorCollection
|
|
{
|
|
$validator = Validation::createValidatorBuilder()
|
|
->enableAnnotationMapping(true)
|
|
->addDefaultDoctrineAnnotationReader()
|
|
->getValidator();
|
|
|
|
$violations = $validator->validate($data);
|
|
|
|
$errorCollection = new ErrorCollection();
|
|
if ($violations->count()) {
|
|
foreach ($violations as $violation) {
|
|
$errorCollection->add(new Error($violation->getMessage(), $violation->getPropertyPath()));
|
|
}
|
|
}
|
|
return $errorCollection;
|
|
}
|
|
|
|
/**
|
|
* todo переделать на перебор филлеров
|
|
* Сделать регистрацию филлеров
|
|
* и выексти филеры заполнения entity и documents в отдельных бандлах
|
|
*/
|
|
protected function grabRequestDTO(string $requestClass, string $content, array $queryParameters = [], array $parameters = [], array $headers = [])
|
|
{
|
|
$serializer = SerializerBuilder::create()->build();
|
|
if ($content) {
|
|
$object = $serializer->deserialize($content, $requestClass, 'json');
|
|
} else {
|
|
$object = new $requestClass;
|
|
}
|
|
$this->fillFromData($object, $queryParameters);
|
|
$this->fillFromData($object, $parameters);
|
|
$this->fillFromData($object, $headers);
|
|
return $object;
|
|
}
|
|
|
|
protected function fillFromData(object $object, array $data): object
|
|
{
|
|
$reflectionObject = new ReflectionObject($object);
|
|
$properties = $reflectionObject->getProperties();
|
|
foreach ($properties as $property) {
|
|
$attributes = $property->getAttributes(HeaderKey::class);
|
|
$attribute = $attributes[0] ?? null;
|
|
if ($attribute) {
|
|
/** @var HeaderKey $headerKey */
|
|
$headerKey = $attribute->newInstance();
|
|
$value = $data[strtolower($headerKey->key)][0] ?? null;
|
|
} else {
|
|
$value = $data[$property->getName()] ?? null;
|
|
}
|
|
if ($value) {
|
|
$property->setValue($object, $value);
|
|
}
|
|
}
|
|
|
|
return $object;
|
|
}
|
|
}
|