PageRenderTime 26ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/Request/RequestBodyParamConverter.php

http://github.com/FriendsOfSymfony/FOSRestBundle
PHP | 155 lines | 112 code | 23 blank | 20 comment | 14 complexity | 6a7e573e9a1585ed6d7c46d37e260bc9 MD5 | raw file
  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\Context\Context;
  12. use FOS\RestBundle\Serializer\Serializer;
  13. use JMS\Serializer\Exception\Exception as JMSSerializerException;
  14. use JMS\Serializer\Exception\UnsupportedFormatException;
  15. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  16. use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  19. use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
  20. use Symfony\Component\OptionsResolver\OptionsResolver;
  21. use Symfony\Component\Serializer\Exception\ExceptionInterface as SymfonySerializerException;
  22. use Symfony\Component\Validator\Validator\ValidatorInterface;
  23. /**
  24. * @author Tyler Stroud <tyler@tylerstroud.com>
  25. */
  26. final class RequestBodyParamConverter implements ParamConverterInterface
  27. {
  28. private $serializer;
  29. private $context = [];
  30. private $validator;
  31. private $validationErrorsArgument;
  32. /**
  33. * @param string[]|null $groups
  34. */
  35. public function __construct(
  36. Serializer $serializer,
  37. ?array $groups = null,
  38. ?string $version = null,
  39. ValidatorInterface $validator = null,
  40. ?string $validationErrorsArgument = null
  41. ) {
  42. $this->serializer = $serializer;
  43. if (!empty($groups)) {
  44. $this->context['groups'] = (array) $groups;
  45. }
  46. if (!empty($version)) {
  47. $this->context['version'] = $version;
  48. }
  49. if (null !== $validator && null === $validationErrorsArgument) {
  50. throw new \InvalidArgumentException('"$validationErrorsArgument" cannot be null when using the validator');
  51. }
  52. $this->validator = $validator;
  53. $this->validationErrorsArgument = $validationErrorsArgument;
  54. }
  55. /**
  56. * {@inheritdoc}
  57. */
  58. public function apply(Request $request, ParamConverter $configuration): bool
  59. {
  60. $options = (array) $configuration->getOptions();
  61. if (isset($options['deserializationContext']) && is_array($options['deserializationContext'])) {
  62. $arrayContext = array_merge($this->context, $options['deserializationContext']);
  63. } else {
  64. $arrayContext = $this->context;
  65. }
  66. $this->configureContext($context = new Context(), $arrayContext);
  67. try {
  68. $object = $this->serializer->deserialize(
  69. $request->getContent(),
  70. $configuration->getClass(),
  71. $request->getContentType(),
  72. $context
  73. );
  74. } catch (UnsupportedFormatException $e) {
  75. return $this->throwException(new UnsupportedMediaTypeHttpException($e->getMessage(), $e), $configuration);
  76. } catch (JMSSerializerException $e) {
  77. return $this->throwException(new BadRequestHttpException($e->getMessage(), $e), $configuration);
  78. } catch (SymfonySerializerException $e) {
  79. return $this->throwException(new BadRequestHttpException($e->getMessage(), $e), $configuration);
  80. }
  81. $request->attributes->set($configuration->getName(), $object);
  82. if (null !== $this->validator && (!isset($options['validate']) || $options['validate'])) {
  83. $validatorOptions = $this->getValidatorOptions($options);
  84. $errors = $this->validator->validate($object, null, $validatorOptions['groups']);
  85. $request->attributes->set(
  86. $this->validationErrorsArgument,
  87. $errors
  88. );
  89. }
  90. return true;
  91. }
  92. /**
  93. * {@inheritdoc}
  94. */
  95. public function supports(ParamConverter $configuration): bool
  96. {
  97. return null !== $configuration->getClass() && 'fos_rest.request_body' === $configuration->getConverter();
  98. }
  99. private function configureContext(Context $context, array $options): void
  100. {
  101. foreach ($options as $key => $value) {
  102. if ('groups' === $key) {
  103. $context->addGroups($options['groups']);
  104. } elseif ('version' === $key) {
  105. $context->setVersion($options['version']);
  106. } elseif ('enableMaxDepth' === $key) {
  107. $context->enableMaxDepth($options['enableMaxDepth']);
  108. } elseif ('serializeNull' === $key) {
  109. $context->setSerializeNull($options['serializeNull']);
  110. } else {
  111. $context->setAttribute($key, $value);
  112. }
  113. }
  114. }
  115. private function throwException(\Exception $exception, ParamConverter $configuration): bool
  116. {
  117. if ($configuration->isOptional()) {
  118. return false;
  119. }
  120. throw $exception;
  121. }
  122. private function getValidatorOptions(array $options): array
  123. {
  124. $resolver = new OptionsResolver();
  125. $resolver->setDefaults([
  126. 'groups' => null,
  127. 'traverse' => false,
  128. 'deep' => false,
  129. ]);
  130. return $resolver->resolve(isset($options['validator']) ? $options['validator'] : []);
  131. }
  132. }