ParamConversionEnhancer.php 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. <?php
  2. namespace Drupal\Core\Routing\Enhancer;
  3. use Drupal\Core\ParamConverter\ParamConverterManagerInterface;
  4. use Drupal\Core\ParamConverter\ParamNotConvertedException;
  5. use Drupal\Core\Routing\EnhancerInterface;
  6. use Symfony\Cmf\Component\Routing\RouteObjectInterface;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Symfony\Component\HttpFoundation\ParameterBag;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  11. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  12. use Symfony\Component\HttpKernel\KernelEvents;
  13. /**
  14. * Provides a route enhancer that handles parameter conversion.
  15. */
  16. class ParamConversionEnhancer implements EnhancerInterface, EventSubscriberInterface {
  17. /**
  18. * The parameter conversion manager.
  19. *
  20. * @var \Drupal\Core\ParamConverter\ParamConverterManagerInterface
  21. */
  22. protected $paramConverterManager;
  23. /**
  24. * Constructs a new ParamConversionEnhancer.
  25. *
  26. * @param \Drupal\Core\ParamConverter\ParamConverterManagerInterface $param_converter_manager
  27. * The parameter conversion manager.
  28. */
  29. public function __construct(ParamConverterManagerInterface $param_converter_manager) {
  30. $this->paramConverterManager = $param_converter_manager;
  31. }
  32. /**
  33. * {@inheritdoc}
  34. */
  35. public function enhance(array $defaults, Request $request) {
  36. // Just run the parameter conversion once per request.
  37. if (!isset($defaults['_raw_variables'])) {
  38. $defaults['_raw_variables'] = $this->copyRawVariables($defaults);
  39. $defaults = $this->paramConverterManager->convert($defaults);
  40. }
  41. return $defaults;
  42. }
  43. /**
  44. * Store a backup of the raw values that corresponding to the route pattern.
  45. *
  46. * @param array $defaults
  47. * The route defaults array.
  48. *
  49. * @return \Symfony\Component\HttpFoundation\ParameterBag
  50. */
  51. protected function copyRawVariables(array $defaults) {
  52. /** @var $route \Symfony\Component\Routing\Route */
  53. $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
  54. $variables = array_flip($route->compile()->getVariables());
  55. // Foreach will copy the values from the array it iterates. Even if they
  56. // are references, use it to break them. This avoids any scenarios where raw
  57. // variables also get replaced with converted values.
  58. $raw_variables = [];
  59. foreach (array_intersect_key($defaults, $variables) as $key => $value) {
  60. $raw_variables[$key] = $value;
  61. }
  62. return new ParameterBag($raw_variables);
  63. }
  64. /**
  65. * Catches failed parameter conversions and throw a 404 instead.
  66. *
  67. * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  68. */
  69. public function onException(GetResponseForExceptionEvent $event) {
  70. $exception = $event->getException();
  71. if ($exception instanceof ParamNotConvertedException) {
  72. $event->setException(new NotFoundHttpException($exception->getMessage(), $exception));
  73. }
  74. }
  75. /**
  76. * {@inheritdoc}
  77. */
  78. public static function getSubscribedEvents() {
  79. $events[KernelEvents::EXCEPTION][] = ['onException', 75];
  80. return $events;
  81. }
  82. }