ParamConverterManager.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. namespace Drupal\Core\ParamConverter;
  3. use Symfony\Cmf\Component\Routing\RouteObjectInterface;
  4. use Symfony\Component\Routing\RouteCollection;
  5. /**
  6. * Manages converter services for converting request parameters to full objects.
  7. *
  8. * A typical use case for this would be upcasting (converting) a node id to a
  9. * node entity.
  10. */
  11. class ParamConverterManager implements ParamConverterManagerInterface {
  12. /**
  13. * Array of loaded converter services keyed by their ids.
  14. *
  15. * @var array
  16. */
  17. protected $converters = [];
  18. /**
  19. * {@inheritdoc}
  20. */
  21. public function addConverter(ParamConverterInterface $param_converter, $id) {
  22. $this->converters[$id] = $param_converter;
  23. return $this;
  24. }
  25. /**
  26. * {@inheritdoc}
  27. */
  28. public function getConverter($converter) {
  29. if (isset($this->converters[$converter])) {
  30. return $this->converters[$converter];
  31. }
  32. else {
  33. throw new \InvalidArgumentException(sprintf('No converter has been registered for %s', $converter));
  34. }
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function setRouteParameterConverters(RouteCollection $routes) {
  40. foreach ($routes->all() as $route) {
  41. if (!$parameters = $route->getOption('parameters')) {
  42. // Continue with the next route if no parameters have been defined.
  43. continue;
  44. }
  45. // Loop over all defined parameters and look up the right converter.
  46. foreach ($parameters as $name => &$definition) {
  47. if (isset($definition['converter'])) {
  48. // Skip parameters that already have a manually set converter.
  49. continue;
  50. }
  51. foreach (array_keys($this->converters) as $converter) {
  52. if ($this->getConverter($converter)->applies($definition, $name, $route)) {
  53. $definition['converter'] = $converter;
  54. break;
  55. }
  56. }
  57. }
  58. // Override the parameters array.
  59. $route->setOption('parameters', $parameters);
  60. }
  61. }
  62. /**
  63. * {@inheritdoc}
  64. */
  65. public function convert(array $defaults) {
  66. /** @var $route \Symfony\Component\Routing\Route */
  67. $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
  68. // Skip this enhancer if there are no parameter definitions.
  69. if (!$parameters = $route->getOption('parameters')) {
  70. return $defaults;
  71. }
  72. // Invoke the registered converter for each parameter.
  73. foreach ($parameters as $name => $definition) {
  74. if (!isset($defaults[$name])) {
  75. // Do not try to convert anything that is already set to NULL.
  76. continue;
  77. }
  78. if (!isset($definition['converter'])) {
  79. // Continue if no converter has been specified.
  80. continue;
  81. }
  82. // If a converter returns NULL it means that the parameter could not be
  83. // converted.
  84. $value = $defaults[$name];
  85. $defaults[$name] = $this->getConverter($definition['converter'])->convert($value, $definition, $name, $defaults);
  86. if (!isset($defaults[$name])) {
  87. $message = 'The "%s" parameter was not converted for the path "%s" (route name: "%s")';
  88. $route_name = $defaults[RouteObjectInterface::ROUTE_NAME];
  89. throw new ParamNotConvertedException(sprintf($message, $name, $route->getPath(), $route_name), 0, NULL, $route_name, [$name => $value]);
  90. }
  91. }
  92. return $defaults;
  93. }
  94. }