Skip to content

Commit 5c809d8

Browse files
committed
[TwigBundle] added support for Twig namespaced paths (Twig 1.10)
In a template, you can now use native Twig template names, instead of the Symfony ones: Before (still works): {% extends "AcmeDemoBundle::layout.html.twig" %} {% include "AcmeDemoBundle:Foo:bar.html.twig" %} After: {% extends "@AcmeDemo/layout.html.twig" %} {% include "@AcmeDemo/Foo/bar.html.twig" %} Using native template names is also faster. The only drawback is that the new notation looks similar to the way we locate resources in Symfony, which would be @AcmeDemoBundle/Resources/views/Foo/bar.html.twig. We could have used the same notation, but it is rather verbose (and by the way, using this notation did not work anyway in templates).
1 parent 0bfa86c commit 5c809d8

File tree

12 files changed

+178
-52
lines changed

12 files changed

+178
-52
lines changed

src/Symfony/Bundle/TwigBundle/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
2.2.0
5+
-----
6+
7+
* added automatic registration of namespaced paths for registered bundles
8+
* added support for namespaced paths
9+
410
2.1.0
511
-----
612

src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,29 @@ private function addTwigOptions(ArrayNodeDefinition $rootNode)
126126
->scalarNode('auto_reload')->end()
127127
->scalarNode('optimizations')->end()
128128
->arrayNode('paths')
129+
->beforeNormalization()
130+
->always()
131+
->then(function ($paths) {
132+
$normalized = array();
133+
foreach ($paths as $path => $namespace) {
134+
if (is_array($namespace)) {
135+
// xml
136+
$path = $namespace['value'];
137+
$namespace = $namespace['namespace'];
138+
}
139+
140+
// path within the default namespace
141+
if (ctype_digit((string) $path)) {
142+
$path = $namespace;
143+
$namespace = null;
144+
}
145+
146+
$normalized[$path] = $namespace;
147+
}
148+
149+
return $normalized;
150+
})
151+
->end()
129152
->prototype('variable')->end()
130153
->end()
131154
->end()

src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,33 @@ public function load(array $configs, ContainerBuilder $container)
6060
$reflClass = new \ReflectionClass('Symfony\Bridge\Twig\Extension\FormExtension');
6161
$container->getDefinition('twig.loader')->addMethodCall('addPath', array(dirname(dirname($reflClass->getFileName())).'/Resources/views/Form'));
6262

63-
if (!empty($config['paths'])) {
64-
foreach ($config['paths'] as $path) {
65-
$container->getDefinition('twig.loader')->addMethodCall('addPath', array($path));
63+
$twigLoaderDefinition = $container->getDefinition('twig.loader');
64+
65+
// register user-configured paths
66+
foreach ($config['paths'] as $path => $namespace) {
67+
if (!$namespace) {
68+
$twigLoaderDefinition->addMethodCall('addPath', array($path));
69+
} else {
70+
$twigLoaderDefinition->addMethodCall('addPath', array($path, $namespace));
6671
}
6772
}
6873

74+
// register bundles as Twig namespaces
75+
foreach ($container->getParameter('kernel.bundles') as $bundle => $class) {
76+
if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/'.$bundle.'/views')) {
77+
$this->addTwigPath($twigLoaderDefinition, $dir, $bundle);
78+
}
79+
80+
$reflection = new \ReflectionClass($class);
81+
if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/views')) {
82+
$this->addTwigPath($twigLoaderDefinition, $dir, $bundle);
83+
}
84+
}
85+
86+
if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/views')) {
87+
$twigLoaderDefinition->addMethodCall('addPath', array($dir));
88+
}
89+
6990
if (!empty($config['globals'])) {
7091
$def = $container->getDefinition('twig');
7192
foreach ($config['globals'] as $key => $global) {
@@ -108,6 +129,15 @@ public function load(array $configs, ContainerBuilder $container)
108129
));
109130
}
110131

132+
private function addTwigPath($twigLoaderDefinition, $dir, $bundle)
133+
{
134+
$name = $bundle;
135+
if ('Bundle' === substr($name, -6)) {
136+
$name = substr($name, 0, -6);
137+
}
138+
$twigLoaderDefinition->addMethodCall('addPath', array($dir, $name));
139+
}
140+
111141
/**
112142
* Returns the base path for the XSD files.
113143
*

src/Symfony/Bundle/TwigBundle/Loader/FilesystemLoader.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,19 @@ protected function findTemplate($template)
6464
$file = null;
6565
$previous = null;
6666
try {
67-
$template = $this->parser->parse($template);
68-
try {
69-
$file = $this->locator->locate($template);
70-
} catch (\InvalidArgumentException $e) {
71-
$previous = $e;
72-
}
73-
} catch (\Exception $e) {
67+
$file = parent::findTemplate($template);
68+
} catch (\Twig_Error_Loader $e) {
69+
$previous = $e;
70+
71+
// for BC
7472
try {
75-
$file = parent::findTemplate($template);
76-
} catch (\Twig_Error_Loader $e) {
73+
$template = $this->parser->parse($template);
74+
try {
75+
$file = $this->locator->locate($template);
76+
} catch (\InvalidArgumentException $e) {
77+
$previous = $e;
78+
}
79+
} catch (\Exception $e) {
7780
$previous = $e;
7881
}
7982
}

src/Symfony/Bundle/TwigBundle/Resources/config/schema/twig-1.0.xsd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<xsd:sequence>
1212
<xsd:element name="form" type="form" minOccurs="0" maxOccurs="1" />
1313
<xsd:element name="global" type="global" minOccurs="0" maxOccurs="unbounded" />
14-
<xsd:element name="path" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
14+
<xsd:element name="path" type="path" minOccurs="0" maxOccurs="unbounded" />
1515
</xsd:sequence>
1616

1717
<xsd:attribute name="auto-reload" type="xsd:string" />
@@ -30,6 +30,10 @@
3030
</xsd:choice>
3131
</xsd:complexType>
3232

33+
<xsd:complexType name="path" mixed="true">
34+
<xsd:attribute name="namespace" type="xsd:string" />
35+
</xsd:complexType>
36+
3337
<xsd:complexType name="global" mixed="true">
3438
<xsd:attribute name="key" type="xsd:string" use="required" />
3539
<xsd:attribute name="type" type="global_type" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is a layout
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is a layout

src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,10 @@
1818
'charset' => 'ISO-8859-1',
1919
'debug' => true,
2020
'strict_variables' => true,
21-
'paths' => array('path1', 'path2'),
21+
'paths' => array(
22+
'path1',
23+
'path2',
24+
'namespaced_path1' => 'namespace',
25+
'namespaced_path2' => 'namespace',
26+
),
2227
));

src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@
1414
<twig:global key="pi">3.14</twig:global>
1515
<twig:path>path1</twig:path>
1616
<twig:path>path2</twig:path>
17+
<twig:path namespace="namespace">namespaced_path1</twig:path>
18+
<twig:path namespace="namespace">namespaced_path2</twig:path>
1719
</twig:config>
1820
</container>

src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ twig:
1313
charset: ISO-8859-1
1414
debug: true
1515
strict_variables: true
16-
paths: [path1, path2]
16+
paths:
17+
path1: ''
18+
path2: ''
19+
namespaced_path1: namespace
20+
namespaced_path2: namespace

0 commit comments

Comments
 (0)