1: <?php
2: /**
3: * This file is part of the Autarky package.
4: *
5: * (c) Andreas Lutro <anlutro@gmail.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:
11: namespace Autarky\TwigTemplating\Extensions;
12:
13: use Twig_Extension;
14: use Twig_SimpleFunction;
15:
16: use Autarky\Routing\UrlGenerator;
17:
18: /**
19: * Extension for url generating functionality in templates.
20: *
21: * Parts shamelessly stolen from Symfony 2.
22: */
23: class UrlGenerationExtension extends Twig_Extension
24: {
25: /**
26: * @var UrlGenerator
27: */
28: protected $urlGenerator;
29:
30: /**
31: * Constructor.
32: *
33: * @param UrlGenerator $urlGenerator
34: */
35: public function __construct(UrlGenerator $urlGenerator)
36: {
37: $this->urlGenerator = $urlGenerator;
38: }
39:
40: /**
41: * {@inheritdoc}
42: */
43: public function getFunctions()
44: {
45: return array(
46: new Twig_SimpleFunction('url', [$this, 'getUrl'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
47: new Twig_SimpleFunction('asset', [$this, 'getAsset']),
48: );
49: }
50:
51: /**
52: * Implementation of the `url(route)` twig function.
53: *
54: * @param string $name Route name
55: * @param array $parameters Route parameters
56: * @param boolean $relative Whether to generate an absolute or relative URL.
57: *
58: * @return string
59: */
60: public function getUrl($name, $parameters = array(), $relative = false)
61: {
62: return $this->urlGenerator->getRouteUrl($name, $parameters, $relative);
63: }
64:
65: /**
66: * Implementation of the `asset(path)` twig function.
67: *
68: * @param string $path Path to the asset, relative to the webroot or asset root.
69: * @param boolean $relative Whether to generate an absolute or relative URL.
70: *
71: * @return [type] [description]
72: */
73: public function getAsset($path, $relative = false)
74: {
75: return $this->urlGenerator->getAssetUrl($path, $relative);
76: }
77:
78: /**
79: * Determines at compile time whether the generated URL will be safe and thus
80: * saving the unneeded automatic escaping for performance reasons.
81: *
82: * The URL generation process percent encodes non-alphanumeric characters. So there is no risk
83: * that malicious/invalid characters are part of the URL. The only character within an URL that
84: * must be escaped in html is the ampersand ("&") which separates query params. So we cannot mark
85: * the URL generation as always safe, but only when we are sure there won't be multiple query
86: * params. This is the case when there are none or only one constant parameter given.
87: * E.g. we know beforehand this will be safe:
88: * - path('route')
89: * - path('route', {'param': 'value'})
90: * But the following may not:
91: * - path('route', var)
92: * - path('route', {'param': ['val1', 'val2'] }) // a sub-array
93: * - path('route', {'param1': 'value1', 'param2': 'value2'})
94: * If param1 and param2 reference placeholder in the route, it would still be safe. But we don't know.
95: *
96: * @param \Twig_Node $argsNode The arguments of the path/url function
97: *
98: * @return array An array with the contexts the URL is safe
99: *
100: * @author Fabien Potencier <fabien@symfony.com>
101: */
102: public function isUrlGenerationSafe(\Twig_Node $argsNode)
103: {
104: // support named arguments
105: $paramsNode = $argsNode->hasNode('parameters') ? $argsNode->getNode('parameters') : (
106: $argsNode->hasNode(1) ? $argsNode->getNode(1) : null
107: );
108:
109: if (null === $paramsNode || $paramsNode instanceof \Twig_Node_Expression_Array && count($paramsNode) <= 2 &&
110: (!$paramsNode->hasNode(1) || $paramsNode->getNode(1) instanceof \Twig_Node_Expression_Constant)
111: ) {
112: return array('html');
113: }
114:
115: return array();
116: }
117:
118: /**
119: * {@inheritdoc}
120: */
121: public function getName()
122: {
123: return 'routing';
124: }
125: }
126: