vendor/friendsofsymfony/rest-bundle/Request/ParamFetcher.php line 36

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the FOSRestBundle package.
  4. *
  5. * (c) FriendsOfSymfony <http://friendsofsymfony.github.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 FOS\RestBundle\Request;
  11. use FOS\RestBundle\Controller\Annotations\ParamInterface;
  12. use FOS\RestBundle\Exception\InvalidParameterException;
  13. use FOS\RestBundle\Util\ResolverTrait;
  14. use FOS\RestBundle\Validator\Constraints\ResolvableConstraintInterface;
  15. use Symfony\Component\DependencyInjection\ContainerInterface;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\RequestStack;
  18. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  19. use Symfony\Component\Validator\Constraint;
  20. use Symfony\Component\Validator\ConstraintViolationList;
  21. use Symfony\Component\Validator\Validator\ValidatorInterface;
  22. use Symfony\Component\Validator\Exception\ValidatorException;
  23. use Symfony\Component\Validator\ConstraintViolation;
  24. /**
  25. * Helper to validate parameters of the active request.
  26. *
  27. * @author Alexander <iam.asm89@gmail.com>
  28. * @author Lukas Kahwe Smith <smith@pooteeweet.org>
  29. * @author Jordi Boggiano <j.boggiano@seld.be>
  30. * @author Boris Guéry <guery.b@gmail.com>
  31. */
  32. final class ParamFetcher implements ParamFetcherInterface
  33. {
  34. use ResolverTrait;
  35. private $container;
  36. private $parameterBag;
  37. private $requestStack;
  38. private $validator;
  39. public function __construct(ContainerInterface $container, ParamReaderInterface $paramReader, RequestStack $requestStack, ValidatorInterface $validator)
  40. {
  41. $this->container = $container;
  42. $this->requestStack = $requestStack;
  43. $this->validator = $validator;
  44. $this->parameterBag = new ParameterBag($paramReader);
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function setController(callable $controller): void
  50. {
  51. $this->parameterBag->setController($this->getRequest(), $controller);
  52. }
  53. /**
  54. * Add additional params to the ParamFetcher during runtime.
  55. *
  56. * Note that adding a param that has the same name as an existing param will override that param.
  57. */
  58. public function addParam(ParamInterface $param): void
  59. {
  60. $this->parameterBag->addParam($this->getRequest(), $param);
  61. }
  62. /**
  63. * @return ParamInterface[]
  64. */
  65. public function getParams(): array
  66. {
  67. return $this->parameterBag->getParams($this->getRequest());
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. public function get(string $name, ?bool $strict = null)
  73. {
  74. $params = $this->getParams();
  75. if (!array_key_exists($name, $params)) {
  76. throw new \InvalidArgumentException(sprintf("No @ParamInterface configuration for parameter '%s'.", $name));
  77. }
  78. /** @var ParamInterface $param */
  79. $param = $params[$name];
  80. $default = $param->getDefault();
  81. $default = $this->resolveValue($this->container, $default);
  82. $strict = (null !== $strict ? $strict : $param->isStrict());
  83. $paramValue = $param->getValue($this->getRequest(), $default);
  84. return $this->cleanParamWithRequirements($param, $paramValue, $strict, $default);
  85. }
  86. private function cleanParamWithRequirements(ParamInterface $param, $paramValue, bool $strict, $default)
  87. {
  88. $this->checkNotIncompatibleParams($param);
  89. if (null !== $default && $default === $paramValue) {
  90. return $paramValue;
  91. }
  92. $constraints = $param->getConstraints();
  93. $this->resolveConstraints($constraints);
  94. if (empty($constraints)) {
  95. return $paramValue;
  96. }
  97. try {
  98. $errors = $this->validator->validate($paramValue, $constraints);
  99. } catch (ValidatorException $e) {
  100. $violation = new ConstraintViolation(
  101. $e->getMessage(),
  102. $e->getMessage(),
  103. [],
  104. $paramValue,
  105. '',
  106. null,
  107. null,
  108. $e->getCode()
  109. );
  110. $errors = new ConstraintViolationList([$violation]);
  111. }
  112. if (0 < count($errors)) {
  113. if ($strict) {
  114. throw InvalidParameterException::withViolations($param, $errors);
  115. }
  116. return null === $default ? '' : $default;
  117. }
  118. return $paramValue;
  119. }
  120. /**
  121. * {@inheritdoc}
  122. */
  123. public function all(?bool $strict = null): array
  124. {
  125. $configuredParams = $this->getParams();
  126. $params = [];
  127. foreach ($configuredParams as $name => $param) {
  128. $params[$name] = $this->get($name, $strict);
  129. }
  130. return $params;
  131. }
  132. private function checkNotIncompatibleParams(ParamInterface $param): void
  133. {
  134. if (null === $param->getValue($this->getRequest(), null)) {
  135. return;
  136. }
  137. $params = $this->getParams();
  138. foreach ($param->getIncompatibilities() as $incompatibleParamName) {
  139. if (!array_key_exists($incompatibleParamName, $params)) {
  140. throw new \InvalidArgumentException(sprintf("No @ParamInterface configuration for parameter '%s'.", $incompatibleParamName));
  141. }
  142. $incompatibleParam = $params[$incompatibleParamName];
  143. if (null !== $incompatibleParam->getValue($this->getRequest(), null)) {
  144. $exceptionMessage = sprintf(
  145. '"%s" param is incompatible with %s param.',
  146. $param->getName(),
  147. $incompatibleParam->getName()
  148. );
  149. throw new BadRequestHttpException($exceptionMessage);
  150. }
  151. }
  152. }
  153. /**
  154. * @param Constraint[] $constraints
  155. */
  156. private function resolveConstraints(array $constraints): void
  157. {
  158. foreach ($constraints as $constraint) {
  159. if ($constraint instanceof ResolvableConstraintInterface) {
  160. $constraint->resolve($this->container);
  161. }
  162. }
  163. }
  164. private function getRequest(): Request
  165. {
  166. $request = $this->requestStack->getCurrentRequest();
  167. if (null === $request) {
  168. throw new \RuntimeException('There is no current request.');
  169. }
  170. return $request;
  171. }
  172. }