You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.6 KiB

3 years ago
  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;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver;
  13. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
  14. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
  15. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
  16. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
  17. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
  18. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
  19. /**
  20. * Responsible for resolving the arguments passed to an action.
  21. *
  22. * @author Iltar van der Berg <kjarli@gmail.com>
  23. */
  24. final class ArgumentResolver implements ArgumentResolverInterface
  25. {
  26. private $argumentMetadataFactory;
  27. /**
  28. * @var iterable|ArgumentValueResolverInterface[]
  29. */
  30. private $argumentValueResolvers;
  31. public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [])
  32. {
  33. $this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory();
  34. $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function getArguments(Request $request, callable $controller): array
  40. {
  41. $arguments = [];
  42. foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller) as $metadata) {
  43. foreach ($this->argumentValueResolvers as $resolver) {
  44. if (!$resolver->supports($request, $metadata)) {
  45. continue;
  46. }
  47. $resolved = $resolver->resolve($request, $metadata);
  48. $atLeastOne = false;
  49. foreach ($resolved as $append) {
  50. $atLeastOne = true;
  51. $arguments[] = $append;
  52. }
  53. if (!$atLeastOne) {
  54. throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', get_debug_type($resolver)));
  55. }
  56. // continue to the next controller argument
  57. continue 2;
  58. }
  59. $representative = $controller;
  60. if (\is_array($representative)) {
  61. $representative = sprintf('%s::%s()', \get_class($representative[0]), $representative[1]);
  62. } elseif (\is_object($representative)) {
  63. $representative = \get_class($representative);
  64. }
  65. throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.', $representative, $metadata->getName()));
  66. }
  67. return $arguments;
  68. }
  69. public static function getDefaultArgumentValueResolvers(): iterable
  70. {
  71. return [
  72. new RequestAttributeValueResolver(),
  73. new RequestValueResolver(),
  74. new SessionValueResolver(),
  75. new DefaultValueResolver(),
  76. new VariadicValueResolver(),
  77. ];
  78. }
  79. }