BackedEnumValueResolver.php 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
  13. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
  14. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  15. /**
  16. * Attempt to resolve backed enum cases from request attributes, for a route path parameter,
  17. * leading to a 404 Not Found if the attribute value isn't a valid backing value for the enum type.
  18. *
  19. * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
  20. */
  21. final class BackedEnumValueResolver implements ValueResolverInterface
  22. {
  23. public function resolve(Request $request, ArgumentMetadata $argument): iterable
  24. {
  25. if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
  26. return [];
  27. }
  28. if ($argument->isVariadic()) {
  29. // only target route path parameters, which cannot be variadic.
  30. return [];
  31. }
  32. // do not support if no value can be resolved at all
  33. // letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
  34. // or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
  35. if (!$request->attributes->has($argument->getName())) {
  36. return [];
  37. }
  38. $value = $request->attributes->get($argument->getName());
  39. if (null === $value) {
  40. return [null];
  41. }
  42. if ($value instanceof \BackedEnum) {
  43. return [$value];
  44. }
  45. if (!\is_int($value) && !\is_string($value)) {
  46. throw new \LogicException(\sprintf('Could not resolve the "%s $%s" controller argument: expecting an int or string, got "%s".', $argument->getType(), $argument->getName(), get_debug_type($value)));
  47. }
  48. /** @var class-string<\BackedEnum> $enumType */
  49. $enumType = $argument->getType();
  50. try {
  51. return [$enumType::from($value)];
  52. } catch (\ValueError|\TypeError $e) {
  53. throw new NotFoundHttpException(\sprintf('Could not resolve the "%s $%s" controller argument: ', $argument->getType(), $argument->getName()).$e->getMessage(), $e);
  54. }
  55. }
  56. }