TwigExtensionTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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\Tests\DependencyInjection;
  11. use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\RuntimeLoaderPass;
  12. use Symfony\Bundle\TwigBundle\DependencyInjection\TwigExtension;
  13. use Symfony\Bundle\TwigBundle\Tests\TestCase;
  14. use Symfony\Component\Config\FileLocator;
  15. use Symfony\Component\DependencyInjection\Compiler\PassConfig;
  16. use Symfony\Component\DependencyInjection\ContainerBuilder;
  17. use Symfony\Component\DependencyInjection\Reference;
  18. use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
  19. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  20. use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
  21. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  22. class TwigExtensionTest extends TestCase
  23. {
  24. public function testLoadEmptyConfiguration()
  25. {
  26. $container = $this->createContainer();
  27. $container->registerExtension(new TwigExtension());
  28. $container->loadFromExtension('twig', array());
  29. $this->compileContainer($container);
  30. $this->assertEquals('Twig_Environment', $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
  31. $this->assertContains('form_div_layout.html.twig', $container->getParameter('twig.form.resources'), '->load() includes default template for form resources');
  32. // Twig options
  33. $options = $container->getDefinition('twig')->getArgument(1);
  34. $this->assertEquals('%kernel.cache_dir%/twig', $options['cache'], '->load() sets default value for cache option');
  35. $this->assertEquals('%kernel.charset%', $options['charset'], '->load() sets default value for charset option');
  36. $this->assertEquals('%kernel.debug%', $options['debug'], '->load() sets default value for debug option');
  37. }
  38. /**
  39. * @dataProvider getFormats
  40. */
  41. public function testLoadFullConfiguration($format)
  42. {
  43. $container = $this->createContainer();
  44. $container->registerExtension(new TwigExtension());
  45. $this->loadFromFile($container, 'full', $format);
  46. $this->compileContainer($container);
  47. $this->assertEquals('Twig_Environment', $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
  48. // Form resources
  49. $resources = $container->getParameter('twig.form.resources');
  50. $this->assertContains('form_div_layout.html.twig', $resources, '->load() includes default template for form resources');
  51. $this->assertContains('MyBundle::form.html.twig', $resources, '->load() merges new templates into form resources');
  52. // Globals
  53. $calls = $container->getDefinition('twig')->getMethodCalls();
  54. $this->assertEquals('app', $calls[0][1][0], '->load() registers services as Twig globals');
  55. $this->assertEquals(new Reference('twig.app_variable'), $calls[0][1][1]);
  56. $this->assertEquals('foo', $calls[2][1][0], '->load() registers services as Twig globals');
  57. $this->assertEquals(new Reference('bar'), $calls[2][1][1], '->load() registers services as Twig globals');
  58. $this->assertEquals('baz', $calls[3][1][0], '->load() registers variables as Twig globals');
  59. $this->assertEquals('@qux', $calls[3][1][1], '->load() allows escaping of service identifiers');
  60. $this->assertEquals('pi', $calls[4][1][0], '->load() registers variables as Twig globals');
  61. $this->assertEquals(3.14, $calls[4][1][1], '->load() registers variables as Twig globals');
  62. // Yaml and Php specific configs
  63. if (in_array($format, array('yml', 'php'))) {
  64. $this->assertEquals('bad', $calls[5][1][0], '->load() registers variables as Twig globals');
  65. $this->assertEquals(array('key' => 'foo'), $calls[5][1][1], '->load() registers variables as Twig globals');
  66. }
  67. // Twig options
  68. $options = $container->getDefinition('twig')->getArgument(1);
  69. $this->assertTrue($options['auto_reload'], '->load() sets the auto_reload option');
  70. $this->assertTrue($options['autoescape'], '->load() sets the autoescape option');
  71. $this->assertEquals('stdClass', $options['base_template_class'], '->load() sets the base_template_class option');
  72. $this->assertEquals('/tmp', $options['cache'], '->load() sets the cache option');
  73. $this->assertEquals('ISO-8859-1', $options['charset'], '->load() sets the charset option');
  74. $this->assertTrue($options['debug'], '->load() sets the debug option');
  75. $this->assertTrue($options['strict_variables'], '->load() sets the strict_variables option');
  76. }
  77. /**
  78. * @dataProvider getFormats
  79. */
  80. public function testLoadCustomTemplateEscapingGuesserConfiguration($format)
  81. {
  82. $container = $this->createContainer();
  83. $container->registerExtension(new TwigExtension());
  84. $this->loadFromFile($container, 'customTemplateEscapingGuesser', $format);
  85. $this->compileContainer($container);
  86. $options = $container->getDefinition('twig')->getArgument(1);
  87. $this->assertEquals(array(new Reference('my_project.some_bundle.template_escaping_guesser'), 'guess'), $options['autoescape']);
  88. }
  89. /**
  90. * @dataProvider getFormats
  91. */
  92. public function testLoadDefaultTemplateEscapingGuesserConfiguration($format)
  93. {
  94. $container = $this->createContainer();
  95. $container->registerExtension(new TwigExtension());
  96. $this->loadFromFile($container, 'empty', $format);
  97. $this->compileContainer($container);
  98. $options = $container->getDefinition('twig')->getArgument(1);
  99. $this->assertEquals('name', $options['autoescape']);
  100. }
  101. public function testGlobalsWithDifferentTypesAndValues()
  102. {
  103. $globals = array(
  104. 'array' => array(),
  105. 'false' => false,
  106. 'float' => 2.0,
  107. 'integer' => 3,
  108. 'null' => null,
  109. 'object' => new \stdClass(),
  110. 'string' => 'foo',
  111. 'true' => true,
  112. );
  113. $container = $this->createContainer();
  114. $container->registerExtension(new TwigExtension());
  115. $container->loadFromExtension('twig', array('globals' => $globals));
  116. $this->compileContainer($container);
  117. $calls = $container->getDefinition('twig')->getMethodCalls();
  118. foreach (array_slice($calls, 2) as $call) {
  119. list($name, $value) = each($globals);
  120. $this->assertEquals($name, $call[1][0]);
  121. $this->assertSame($value, $call[1][1]);
  122. }
  123. }
  124. /**
  125. * @dataProvider getFormats
  126. */
  127. public function testTwigLoaderPaths($format)
  128. {
  129. $container = $this->createContainer();
  130. $container->registerExtension(new TwigExtension());
  131. $this->loadFromFile($container, 'full', $format);
  132. $this->loadFromFile($container, 'extra', $format);
  133. $this->compileContainer($container);
  134. $def = $container->getDefinition('twig.loader.filesystem');
  135. $paths = array();
  136. foreach ($def->getMethodCalls() as $call) {
  137. if ('addPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
  138. $paths[] = $call[1];
  139. }
  140. }
  141. $this->assertEquals(array(
  142. array('path1'),
  143. array('path2'),
  144. array('namespaced_path1', 'namespace1'),
  145. array('namespaced_path2', 'namespace2'),
  146. array('namespaced_path3', 'namespace3'),
  147. array(__DIR__.'/Fixtures/Resources/TwigBundle/views', 'Twig'),
  148. array(realpath(__DIR__.'/../..').'/Resources/views', 'Twig'),
  149. array(__DIR__.'/Fixtures/Resources/views'),
  150. ), $paths);
  151. }
  152. public function getFormats()
  153. {
  154. return array(
  155. array('php'),
  156. array('yml'),
  157. array('xml'),
  158. );
  159. }
  160. /**
  161. * @dataProvider stopwatchExtensionAvailabilityProvider
  162. */
  163. public function testStopwatchExtensionAvailability($debug, $stopwatchEnabled, $expected)
  164. {
  165. $container = $this->createContainer();
  166. $container->setParameter('kernel.debug', $debug);
  167. if ($stopwatchEnabled) {
  168. $container->register('debug.stopwatch', 'Symfony\Component\Stopwatch\Stopwatch');
  169. }
  170. $container->registerExtension(new TwigExtension());
  171. $container->loadFromExtension('twig', array());
  172. $this->compileContainer($container);
  173. $tokenParsers = $container->get('twig.extension.debug.stopwatch')->getTokenParsers();
  174. $stopwatchIsAvailable = new \ReflectionProperty($tokenParsers[0], 'stopwatchIsAvailable');
  175. $stopwatchIsAvailable->setAccessible(true);
  176. $this->assertSame($expected, $stopwatchIsAvailable->getValue($tokenParsers[0]));
  177. }
  178. public function stopwatchExtensionAvailabilityProvider()
  179. {
  180. return array(
  181. 'debug-and-stopwatch-enabled' => array(true, true, true),
  182. 'only-stopwatch-enabled' => array(false, true, false),
  183. 'only-debug-enabled' => array(true, false, false),
  184. 'debug-and-stopwatch-disabled' => array(false, false, false),
  185. );
  186. }
  187. public function testRuntimeLoader()
  188. {
  189. $container = $this->createContainer();
  190. $container->registerExtension(new TwigExtension());
  191. $container->loadFromExtension('twig', array());
  192. $container->setParameter('kernel.environment', 'test');
  193. $container->setParameter('debug.file_link_format', 'test');
  194. $container->setParameter('foo', 'FooClass');
  195. $container->register('http_kernel', 'FooClass');
  196. $container->register('templating.locator', 'FooClass');
  197. $container->register('templating.name_parser', 'FooClass');
  198. $container->register('foo', '%foo%')->addTag('twig.runtime');
  199. $container->addCompilerPass(new RuntimeLoaderPass(), PassConfig::TYPE_BEFORE_REMOVING);
  200. $container->getCompilerPassConfig()->setRemovingPasses(array());
  201. $container->compile();
  202. $loader = $container->getDefinition('twig.runtime_loader');
  203. $args = $loader->getArgument(1);
  204. $this->assertArrayHasKey('Symfony\Bridge\Twig\Form\TwigRenderer', $args);
  205. $this->assertArrayHasKey('FooClass', $args);
  206. $this->assertContains('twig.form.renderer', $args);
  207. $this->assertContains('foo', $args);
  208. }
  209. private function createContainer()
  210. {
  211. $container = new ContainerBuilder(new ParameterBag(array(
  212. 'kernel.cache_dir' => __DIR__,
  213. 'kernel.root_dir' => __DIR__.'/Fixtures',
  214. 'kernel.charset' => 'UTF-8',
  215. 'kernel.debug' => false,
  216. 'kernel.bundles' => array('TwigBundle' => 'Symfony\\Bundle\\TwigBundle\\TwigBundle'),
  217. )));
  218. return $container;
  219. }
  220. private function compileContainer(ContainerBuilder $container)
  221. {
  222. $container->getCompilerPassConfig()->setOptimizationPasses(array());
  223. $container->getCompilerPassConfig()->setRemovingPasses(array());
  224. $container->compile();
  225. }
  226. private function loadFromFile(ContainerBuilder $container, $file, $format)
  227. {
  228. $locator = new FileLocator(__DIR__.'/Fixtures/'.$format);
  229. switch ($format) {
  230. case 'php':
  231. $loader = new PhpFileLoader($container, $locator);
  232. break;
  233. case 'xml':
  234. $loader = new XmlFileLoader($container, $locator);
  235. break;
  236. case 'yml':
  237. $loader = new YamlFileLoader($container, $locator);
  238. break;
  239. default:
  240. throw new \InvalidArgumentException(sprintf('Unsupported format: %s', $format));
  241. }
  242. $loader->load($file.'.'.$format);
  243. }
  244. }