RoutingExtension.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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\Bridge\Twig\Extension;
  11. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  12. use Twig\Extension\AbstractExtension;
  13. use Twig\Node\Expression\ArrayExpression;
  14. use Twig\Node\Expression\ConstantExpression;
  15. use Twig\Node\Node;
  16. use Twig\TwigFunction;
  17. /**
  18. * Provides integration of the Routing component with Twig.
  19. *
  20. * @author Fabien Potencier <fabien@symfony.com>
  21. */
  22. class RoutingExtension extends AbstractExtension
  23. {
  24. private $generator;
  25. public function __construct(UrlGeneratorInterface $generator)
  26. {
  27. $this->generator = $generator;
  28. }
  29. /**
  30. * Returns a list of functions to add to the existing list.
  31. *
  32. * @return array An array of functions
  33. */
  34. public function getFunctions()
  35. {
  36. return array(
  37. new TwigFunction('url', array($this, 'getUrl'), array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
  38. new TwigFunction('path', array($this, 'getPath'), array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
  39. );
  40. }
  41. /**
  42. * @param string $name
  43. * @param array $parameters
  44. * @param bool $relative
  45. *
  46. * @return string
  47. */
  48. public function getPath($name, $parameters = array(), $relative = false)
  49. {
  50. return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
  51. }
  52. /**
  53. * @param string $name
  54. * @param array $parameters
  55. * @param bool $schemeRelative
  56. *
  57. * @return string
  58. */
  59. public function getUrl($name, $parameters = array(), $schemeRelative = false)
  60. {
  61. return $this->generator->generate($name, $parameters, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL);
  62. }
  63. /**
  64. * Determines at compile time whether the generated URL will be safe and thus
  65. * saving the unneeded automatic escaping for performance reasons.
  66. *
  67. * The URL generation process percent encodes non-alphanumeric characters. So there is no risk
  68. * that malicious/invalid characters are part of the URL. The only character within an URL that
  69. * must be escaped in html is the ampersand ("&") which separates query params. So we cannot mark
  70. * the URL generation as always safe, but only when we are sure there won't be multiple query
  71. * params. This is the case when there are none or only one constant parameter given.
  72. * E.g. we know beforehand this will be safe:
  73. * - path('route')
  74. * - path('route', {'param': 'value'})
  75. * But the following may not:
  76. * - path('route', var)
  77. * - path('route', {'param': ['val1', 'val2'] }) // a sub-array
  78. * - path('route', {'param1': 'value1', 'param2': 'value2'})
  79. * If param1 and param2 reference placeholder in the route, it would still be safe. But we don't know.
  80. *
  81. * @param Node $argsNode The arguments of the path/url function
  82. *
  83. * @return array An array with the contexts the URL is safe
  84. *
  85. * To be made @final in 3.4, and the type-hint be changed to "\Twig\Node\Node" in 4.0.
  86. */
  87. public function isUrlGenerationSafe(\Twig_Node $argsNode)
  88. {
  89. // support named arguments
  90. $paramsNode = $argsNode->hasNode('parameters') ? $argsNode->getNode('parameters') : (
  91. $argsNode->hasNode(1) ? $argsNode->getNode(1) : null
  92. );
  93. if (null === $paramsNode || $paramsNode instanceof ArrayExpression && count($paramsNode) <= 2 &&
  94. (!$paramsNode->hasNode(1) || $paramsNode->getNode(1) instanceof ConstantExpression)
  95. ) {
  96. return array('html');
  97. }
  98. return array();
  99. }
  100. /**
  101. * {@inheritdoc}
  102. */
  103. public function getName()
  104. {
  105. return 'routing';
  106. }
  107. }