Skip to content

Commit 4833acf

Browse files
committed
Merge remote branch 'opensky/TwigExtension-configuration'
* opensky/TwigExtension-configuration: [TwigBundle] Refactored TwigExtension class and implemented configuration tree
2 parents f849353 + f0d2ce7 commit 4833acf

File tree

8 files changed

+344
-141
lines changed

8 files changed

+344
-141
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\TwigBundle\DependencyInjection;
4+
5+
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
6+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
7+
8+
/**
9+
* TwigExtension configuration structure.
10+
*
11+
* @author Jeremy Mikola <jmikola@gmail.com>
12+
*/
13+
class Configuration
14+
{
15+
/**
16+
* Generates the configuration tree.
17+
*
18+
* @return \Symfony\Component\Config\Definition\NodeInterface
19+
*/
20+
public function getConfigTree()
21+
{
22+
$treeBuilder = new TreeBuilder();
23+
$rootNode = $treeBuilder->root('twig', 'array');
24+
25+
$rootNode
26+
->scalarNode('cache_warmer')->end()
27+
;
28+
29+
$this->addExtensionsSection($rootNode);
30+
$this->addFormSection($rootNode);
31+
$this->addGlobalsSection($rootNode);
32+
$this->addTwigOptions($rootNode);
33+
34+
return $treeBuilder->buildTree();
35+
}
36+
37+
private function addExtensionsSection(NodeBuilder $rootNode)
38+
{
39+
$rootNode
40+
->fixXmlConfig('extension')
41+
->arrayNode('extensions')
42+
->prototype('scalar')
43+
->beforeNormalization()
44+
->ifTrue(function($v) { return is_array($v) && isset($v['id']); })
45+
->then(function($v){ return $v['id']; })
46+
->end()
47+
->end()
48+
->end()
49+
;
50+
}
51+
52+
private function addFormSection(NodeBuilder $rootNode)
53+
{
54+
$rootNode
55+
->arrayNode('form')
56+
->addDefaultsIfNotSet()
57+
->fixXmlConfig('resource')
58+
->arrayNode('resources')
59+
->addDefaultsIfNotSet()
60+
->defaultValue(array('TwigBundle::form.html.twig'))
61+
->validate()
62+
->always()
63+
->then(function($v){
64+
return array_merge(array('TwigBundle::form.html.twig'), $v);
65+
})
66+
->end()
67+
->prototype('scalar')->end()
68+
->end()
69+
->end()
70+
;
71+
}
72+
73+
private function addGlobalsSection(NodeBuilder $rootNode)
74+
{
75+
$rootNode
76+
->fixXmlConfig('global')
77+
->arrayNode('globals')
78+
->useAttributeAsKey('key')
79+
->prototype('array')
80+
->beforeNormalization()
81+
->ifTrue(function($v){ return is_scalar($v); })
82+
->then(function($v){
83+
return ('@' === substr($v, 0, 1))
84+
? array('id' => substr($v, 1), 'type' => 'service')
85+
: array('value' => $v);
86+
})
87+
->end()
88+
->scalarNode('id')->end()
89+
->scalarNode('type')
90+
->validate()
91+
->ifNotInArray(array('service'))
92+
->thenInvalid('The %s type is not supported')
93+
->end()
94+
->end()
95+
->scalarNode('value')->end()
96+
->end()
97+
->end()
98+
;
99+
}
100+
101+
private function addTwigOptions(NodeBuilder $rootNode)
102+
{
103+
$rootNode
104+
->scalarNode('autoescape')->end()
105+
->scalarNode('base_template_class')->end()
106+
->scalarNode('cache')
107+
->addDefaultsIfNotSet()
108+
->defaultValue('%kernel.cache_dir%/twig')
109+
->end()
110+
->scalarNode('charset')
111+
->addDefaultsIfNotSet()
112+
->defaultValue('%kernel.charset%')
113+
->end()
114+
->scalarNode('debug')
115+
->addDefaultsIfNotSet()
116+
->defaultValue('%kernel.debug%')
117+
->end()
118+
->scalarNode('strict_variables')->end()
119+
->scalarNode('auto_reload')->end()
120+
;
121+
}
122+
}

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

Lines changed: 43 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -11,113 +11,81 @@
1111

1212
namespace Symfony\Bundle\TwigBundle\DependencyInjection;
1313

14-
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
15-
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
14+
use Symfony\Component\Config\FileLocator;
15+
use Symfony\Component\Config\Definition\Processor;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
1717
use Symfony\Component\DependencyInjection\Reference;
18-
use Symfony\Component\Config\FileLocator;
18+
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
19+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
1920

2021
/**
2122
* TwigExtension.
2223
*
2324
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
25+
* @author Jeremy Mikola <jmikola@gmail.com>
2426
*/
2527
class TwigExtension extends Extension
2628
{
29+
/**
30+
* Responds to the twig configuration parameter.
31+
*
32+
* @param array $configs
33+
* @param ContainerBuilder $container
34+
*/
2735
public function load(array $configs, ContainerBuilder $container)
2836
{
2937
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
3038
$loader->load('twig.xml');
3139

32-
$this->addClassesToCompile(array(
33-
'Twig_Environment',
34-
'Twig_ExtensionInterface',
35-
'Twig_Extension',
36-
'Twig_Extension_Core',
37-
'Twig_Extension_Escaper',
38-
'Twig_Extension_Optimizer',
39-
'Twig_LoaderInterface',
40-
'Twig_Markup',
41-
'Twig_TemplateInterface',
42-
'Twig_Template',
43-
));
40+
$processor = new Processor();
41+
$configuration = new Configuration();
4442

45-
foreach ($configs as $config) {
46-
$this->doConfigLoad($config, $container);
47-
}
48-
}
43+
$config = $processor->process($configuration->getConfigTree(), $configs);
4944

50-
/**
51-
* Loads the Twig configuration.
52-
*
53-
* @param array $config An array of configuration settings
54-
* @param ContainerBuilder $container A ContainerBuilder instance
55-
*/
56-
protected function doConfigLoad(array $config, ContainerBuilder $container)
57-
{
58-
// form resources
59-
foreach (array('resources', 'resource') as $key) {
60-
if (isset($config['form'][$key])) {
61-
$resources = (array) $config['form'][$key];
62-
$container->setParameter('twig.form.resources', array_merge($container->getParameter('twig.form.resources'), $resources));
63-
unset($config['form'][$key]);
64-
}
65-
}
45+
$container->setParameter('twig.form.resources', $config['form']['resources']);
6646

67-
// globals
68-
$def = $container->getDefinition('twig');
69-
$globals = $this->normalizeConfig($config, 'global');
70-
if (isset($globals[0])) {
71-
foreach ($globals as $global) {
47+
if (!empty($config['globals'])) {
48+
$def = $container->getDefinition('twig');
49+
foreach ($config['globals'] as $key => $global) {
7250
if (isset($global['type']) && 'service' === $global['type']) {
73-
$def->addMethodCall('addGlobal', array($global['key'], new Reference($global['id'])));
74-
} elseif (isset($global['value'])) {
75-
$def->addMethodCall('addGlobal', array($global['key'], $global['value']));
76-
} else {
77-
throw new \InvalidArgumentException(sprintf('Unable to understand global configuration (%s).', var_export($global, true)));
78-
}
79-
}
80-
} else {
81-
foreach ($globals as $key => $value) {
82-
if (is_string($value) && '@' === substr($value, 0, 1)) {
83-
$def->addMethodCall('addGlobal', array($key, new Reference(substr($value, 1))));
51+
$def->addMethodCall('addGlobal', array($key, new Reference($global['id'])));
8452
} else {
85-
$def->addMethodCall('addGlobal', array($key, $value));
53+
$def->addMethodCall('addGlobal', array($key, $global['value']));
8654
}
8755
}
8856
}
89-
unset($config['globals'], $config['global']);
9057

91-
// extensions
92-
$extensions = $this->normalizeConfig($config, 'extension');
93-
if (isset($extensions[0]) && is_array($extensions[0])) {
94-
foreach ($extensions as $extension) {
95-
$container->getDefinition($extension['id'])->addTag('twig.extension');
96-
}
97-
} else {
98-
foreach ($extensions as $id) {
58+
if (!empty($config['extensions'])) {
59+
foreach ($config['extensions'] as $id) {
9960
$container->getDefinition($id)->addTag('twig.extension');
10061
}
10162
}
102-
unset($config['extensions'], $config['extension']);
10363

104-
// convert - to _
105-
foreach ($config as $key => $value) {
106-
if (false !== strpos($key, '-')) {
107-
unset($config[$key]);
108-
$config[str_replace('-', '_', $key)] = $value;
109-
}
64+
if (!empty($config['cache_warmer'])) {
65+
$container->getDefinition('templating.cache_warmer.templates_cache')->addTag('kernel.cache_warmer');
11066
}
11167

112-
if (isset($config['cache-warmer'])) {
113-
$config['cache_warmer'] = $config['cache-warmer'];
114-
}
68+
unset(
69+
$config['form'],
70+
$config['globals'],
71+
$config['extensions'],
72+
$config['cache_warmer']
73+
);
11574

116-
if (isset($config['cache_warmer']) && $config['cache_warmer']) {
117-
$container->getDefinition('templating.cache_warmer.templates_cache')->addTag('kernel.cache_warmer');
118-
}
75+
$container->setParameter('twig.options', $config);
11976

120-
$container->setParameter('twig.options', array_replace($container->getParameter('twig.options'), $config));
77+
$this->addClassesToCompile(array(
78+
'Twig_Environment',
79+
'Twig_ExtensionInterface',
80+
'Twig_Extension',
81+
'Twig_Extension_Core',
82+
'Twig_Extension_Escaper',
83+
'Twig_Extension_Optimizer',
84+
'Twig_LoaderInterface',
85+
'Twig_Markup',
86+
'Twig_TemplateInterface',
87+
'Twig_Template',
88+
));
12189
}
12290

12391
/**

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
<xsd:element name="extension" type="extension" minOccurs="0" maxOccurs="unbounded" />
1515
</xsd:sequence>
1616

17-
<xsd:attribute name="charset" type="xsd:string" />
18-
<xsd:attribute name="debug" type="xsd:string" />
19-
<xsd:attribute name="cache" type="xsd:string" />
20-
<xsd:attribute name="strict-variables" type="xsd:string" />
21-
<xsd:attribute name="auto-reload" type="xsd:string" />
17+
<xsd:attribute name="auto-reload" type="xsd:boolean" />
18+
<xsd:attribute name="autoescape" type="xsd:boolean" />
2219
<xsd:attribute name="base-template-class" type="xsd:string" />
23-
<xsd:attribute name="autoescape" type="xsd:string" />
20+
<xsd:attribute name="cache" type="xsd:string" />
2421
<xsd:attribute name="cache-warmer" type="cache_warmer" />
22+
<xsd:attribute name="charset" type="xsd:string" />
23+
<xsd:attribute name="debug" type="xsd:boolean" />
24+
<xsd:attribute name="strict-variables" type="xsd:boolean" />
2525
</xsd:complexType>
2626

2727
<xsd:complexType name="form">
@@ -32,7 +32,7 @@
3232

3333
<xsd:complexType name="global" mixed="true">
3434
<xsd:attribute name="key" type="xsd:string" use="required" />
35-
<xsd:attribute name="type" type="xsd:string" />
35+
<xsd:attribute name="type" type="global_type" />
3636
<xsd:attribute name="id" type="xsd:string" />
3737
</xsd:complexType>
3838

@@ -47,4 +47,10 @@
4747
<xsd:enumeration value="full" />
4848
</xsd:restriction>
4949
</xsd:simpleType>
50+
51+
<xsd:simpleType name="global_type">
52+
<xsd:restriction base="xsd:string">
53+
<xsd:enumeration value="service" />
54+
</xsd:restriction>
55+
</xsd:simpleType>
5056
</xsd:schema>

src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,8 @@
66

77
<parameters>
88
<parameter key="twig.class">Twig_Environment</parameter>
9-
<parameter key="twig.options" type="collection">
10-
<parameter key="charset">%kernel.charset%</parameter>
11-
<parameter key="debug">%kernel.debug%</parameter>
12-
<parameter key="cache">%kernel.cache_dir%/twig</parameter>
13-
</parameter>
149
<parameter key="twig.loader.class">Symfony\Bundle\TwigBundle\Loader\FilesystemLoader</parameter>
1510
<parameter key="twig.globals.class">Symfony\Bundle\TwigBundle\GlobalVariables</parameter>
16-
<parameter key="twig.form.resources" type="collection">
17-
<parameter>TwigBundle::form.html.twig</parameter>
18-
</parameter>
1911
<parameter key="templating.engine.twig.class">Symfony\Bundle\TwigBundle\TwigEngine</parameter>
2012
<parameter key="templating.cache_warmer.templates_cache.class">Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer</parameter>
2113
</parameters>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
$container->loadFromExtension('twig', array(
4+
'form' => array(
5+
'resources' => array(
6+
'MyBundle::form.html.twig',
7+
)
8+
),
9+
'extensions' => array(
10+
'twig.extension.debug',
11+
'twig.extension.text',
12+
),
13+
'globals' => array(
14+
'foo' => '@bar',
15+
'pi' => 3.14,
16+
),
17+
'auto_reload' => true,
18+
'autoescape' => true,
19+
'base_template_class' => 'stdClass',
20+
'cache' => '/tmp',
21+
'cache_warmer' => true,
22+
'charset' => 'ISO-8859-1',
23+
'debug' => true,
24+
'strict_variables' => true,
25+
));
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://www.symfony-project.org/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:twig="http://www.symfony-project.org/schema/dic/twig"
6+
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd
7+
http://www.symfony-project.org/schema/dic/twig http://www.symfony-project.org/schema/dic/twig/twig-1.0.xsd">
8+
9+
<twig:config auto-reload="true" autoescape="true" base-template-class="stdClass" cache="/tmp" cache-warmer="true" charset="ISO-8859-1" debug="true" strict-variables="true">
10+
<twig:form>
11+
<twig:resource>MyBundle::form.html.twig</twig:resource>
12+
</twig:form>
13+
<twig:global key="foo" id="bar" type="service" />
14+
<twig:global key="pi">3.14</twig:global>
15+
<twig:extension id="twig.extension.debug" />
16+
<twig:extension id="twig.extension.text" />
17+
</twig:config>
18+
</container>

0 commit comments

Comments
 (0)