Configuration.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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\Bundle\TwigBundle\DependencyInjection;
  11. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  12. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  13. use Symfony\Component\Config\Definition\ConfigurationInterface;
  14. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  15. /**
  16. * TwigExtension configuration structure.
  17. *
  18. * @author Jeremy Mikola <jmikola@gmail.com>
  19. */
  20. class Configuration implements ConfigurationInterface
  21. {
  22. /**
  23. * Generates the configuration tree builder.
  24. *
  25. * @return TreeBuilder The tree builder
  26. */
  27. public function getConfigTreeBuilder()
  28. {
  29. $treeBuilder = new TreeBuilder('twig');
  30. $rootNode = $treeBuilder->getRootNode();
  31. $rootNode->beforeNormalization()
  32. ->ifTrue(function ($v) { return \is_array($v) && \array_key_exists('exception_controller', $v); })
  33. ->then(function ($v) {
  34. if (isset($v['exception_controller'])) {
  35. throw new InvalidConfigurationException('Option "exception_controller" under "twig" must be null or unset, use "error_controller" under "framework" instead.');
  36. }
  37. unset($v['exception_controller']);
  38. return $v;
  39. })
  40. ->end();
  41. $this->addFormThemesSection($rootNode);
  42. $this->addGlobalsSection($rootNode);
  43. $this->addTwigOptions($rootNode);
  44. $this->addTwigFormatOptions($rootNode);
  45. return $treeBuilder;
  46. }
  47. private function addFormThemesSection(ArrayNodeDefinition $rootNode)
  48. {
  49. $rootNode
  50. ->fixXmlConfig('form_theme')
  51. ->children()
  52. ->arrayNode('form_themes')
  53. ->addDefaultChildrenIfNoneSet()
  54. ->prototype('scalar')->defaultValue('form_div_layout.html.twig')->end()
  55. ->example(['@My/form.html.twig'])
  56. ->validate()
  57. ->ifTrue(function ($v) { return !\in_array('form_div_layout.html.twig', $v); })
  58. ->then(function ($v) {
  59. return array_merge(['form_div_layout.html.twig'], $v);
  60. })
  61. ->end()
  62. ->end()
  63. ->end()
  64. ;
  65. }
  66. private function addGlobalsSection(ArrayNodeDefinition $rootNode)
  67. {
  68. $rootNode
  69. ->fixXmlConfig('global')
  70. ->children()
  71. ->arrayNode('globals')
  72. ->normalizeKeys(false)
  73. ->useAttributeAsKey('key')
  74. ->example(['foo' => '@bar', 'pi' => 3.14])
  75. ->prototype('array')
  76. ->normalizeKeys(false)
  77. ->beforeNormalization()
  78. ->ifTrue(function ($v) { return \is_string($v) && 0 === strpos($v, '@'); })
  79. ->then(function ($v) {
  80. if (0 === strpos($v, '@@')) {
  81. return substr($v, 1);
  82. }
  83. return ['id' => substr($v, 1), 'type' => 'service'];
  84. })
  85. ->end()
  86. ->beforeNormalization()
  87. ->ifTrue(function ($v) {
  88. if (\is_array($v)) {
  89. $keys = array_keys($v);
  90. sort($keys);
  91. return $keys !== ['id', 'type'] && $keys !== ['value'];
  92. }
  93. return true;
  94. })
  95. ->then(function ($v) { return ['value' => $v]; })
  96. ->end()
  97. ->children()
  98. ->scalarNode('id')->end()
  99. ->scalarNode('type')
  100. ->validate()
  101. ->ifNotInArray(['service'])
  102. ->thenInvalid('The %s type is not supported')
  103. ->end()
  104. ->end()
  105. ->variableNode('value')->end()
  106. ->end()
  107. ->end()
  108. ->end()
  109. ->end()
  110. ;
  111. }
  112. private function addTwigOptions(ArrayNodeDefinition $rootNode)
  113. {
  114. $rootNode
  115. ->fixXmlConfig('path')
  116. ->children()
  117. ->variableNode('autoescape')->defaultValue('name')->end()
  118. ->scalarNode('autoescape_service')->defaultNull()->end()
  119. ->scalarNode('autoescape_service_method')->defaultNull()->end()
  120. ->scalarNode('base_template_class')->example('Twig\Template')->cannotBeEmpty()->end()
  121. ->scalarNode('cache')->defaultValue('%kernel.cache_dir%/twig')->end()
  122. ->scalarNode('charset')->defaultValue('%kernel.charset%')->end()
  123. ->booleanNode('debug')->defaultValue('%kernel.debug%')->end()
  124. ->booleanNode('strict_variables')->defaultValue('%kernel.debug%')->end()
  125. ->scalarNode('auto_reload')->end()
  126. ->integerNode('optimizations')->min(-1)->end()
  127. ->scalarNode('default_path')
  128. ->info('The default path used to load templates')
  129. ->defaultValue('%kernel.project_dir%/templates')
  130. ->end()
  131. ->arrayNode('paths')
  132. ->normalizeKeys(false)
  133. ->useAttributeAsKey('paths')
  134. ->beforeNormalization()
  135. ->always()
  136. ->then(function ($paths) {
  137. $normalized = [];
  138. foreach ($paths as $path => $namespace) {
  139. if (\is_array($namespace)) {
  140. // xml
  141. $path = $namespace['value'];
  142. $namespace = $namespace['namespace'];
  143. }
  144. // path within the default namespace
  145. if (ctype_digit((string) $path)) {
  146. $path = $namespace;
  147. $namespace = null;
  148. }
  149. $normalized[$path] = $namespace;
  150. }
  151. return $normalized;
  152. })
  153. ->end()
  154. ->prototype('variable')->end()
  155. ->end()
  156. ->end()
  157. ;
  158. }
  159. private function addTwigFormatOptions(ArrayNodeDefinition $rootNode)
  160. {
  161. $rootNode
  162. ->children()
  163. ->arrayNode('date')
  164. ->info('The default format options used by the date filter')
  165. ->addDefaultsIfNotSet()
  166. ->children()
  167. ->scalarNode('format')->defaultValue('F j, Y H:i')->end()
  168. ->scalarNode('interval_format')->defaultValue('%d days')->end()
  169. ->scalarNode('timezone')
  170. ->info('The timezone used when formatting dates, when set to null, the timezone returned by date_default_timezone_get() is used')
  171. ->defaultNull()
  172. ->end()
  173. ->end()
  174. ->end()
  175. ->arrayNode('number_format')
  176. ->info('The default format options for the number_format filter')
  177. ->addDefaultsIfNotSet()
  178. ->children()
  179. ->integerNode('decimals')->defaultValue(0)->end()
  180. ->scalarNode('decimal_point')->defaultValue('.')->end()
  181. ->scalarNode('thousands_separator')->defaultValue(',')->end()
  182. ->end()
  183. ->end()
  184. ->end()
  185. ;
  186. }
  187. }