Skip to content

Instantly share code, notes, and snippets.

@Loupax
Last active October 1, 2020 18:45
Show Gist options
  • Save Loupax/fa011ac275b0b3f71ef0d76fdaf00449 to your computer and use it in GitHub Desktop.
Save Loupax/fa011ac275b0b3f71ef0d76fdaf00449 to your computer and use it in GitHub Desktop.
SomethingLikeValueResolver
<?php
declare(strict_types=1);
namespace App\Listener;
use App\MyDto;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class ControllerListener
{
private $validator;
private $denormalizer;
public function __construct(
DenormalizerInterface $denormalizer,
ValidatorInterface $validator
)
{
$this->denormalizer = $denormalizer;
$this->validator = $validator;
}
public function onKernelController(ControllerEvent $event): void
{
$argName = false;
// 1: Check if the current controller expects a MyDto as an argument
// 2: If it does, create it and inject it in the request so that the controller can have access to it
// 2.5: If the DTO is invalid, return intercept the request and just return a Bad Request response
/** @var \ReflectionParameter $reflectionParameter */
foreach ($this->extractCallableParams($event->getController()) as $reflectionParameter) {
if ((string)$reflectionParameter->getType() === MyDto::class) {
$argName = $reflectionParameter->getName();
break;
}
}
if ($argName === false) {
return;
}
$request = $event->getRequest();
$dto = $this->denormalizer->denormalize($request->query->all(), MyDto::class);
$validationErrors = $this->validator->validate($dto);
if ($validationErrors->count() > 0) {
$event->setController(function () use ($validationErrors) {
return new JsonResponse(
[
'errors' => array_map(function($err){return $err->getMessage();}, $validationErrors),
],
Response::HTTP_BAD_REQUEST
);
});
$event->stopPropagation();
return;
}
$event->getRequest()->attributes->set($argName, $dto);
}
private function extractCallableParams(callable $callable): array
{
if ($callable instanceof Closure || is_object($callable)) {
$name = '';
is_callable($callable, false, $name);
if (strpos($name, '::') !== false) {
$r = new \ReflectionMethod($name);
} else {
$r = new \ReflectionFunction($name);
}
} else {
$r = new \ReflectionFunction($callable);
}
return $r->getParameters();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment