BackedEnumValueResolver.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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\ArgumentValueResolverInterface;
  13. use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
  14. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
  15. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  16. /**
  17. * Attempt to resolve backed enum cases from request attributes, for a route path parameter,
  18. * leading to a 404 Not Found if the attribute value isn't a valid backing value for the enum type.
  19. *
  20. * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
  21. *
  22. * @final since Symfony 6.2
  23. */
  24. class BackedEnumValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
  25. {
  26. /**
  27. * @deprecated since Symfony 6.2, use resolve() instead
  28. */
  29. public function supports(Request $request, ArgumentMetadata $argument): bool
  30. {
  31. @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
  32. if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
  33. return false;
  34. }
  35. if ($argument->isVariadic()) {
  36. // only target route path parameters, which cannot be variadic.
  37. return false;
  38. }
  39. // do not support if no value can be resolved at all
  40. // letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
  41. // or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
  42. return $request->attributes->has($argument->getName());
  43. }
  44. public function resolve(Request $request, ArgumentMetadata $argument): iterable
  45. {
  46. if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
  47. return [];
  48. }
  49. if ($argument->isVariadic()) {
  50. // only target route path parameters, which cannot be variadic.
  51. return [];
  52. }
  53. // do not support if no value can be resolved at all
  54. // letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
  55. // or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
  56. if (!$request->attributes->has($argument->getName())) {
  57. return [];
  58. }
  59. $value = $request->attributes->get($argument->getName());
  60. if (null === $value) {
  61. return [null];
  62. }
  63. if ($value instanceof \BackedEnum) {
  64. return [$value];
  65. }
  66. if (!\is_int($value) && !\is_string($value)) {
  67. 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)));
  68. }
  69. /** @var class-string<\BackedEnum> $enumType */
  70. $enumType = $argument->getType();
  71. try {
  72. return [$enumType::from($value)];
  73. } catch (\ValueError|\TypeError $e) {
  74. throw new NotFoundHttpException(\sprintf('Could not resolve the "%s $%s" controller argument: ', $argument->getType(), $argument->getName()).$e->getMessage(), $e);
  75. }
  76. }
  77. }