N°3129 PHP 8.0 compat: Fix "Deprecated: Required parameter ... follows optional parameter ..." in Twig

Update symfony/twig-bundle from 3.4.36 to 3.4.47
This commit is contained in:
Pierre Goiffon
2022-01-28 09:55:38 +01:00
parent 75dbad7406
commit 7495fb9af4
58 changed files with 1437 additions and 42 deletions

32
composer.lock generated
View File

@@ -2200,16 +2200,16 @@
},
{
"name": "symfony/twig-bundle",
"version": "v3.4.36",
"version": "v3.4.47",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bundle.git",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9"
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/977b3096e2df96bc8a8d2329e83466cfc30c373d",
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d",
"shasum": ""
},
"require": {
@@ -2242,11 +2242,6 @@
"symfony/yaml": "~2.8|~3.0|~4.0"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Bundle\\TwigBundle\\": ""
@@ -2271,7 +2266,24 @@
],
"description": "Symfony TwigBundle",
"homepage": "https://symfony.com",
"time": "2019-10-01T15:13:36+00:00"
"support": {
"source": "https://github.com/symfony/twig-bundle/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "symfony/yaml",

View File

@@ -17,7 +17,7 @@ return array(
'ActionChecker' => $baseDir . '/core/userrights.class.inc.php',
'ActionEmail' => $baseDir . '/core/action.class.inc.php',
'ActionNotification' => $baseDir . '/core/action.class.inc.php',
'ApcService' => $baseDir . '/core/apc-service.class.inc.php',
'ApcService' => $baseDir . '/core/apc-service.class.inc.php',
'ApplicationContext' => $baseDir . '/application/applicationcontext.class.inc.php',
'ApplicationException' => $baseDir . '/application/application.inc.php',
'ApplicationMenu' => $baseDir . '/application/menunode.class.inc.php',
@@ -175,6 +175,7 @@ return array(
'DBProperty' => $baseDir . '/core/dbproperty.class.inc.php',
'DBSearch' => $baseDir . '/core/dbsearch.class.php',
'DBUnionSearch' => $baseDir . '/core/dbunionsearch.class.php',
'DOMSanitizer' => $baseDir . '/core/htmlsanitizer.class.inc.php',
'DailyRotatingLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php',
'Dashboard' => $baseDir . '/application/dashboard.class.inc.php',
'DashboardLayout' => $baseDir . '/application/dashboardlayout.class.inc.php',
@@ -645,6 +646,7 @@ return array(
'SQLObjectQueryBuilder' => $baseDir . '/core/sqlobjectquerybuilder.class.inc.php',
'SQLQuery' => $baseDir . '/core/sqlquery.class.inc.php',
'SQLUnionQuery' => $baseDir . '/core/sqlunionquery.class.inc.php',
'SVGDOMSanitizer' => $baseDir . '/core/htmlsanitizer.class.inc.php',
'ScalarExpression' => $baseDir . '/core/oql/expression.class.inc.php',
'ScalarOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
'ScssPhp\\ScssPhp\\Base\\Range' => $vendorDir . '/scssphp/scssphp/src/Base/Range.php',

View File

@@ -247,7 +247,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'ActionChecker' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
'ActionEmail' => __DIR__ . '/../..' . '/core/action.class.inc.php',
'ActionNotification' => __DIR__ . '/../..' . '/core/action.class.inc.php',
'ApcService' => __DIR__ . '/../..' . '/core/apc-service.class.inc.php',
'ApcService' => __DIR__ . '/../..' . '/core/apc-service.class.inc.php',
'ApplicationContext' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
'ApplicationException' => __DIR__ . '/../..' . '/application/application.inc.php',
'ApplicationMenu' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
@@ -405,6 +405,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'DBProperty' => __DIR__ . '/../..' . '/core/dbproperty.class.inc.php',
'DBSearch' => __DIR__ . '/../..' . '/core/dbsearch.class.php',
'DBUnionSearch' => __DIR__ . '/../..' . '/core/dbunionsearch.class.php',
'DOMSanitizer' => __DIR__ . '/../..' . '/core/htmlsanitizer.class.inc.php',
'DailyRotatingLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php',
'Dashboard' => __DIR__ . '/../..' . '/application/dashboard.class.inc.php',
'DashboardLayout' => __DIR__ . '/../..' . '/application/dashboardlayout.class.inc.php',
@@ -875,6 +876,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'SQLObjectQueryBuilder' => __DIR__ . '/../..' . '/core/sqlobjectquerybuilder.class.inc.php',
'SQLQuery' => __DIR__ . '/../..' . '/core/sqlquery.class.inc.php',
'SQLUnionQuery' => __DIR__ . '/../..' . '/core/sqlunionquery.class.inc.php',
'SVGDOMSanitizer' => __DIR__ . '/../..' . '/core/htmlsanitizer.class.inc.php',
'ScalarExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
'ScalarOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
'ScssPhp\\ScssPhp\\Base\\Range' => __DIR__ . '/..' . '/scssphp/scssphp/src/Base/Range.php',

View File

@@ -6,8 +6,8 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/pear/archive_tar',
$vendorDir . '/pear/console_getopt',
$vendorDir . '/pear/pear-core-minimal/src',
$vendorDir . '/pear/pear_exception',
$vendorDir . '/pear/archive_tar',
);

View File

@@ -2354,17 +2354,17 @@
},
{
"name": "symfony/twig-bundle",
"version": "v3.4.36",
"version_normalized": "3.4.36.0",
"version": "v3.4.47",
"version_normalized": "3.4.47.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bundle.git",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9"
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/977b3096e2df96bc8a8d2329e83466cfc30c373d",
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d",
"shasum": ""
},
"require": {
@@ -2396,13 +2396,8 @@
"symfony/web-link": "~3.3|~4.0",
"symfony/yaml": "~2.8|~3.0|~4.0"
},
"time": "2019-10-01T15:13:36+00:00",
"time": "2020-10-24T10:57:07+00:00",
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
@@ -2428,6 +2423,23 @@
],
"description": "Symfony TwigBundle",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/twig-bundle/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/twig-bundle"
},
{

View File

@@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'fe3512cb5f5d01fa590447c2f6fa15416802b748',
'reference' => 'b7f99d139c034935611802a6b2cf795e503427a2',
'name' => '__root__',
'dev' => true,
),
@@ -16,7 +16,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'fe3512cb5f5d01fa590447c2f6fa15416802b748',
'reference' => 'b7f99d139c034935611802a6b2cf795e503427a2',
'dev_requirement' => false,
),
'combodo/tcpdf' => array(
@@ -383,12 +383,12 @@
'dev_requirement' => false,
),
'symfony/twig-bundle' => array(
'pretty_version' => 'v3.4.36',
'version' => '3.4.36.0',
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/twig-bundle',
'aliases' => array(),
'reference' => 'd39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9',
'reference' => '977b3096e2df96bc8a8d2329e83466cfc30c373d',
'dev_requirement' => false,
),
'symfony/var-dumper' => array(

View File

@@ -40,9 +40,9 @@ class TemplateCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInte
$this->container = $container;
} elseif ($container instanceof Environment) {
$this->twig = $container;
@trigger_error(sprintf('Using a "%s" as first argument of %s is deprecated since Symfony 3.4 and will be unsupported in version 4.0. Use a %s instead.', Environment::class, __CLASS__, ContainerInterface::class), E_USER_DEPRECATED);
@trigger_error(sprintf('Using a "%s" as first argument of %s is deprecated since Symfony 3.4 and will be unsupported in version 4.0. Use a %s instead.', Environment::class, __CLASS__, ContainerInterface::class), \E_USER_DEPRECATED);
} else {
throw new \InvalidArgumentException(sprintf('%s only accepts instance of Psr\Container\ContainerInterface as first argument.', __CLASS__));
throw new \InvalidArgumentException(sprintf('"%s" only accepts instance of Psr\Container\ContainerInterface as first argument.', __CLASS__));
}
$this->iterator = $iterator;

View File

@@ -11,7 +11,7 @@
namespace Symfony\Bundle\TwigBundle\Command;
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Bridge\Twig\Command\DebugCommand instead.', DebugCommand::class), E_USER_DEPRECATED);
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Bridge\Twig\Command\DebugCommand instead.', DebugCommand::class), \E_USER_DEPRECATED);
use Symfony\Bridge\Twig\Command\DebugCommand as BaseDebugCommand;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;

View File

@@ -11,7 +11,7 @@
namespace Symfony\Bundle\TwigBundle;
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Twig\RuntimeLoader\ContainerRuntimeLoader class instead.', ContainerAwareRuntimeLoader::class), E_USER_DEPRECATED);
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Twig\RuntimeLoader\ContainerRuntimeLoader class instead.', ContainerAwareRuntimeLoader::class), \E_USER_DEPRECATED);
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

View File

@@ -39,7 +39,7 @@ class TwigLoaderPass implements CompilerPassInterface
}
if (!$found) {
throw new LogicException('No twig loaders found. You need to tag at least one loader with "twig.loader"');
throw new LogicException('No twig loaders found. You need to tag at least one loader with "twig.loader".');
}
if (1 === $found) {

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2019 Fabien Potencier
Copyright (c) 2004-2020 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\TwigBundle\ContainerAwareRuntimeLoader;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @group legacy
*/
class ContainerAwareRuntimeLoaderTest extends TestCase
{
public function testLoad()
{
$container = $this->getMockBuilder(ContainerInterface::class)->getMock();
$container->expects($this->once())->method('get')->with('foo');
$loader = new ContainerAwareRuntimeLoader($container, [
'FooClass' => 'foo',
]);
$loader->load('FooClass');
}
public function testLoadWithoutAMatch()
{
$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
$logger->expects($this->once())->method('warning')->with('Class "BarClass" is not configured as a Twig runtime. Add the "twig.runtime" tag to the related service in the container.');
$loader = new ContainerAwareRuntimeLoader($this->getMockBuilder(ContainerInterface::class)->getMock(), [], $logger);
$this->assertNull($loader->load('BarClass'));
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\Controller;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Request;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class ExceptionControllerTest extends TestCase
{
public function testShowActionCanBeForcedToShowErrorPage()
{
$twig = $this->createTwigEnv(['@Twig/Exception/error404.html.twig' => '<html>not found</html>']);
$request = $this->createRequest('html');
$request->attributes->set('showException', false);
$exception = FlattenException::create(new \Exception(), 404);
$controller = new ExceptionController($twig, /* "showException" defaults to --> */ true);
$response = $controller->showAction($request, $exception, null);
$this->assertEquals(200, $response->getStatusCode()); // successful request
$this->assertEquals('<html>not found</html>', $response->getContent());
}
public function testFallbackToHtmlIfNoTemplateForRequestedFormat()
{
$twig = $this->createTwigEnv(['@Twig/Exception/error.html.twig' => '<html></html>']);
$request = $this->createRequest('txt');
$exception = FlattenException::create(new \Exception());
$controller = new ExceptionController($twig, false);
$controller->showAction($request, $exception);
$this->assertEquals('html', $request->getRequestFormat());
}
public function testFallbackToHtmlWithFullExceptionIfNoTemplateForRequestedFormatAndExceptionsShouldBeShown()
{
$twig = $this->createTwigEnv(['@Twig/Exception/exception_full.html.twig' => '<html></html>']);
$request = $this->createRequest('txt');
$request->attributes->set('showException', true);
$exception = FlattenException::create(new \Exception());
$controller = new ExceptionController($twig, false);
$controller->showAction($request, $exception);
$this->assertEquals('html', $request->getRequestFormat());
}
public function testResponseHasRequestedMimeType()
{
$twig = $this->createTwigEnv(['@Twig/Exception/error.json.twig' => '{}']);
$request = $this->createRequest('json');
$exception = FlattenException::create(new \Exception());
$controller = new ExceptionController($twig, false);
$response = $controller->showAction($request, $exception);
$this->assertEquals('json', $request->getRequestFormat());
$this->assertEquals($request->getMimeType('json'), $response->headers->get('Content-Type'));
}
private function createRequest($requestFormat)
{
$request = Request::create('whatever');
$request->headers->set('X-Php-Ob-Level', 1);
$request->setRequestFormat($requestFormat);
return $request;
}
private function createTwigEnv(array $templates)
{
return new Environment(new ArrayLoader($templates));
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\Controller;
use Symfony\Bundle\TwigBundle\Controller\PreviewErrorController;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class PreviewErrorControllerTest extends TestCase
{
public function testForwardRequestToConfiguredController()
{
$request = Request::create('whatever');
$response = new Response('');
$code = 123;
$logicalControllerName = 'foo:bar:baz';
$kernel = $this->getMockBuilder('\Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$kernel
->expects($this->once())
->method('handle')
->with(
$this->callback(function (Request $request) use ($logicalControllerName, $code) {
$this->assertEquals($logicalControllerName, $request->attributes->get('_controller'));
$exception = $request->attributes->get('exception');
$this->assertInstanceOf(FlattenException::class, $exception);
$this->assertEquals($code, $exception->getStatusCode());
$this->assertFalse($request->attributes->get('showException'));
return true;
}),
$this->equalTo(HttpKernelInterface::SUB_REQUEST)
)
->willReturn($response);
$controller = new PreviewErrorController($kernel, $logicalControllerName);
$this->assertSame($response, $controller->previewErrorPageAction($request, $code));
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\ExtensionPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
class ExtensionPassTest extends TestCase
{
public function testProcessDoesNotDropExistingFileLoaderMethodCalls()
{
$container = new ContainerBuilder();
$container->setParameter('kernel.debug', false);
$container->register('twig.app_variable', '\Symfony\Bridge\Twig\AppVariable');
$container->register('templating', '\Symfony\Bundle\TwigBundle\TwigEngine');
$container->register('twig.extension.yaml');
$container->register('twig.extension.debug.stopwatch');
$container->register('twig.extension.expression');
$nativeTwigLoader = new Definition('\Twig\Loader\FilesystemLoader');
$nativeTwigLoader->addMethodCall('addPath', []);
$container->setDefinition('twig.loader.native_filesystem', $nativeTwigLoader);
$filesystemLoader = new Definition('\Symfony\Bundle\TwigBundle\Loader\FilesystemLoader');
$filesystemLoader->setArguments([null, null, null]);
$filesystemLoader->addMethodCall('addPath', []);
$container->setDefinition('twig.loader.filesystem', $filesystemLoader);
$extensionPass = new ExtensionPass();
$extensionPass->process($container);
$this->assertCount(2, $filesystemLoader->getMethodCalls());
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigEnvironmentPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class TwigEnvironmentPassTest extends TestCase
{
public function testTwigBridgeExtensionsAreRegisteredFirst()
{
$container = new ContainerBuilder();
$twigDefinition = $container->register('twig');
$container->register('other_extension', 'Foo\Bar')
->addTag('twig.extension');
$container->register('twig_bridge_extension', FormExtension::class)
->addTag('twig.extension');
$twigEnvironmentPass = new TwigEnvironmentPass();
$twigEnvironmentPass->process($container);
$methodCalls = $twigDefinition->getMethodCalls();
$this->assertCount(2, $methodCalls);
$twigBridgeExtensionReference = $methodCalls[0][1][0];
$this->assertInstanceOf(Reference::class, $twigBridgeExtensionReference);
$this->assertSame('twig_bridge_extension', (string) $twigBridgeExtensionReference);
$otherExtensionReference = $methodCalls[1][1][0];
$this->assertInstanceOf(Reference::class, $otherExtensionReference);
$this->assertSame('other_extension', (string) $otherExtensionReference);
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigLoaderPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
class TwigLoaderPassTest extends TestCase
{
/**
* @var ContainerBuilder
*/
private $builder;
/**
* @var Definition
*/
private $chainLoader;
/**
* @var TwigLoaderPass
*/
private $pass;
protected function setUp()
{
$this->builder = new ContainerBuilder();
$this->builder->register('twig');
$this->chainLoader = new Definition('loader');
$this->pass = new TwigLoaderPass();
}
public function testMapperPassWithOneTaggedLoader()
{
$this->builder->register('test_loader_1')
->addTag('twig.loader');
$this->pass->process($this->builder);
$this->assertSame('test_loader_1', (string) $this->builder->getAlias('twig.loader'));
}
public function testMapperPassWithTwoTaggedLoaders()
{
$this->builder->setDefinition('twig.loader.chain', $this->chainLoader);
$this->builder->register('test_loader_1')
->addTag('twig.loader');
$this->builder->register('test_loader_2')
->addTag('twig.loader');
$this->pass->process($this->builder);
$this->assertSame('twig.loader.chain', (string) $this->builder->getAlias('twig.loader'));
$calls = $this->chainLoader->getMethodCalls();
$this->assertCount(2, $calls);
$this->assertEquals('addLoader', $calls[0][0]);
$this->assertEquals('addLoader', $calls[1][0]);
$this->assertEquals('test_loader_1', (string) $calls[0][1][0]);
$this->assertEquals('test_loader_2', (string) $calls[1][1][0]);
}
public function testMapperPassWithTwoTaggedLoadersWithPriority()
{
$this->builder->setDefinition('twig.loader.chain', $this->chainLoader);
$this->builder->register('test_loader_1')
->addTag('twig.loader', ['priority' => 100]);
$this->builder->register('test_loader_2')
->addTag('twig.loader', ['priority' => 200]);
$this->pass->process($this->builder);
$this->assertSame('twig.loader.chain', (string) $this->builder->getAlias('twig.loader'));
$calls = $this->chainLoader->getMethodCalls();
$this->assertCount(2, $calls);
$this->assertEquals('addLoader', $calls[0][0]);
$this->assertEquals('addLoader', $calls[1][0]);
$this->assertEquals('test_loader_2', (string) $calls[0][1][0]);
$this->assertEquals('test_loader_1', (string) $calls[1][1][0]);
}
public function testMapperPassWithZeroTaggedLoaders()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\LogicException');
$this->pass->process($this->builder);
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\TwigBundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\Processor;
class ConfigurationTest extends TestCase
{
public function testDoNoDuplicateDefaultFormResources()
{
$input = [
'form_themes' => ['form_div_layout.html.twig'],
];
$processor = new Processor();
$config = $processor->processConfiguration(new Configuration(), [$input]);
$this->assertEquals(['form_div_layout.html.twig'], $config['form_themes']);
}
}

View File

@@ -0,0 +1,6 @@
<?php
$container->loadFromExtension('twig', [
'autoescape_service' => 'my_project.some_bundle.template_escaping_guesser',
'autoescape_service_method' => 'guess',
]);

View File

@@ -0,0 +1,3 @@
<?php
$container->loadFromExtension('twig', []);

View File

@@ -0,0 +1,7 @@
<?php
$container->loadFromExtension('twig', [
'paths' => [
'namespaced_path3' => 'namespace3',
],
]);

View File

@@ -0,0 +1,14 @@
<?php
$container->loadFromExtension('twig', [
'date' => [
'format' => 'Y-m-d',
'interval_format' => '%d',
'timezone' => 'Europe/Berlin',
],
'number_format' => [
'decimals' => 2,
'decimal_point' => ',',
'thousands_separator' => '.',
],
]);

View File

@@ -0,0 +1,27 @@
<?php
$container->loadFromExtension('twig', [
'form_themes' => [
'MyBundle::form.html.twig',
],
'globals' => [
'foo' => '@bar',
'baz' => '@@qux',
'pi' => 3.14,
'bad' => ['key' => 'foo'],
],
'auto_reload' => true,
'autoescape' => true,
'base_template_class' => 'stdClass',
'cache' => '/tmp',
'charset' => 'ISO-8859-1',
'debug' => true,
'strict_variables' => true,
'default_path' => '%kernel.project_dir%/Fixtures/templates',
'paths' => [
'path1',
'path2',
'namespaced_path1' => 'namespace1',
'namespaced_path2' => 'namespace2',
],
]);

View File

@@ -0,0 +1 @@
This is a layout

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:twig="http://symfony.com/schema/dic/twig"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
<twig:config autoescape-service="my_project.some_bundle.template_escaping_guesser" autoescape-service-method="guess" />
</container>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:twig="http://symfony.com/schema/dic/twig"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
<twig:config />
</container>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:twig="http://symfony.com/schema/dic/twig"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
<twig:config auto-reload="true" autoescape="true" base-template-class="stdClass" cache="/tmp" charset="ISO-8859-1" debug="true" strict-variables="true">
<twig:path namespace="namespace3">namespaced_path3</twig:path>
</twig:config>
</container>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:twig="http://symfony.com/schema/dic/twig"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
<twig:config>
<twig:date format="Y-m-d" interval-format="%d" timezone="Europe/Berlin" />
<twig:number-format decimals="2" decimal-point="," thousands-separator="." />
</twig:config>
</container>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:twig="http://symfony.com/schema/dic/twig"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
<twig:config auto-reload="true" autoescape="true" base-template-class="stdClass" cache="/tmp" charset="ISO-8859-1" debug="true" strict-variables="true" default-path="%kernel.project_dir%/Fixtures/templates">
<twig:form-theme>MyBundle::form.html.twig</twig:form-theme>
<twig:global key="foo" id="bar" type="service" />
<twig:global key="baz">@@qux</twig:global>
<twig:global key="pi">3.14</twig:global>
<twig:path>path1</twig:path>
<twig:path>path2</twig:path>
<twig:path namespace="namespace1">namespaced_path1</twig:path>
<twig:path namespace="namespace2">namespaced_path2</twig:path>
</twig:config>
</container>

View File

@@ -0,0 +1,3 @@
twig:
autoescape_service: my_project.some_bundle.template_escaping_guesser
autoescape_service_method: guess

View File

@@ -0,0 +1,3 @@
twig:
paths:
namespaced_path3: namespace3

View File

@@ -0,0 +1,9 @@
twig:
date:
format: Y-m-d
interval_format: '%d'
timezone: Europe/Berlin
number_format:
decimals: 2
decimal_point: ','
thousands_separator: .

View File

@@ -0,0 +1,21 @@
twig:
form_themes:
- MyBundle::form.html.twig
globals:
foo: "@bar"
baz: "@@qux"
pi: 3.14
bad: {key: foo}
auto_reload: true
autoescape: true
base_template_class: stdClass
cache: /tmp
charset: ISO-8859-1
debug: true
strict_variables: true
default_path: '%kernel.project_dir%/Fixtures/templates'
paths:
path1: ''
path2: ''
namespaced_path1: namespace1
namespaced_path2: namespace2

View File

@@ -0,0 +1,355 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\RuntimeLoaderPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\TwigExtension;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
class TwigExtensionTest extends TestCase
{
public function testLoadEmptyConfiguration()
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$container->loadFromExtension('twig', []);
$this->compileContainer($container);
$this->assertEquals('Twig\Environment', $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
$this->assertContains('form_div_layout.html.twig', $container->getParameter('twig.form.resources'), '->load() includes default template for form resources');
// Twig options
$options = $container->getDefinition('twig')->getArgument(1);
$this->assertEquals('%kernel.cache_dir%/twig', $options['cache'], '->load() sets default value for cache option');
$this->assertEquals('%kernel.charset%', $options['charset'], '->load() sets default value for charset option');
$this->assertEquals('%kernel.debug%', $options['debug'], '->load() sets default value for debug option');
}
/**
* @dataProvider getFormats
*/
public function testLoadFullConfiguration($format)
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'full', $format);
$this->compileContainer($container);
$this->assertEquals('Twig\Environment', $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
// Form resources
$resources = $container->getParameter('twig.form.resources');
$this->assertContains('form_div_layout.html.twig', $resources, '->load() includes default template for form resources');
$this->assertContains('MyBundle::form.html.twig', $resources, '->load() merges new templates into form resources');
// Globals
$calls = $container->getDefinition('twig')->getMethodCalls();
$this->assertEquals('app', $calls[0][1][0], '->load() registers services as Twig globals');
$this->assertEquals(new Reference('twig.app_variable'), $calls[0][1][1]);
$this->assertEquals('foo', $calls[2][1][0], '->load() registers services as Twig globals');
$this->assertEquals(new Reference('bar'), $calls[2][1][1], '->load() registers services as Twig globals');
$this->assertEquals('baz', $calls[3][1][0], '->load() registers variables as Twig globals');
$this->assertEquals('@qux', $calls[3][1][1], '->load() allows escaping of service identifiers');
$this->assertEquals('pi', $calls[4][1][0], '->load() registers variables as Twig globals');
$this->assertEquals(3.14, $calls[4][1][1], '->load() registers variables as Twig globals');
// Yaml and Php specific configs
if (\in_array($format, ['yml', 'php'])) {
$this->assertEquals('bad', $calls[5][1][0], '->load() registers variables as Twig globals');
$this->assertEquals(['key' => 'foo'], $calls[5][1][1], '->load() registers variables as Twig globals');
}
// Twig options
$options = $container->getDefinition('twig')->getArgument(1);
$this->assertTrue($options['auto_reload'], '->load() sets the auto_reload option');
$this->assertTrue($options['autoescape'], '->load() sets the autoescape option');
$this->assertEquals('stdClass', $options['base_template_class'], '->load() sets the base_template_class option');
$this->assertEquals('/tmp', $options['cache'], '->load() sets the cache option');
$this->assertEquals('ISO-8859-1', $options['charset'], '->load() sets the charset option');
$this->assertTrue($options['debug'], '->load() sets the debug option');
$this->assertTrue($options['strict_variables'], '->load() sets the strict_variables option');
}
/**
* @dataProvider getFormats
*/
public function testLoadCustomTemplateEscapingGuesserConfiguration($format)
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'customTemplateEscapingGuesser', $format);
$this->compileContainer($container);
$options = $container->getDefinition('twig')->getArgument(1);
$this->assertEquals([new Reference('my_project.some_bundle.template_escaping_guesser'), 'guess'], $options['autoescape']);
}
/**
* @dataProvider getFormats
*/
public function testLoadDefaultTemplateEscapingGuesserConfiguration($format)
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'empty', $format);
$this->compileContainer($container);
$options = $container->getDefinition('twig')->getArgument(1);
$this->assertEquals('name', $options['autoescape']);
}
/**
* @dataProvider getFormats
*/
public function testLoadCustomDateFormats($fileFormat)
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'formats', $fileFormat);
$this->compileContainer($container);
$environmentConfigurator = $container->getDefinition('twig.configurator.environment');
$this->assertSame('Y-m-d', $environmentConfigurator->getArgument(0));
$this->assertSame('%d', $environmentConfigurator->getArgument(1));
$this->assertSame('Europe/Berlin', $environmentConfigurator->getArgument(2));
$this->assertSame(2, $environmentConfigurator->getArgument(3));
$this->assertSame(',', $environmentConfigurator->getArgument(4));
$this->assertSame('.', $environmentConfigurator->getArgument(5));
}
public function testGlobalsWithDifferentTypesAndValues()
{
$globals = [
'array' => [],
'false' => false,
'float' => 2.0,
'integer' => 3,
'null' => null,
'object' => new \stdClass(),
'string' => 'foo',
'true' => true,
];
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$container->loadFromExtension('twig', ['globals' => $globals]);
$this->compileContainer($container);
$calls = $container->getDefinition('twig')->getMethodCalls();
foreach (\array_slice($calls, 2) as $call) {
$this->assertEquals(key($globals), $call[1][0]);
$this->assertSame(current($globals), $call[1][1]);
next($globals);
}
}
/**
* @dataProvider getFormats
*/
public function testTwigLoaderPaths($format)
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'full', $format);
$this->loadFromFile($container, 'extra', $format);
$this->compileContainer($container);
$def = $container->getDefinition('twig.loader.native_filesystem');
$paths = [];
foreach ($def->getMethodCalls() as $call) {
if ('addPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
$paths[] = $call[1];
}
}
$this->assertEquals([
['path1'],
['path2'],
['namespaced_path1', 'namespace1'],
['namespaced_path2', 'namespace2'],
['namespaced_path3', 'namespace3'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildChildTwigBundle/Resources/views', 'ChildChildChildChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildChildTwigBundle/Resources/views', 'ChildChildChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildTwigBundle/Resources/views', 'ChildChildChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildChildTwigBundle/Resources/views', 'Twig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildTwigBundle/Resources/views', 'Twig'],
[__DIR__.'/Fixtures/Bundle/ChildChildTwigBundle/Resources/views', 'Twig'],
[__DIR__.'/Fixtures/Bundle/ChildTwigBundle/Resources/views', 'Twig'],
[__DIR__.'/Fixtures/Resources/TwigBundle/views', 'Twig'],
[__DIR__.'/Fixtures/templates/bundles/TwigBundle', 'Twig'],
[realpath(__DIR__.'/../..').'/Resources/views', 'Twig'],
[realpath(__DIR__.'/../..').'/Resources/views', '!Twig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildChildTwigBundle/Resources/views', 'ChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildTwigBundle/Resources/views', 'ChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildTwigBundle/Resources/views', 'ChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildTwigBundle/Resources/views', 'ChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildChildTwigBundle/Resources/views', 'ChildChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildChildTwigBundle/Resources/views', 'ChildChildTwig'],
[__DIR__.'/Fixtures/Bundle/ChildChildTwigBundle/Resources/views', 'ChildChildTwig'],
[__DIR__.'/Fixtures/Resources/views'],
[__DIR__.'/Fixtures/templates'],
], $paths);
}
public function getFormats()
{
return [
['php'],
['yml'],
['xml'],
];
}
/**
* @dataProvider stopwatchExtensionAvailabilityProvider
*/
public function testStopwatchExtensionAvailability($debug, $stopwatchEnabled, $expected)
{
$container = $this->createContainer();
$container->setParameter('kernel.debug', $debug);
if ($stopwatchEnabled) {
$container->register('debug.stopwatch', 'Symfony\Component\Stopwatch\Stopwatch');
}
$container->registerExtension(new TwigExtension());
$container->loadFromExtension('twig', []);
$container->setAlias('test.twig.extension.debug.stopwatch', 'twig.extension.debug.stopwatch')->setPublic(true);
$this->compileContainer($container);
$tokenParsers = $container->get('test.twig.extension.debug.stopwatch')->getTokenParsers();
$stopwatchIsAvailable = new \ReflectionProperty($tokenParsers[0], 'stopwatchIsAvailable');
$stopwatchIsAvailable->setAccessible(true);
$this->assertSame($expected, $stopwatchIsAvailable->getValue($tokenParsers[0]));
}
public function stopwatchExtensionAvailabilityProvider()
{
return [
'debug-and-stopwatch-enabled' => [true, true, true],
'only-stopwatch-enabled' => [false, true, false],
'only-debug-enabled' => [true, false, false],
'debug-and-stopwatch-disabled' => [false, false, false],
];
}
public function testRuntimeLoader()
{
$container = $this->createContainer();
$container->registerExtension(new TwigExtension());
$container->loadFromExtension('twig', []);
$container->setParameter('kernel.environment', 'test');
$container->setParameter('debug.file_link_format', 'test');
$container->setParameter('foo', 'FooClass');
$container->register('http_kernel', 'FooClass');
$container->register('templating.locator', 'FooClass');
$container->register('templating.name_parser', 'FooClass');
$container->register('foo', '%foo%')->addTag('twig.runtime');
$container->addCompilerPass(new RuntimeLoaderPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->getCompilerPassConfig()->setRemovingPasses([]);
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
$container->compile();
$loader = $container->getDefinition('twig.runtime_loader');
$args = $container->getDefinition((string) $loader->getArgument(0))->getArgument(0);
$this->assertArrayHasKey('Symfony\Component\Form\FormRenderer', $args);
$this->assertArrayHasKey('FooClass', $args);
$this->assertEquals('twig.form.renderer', $args['Symfony\Component\Form\FormRenderer']->getValues()[0]);
$this->assertEquals('foo', $args['FooClass']->getValues()[0]);
}
private function createContainer()
{
$container = new ContainerBuilder(new ParameterBag([
'kernel.cache_dir' => __DIR__,
'kernel.root_dir' => __DIR__.'/Fixtures',
'kernel.project_dir' => __DIR__,
'kernel.charset' => 'UTF-8',
'kernel.debug' => false,
'kernel.bundles' => [
'TwigBundle' => 'Symfony\\Bundle\\TwigBundle\\TwigBundle',
'ChildTwigBundle' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildTwigBundle\\ChildTwigBundle',
'ChildChildTwigBundle' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildChildTwigBundle\\ChildChildTwigBundle',
'ChildChildChildTwigBundle' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildChildChildTwigBundle\\ChildChildChildTwigBundle',
'ChildChildChildChildTwigBundle' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildChildChildChildTwigBundle\\ChildChildChildChildTwigBundle',
],
'kernel.bundles_metadata' => [
'ChildChildChildChildTwigBundle' => [
'namespace' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildChildChildChildTwigBundle\\ChildChildChildChildTwigBundle',
'parent' => 'ChildChildChildTwigBundle',
'path' => __DIR__.'/Fixtures/Bundle/ChildChildChildChildTwigBundle',
],
'TwigBundle' => [
'namespace' => 'Symfony\\Bundle\\TwigBundle',
'parent' => null,
'path' => realpath(__DIR__.'/../..'),
],
'ChildTwigBundle' => [
'namespace' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildTwigBundle\\ChildTwigBundle',
'parent' => 'TwigBundle',
'path' => __DIR__.'/Fixtures/Bundle/ChildTwigBundle',
],
'ChildChildChildTwigBundle' => [
'namespace' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildChildChildTwigBundle\\ChildChildChildTwigBundle',
'parent' => 'ChildChildTwigBundle',
'path' => __DIR__.'/Fixtures/Bundle/ChildChildChildTwigBundle',
],
'ChildChildTwigBundle' => [
'namespace' => 'Symfony\\Bundle\\TwigBundle\\Tests\\DependencyInjection\\Fixtures\\Bundle\\ChildChildTwigBundle\\ChildChildTwigBundle',
'parent' => 'ChildTwigBundle',
'path' => __DIR__.'/Fixtures/Bundle/ChildChildTwigBundle',
],
],
]));
return $container;
}
private function compileContainer(ContainerBuilder $container)
{
$container->getCompilerPassConfig()->setOptimizationPasses([]);
$container->getCompilerPassConfig()->setRemovingPasses([]);
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
$container->compile();
}
private function loadFromFile(ContainerBuilder $container, $file, $format)
{
$locator = new FileLocator(__DIR__.'/Fixtures/'.$format);
switch ($format) {
case 'php':
$loader = new PhpFileLoader($container, $locator);
break;
case 'xml':
$loader = new XmlFileLoader($container, $locator);
break;
case 'yml':
$loader = new YamlFileLoader($container, $locator);
break;
default:
throw new \InvalidArgumentException(sprintf('Unsupported format: "%s"', $format));
}
$loader->load($file.'.'.$format);
}
}

View File

@@ -0,0 +1 @@
{# Twig template #}

View File

@@ -0,0 +1 @@
{# Twig template #}

View File

@@ -0,0 +1 @@
{# Twig template #}

View File

@@ -0,0 +1 @@
{# Twig template #}

View File

@@ -0,0 +1,124 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;
class CacheWarmingTest extends TestCase
{
public function testCacheIsProperlyWarmedWhenTemplatingIsAvailable()
{
$kernel = new CacheWarmingKernel(true);
$kernel->boot();
$warmer = $kernel->getContainer()->get('cache_warmer');
$warmer->enableOptionalWarmers();
$warmer->warmUp($kernel->getCacheDir());
$this->assertFileExists($kernel->getCacheDir().'/twig');
}
public function testCacheIsProperlyWarmedWhenTemplatingIsDisabled()
{
$kernel = new CacheWarmingKernel(false);
$kernel->boot();
$warmer = $kernel->getContainer()->get('cache_warmer');
$warmer->enableOptionalWarmers();
$warmer->warmUp($kernel->getCacheDir());
$this->assertFileExists($kernel->getCacheDir().'/twig');
}
protected function setUp()
{
$this->deleteTempDir();
}
protected function tearDown()
{
$this->deleteTempDir();
}
private function deleteTempDir()
{
if (!file_exists($dir = sys_get_temp_dir().'/'.Kernel::VERSION.'/CacheWarmingKernel')) {
return;
}
$fs = new Filesystem();
$fs->remove($dir);
}
}
class CacheWarmingKernel extends Kernel
{
private $withTemplating;
public function __construct($withTemplating)
{
$this->withTemplating = $withTemplating;
parent::__construct(($withTemplating ? 'with' : 'without').'_templating', true);
}
public function getName()
{
return 'CacheWarming';
}
public function registerBundles()
{
return [new FrameworkBundle(), new TwigBundle()];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(function ($container) {
$container->loadFromExtension('framework', [
'secret' => '$ecret',
'form' => ['enabled' => false],
]);
});
if ($this->withTemplating) {
$loader->load(function ($container) {
$container->loadFromExtension('framework', [
'secret' => '$ecret',
'templating' => ['engines' => ['twig']],
'router' => ['resource' => '%kernel.project_dir%/Resources/config/empty_routing.yml'],
'form' => ['enabled' => false],
]);
});
}
}
public function getProjectDir()
{
return __DIR__;
}
public function getCacheDir()
{
return sys_get_temp_dir().'/'.Kernel::VERSION.'/CacheWarmingKernel/cache/'.$this->environment;
}
public function getLogDir()
{
return sys_get_temp_dir().'/'.Kernel::VERSION.'/CacheWarmingKernel/logs';
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\Functional;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class EmptyAppTest extends TestCase
{
public function testBootEmptyApp()
{
$kernel = new EmptyAppKernel('test', true);
$kernel->boot();
$this->assertTrue($kernel->getContainer()->hasParameter('twig.default_path'));
$this->assertNotEmpty($kernel->getContainer()->getParameter('twig.default_path'));
}
}
class EmptyAppKernel extends Kernel
{
public function registerBundles()
{
return [new TwigBundle()];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
}
public function getCacheDir()
{
return sys_get_temp_dir().'/'.Kernel::VERSION.'/EmptyAppKernel/cache/'.$this->environment;
}
public function getLogDir()
{
return sys_get_temp_dir().'/'.Kernel::VERSION.'/EmptyAppKernel/logs';
}
}

View File

@@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;
class NoTemplatingEntryTest extends TestCase
{
public function test()
{
$kernel = new NoTemplatingEntryKernel('dev', true);
$kernel->boot();
$container = $kernel->getContainer();
$content = $container->get('twig')->render('index.html.twig');
$this->assertStringContainsString('{ a: b }', $content);
}
protected function setUp()
{
$this->deleteTempDir();
}
protected function tearDown()
{
$this->deleteTempDir();
}
protected function deleteTempDir()
{
if (!file_exists($dir = sys_get_temp_dir().'/'.Kernel::VERSION.'/NoTemplatingEntryKernel')) {
return;
}
$fs = new Filesystem();
$fs->remove($dir);
}
}
class NoTemplatingEntryKernel extends Kernel
{
public function registerBundles()
{
return [new FrameworkBundle(), new TwigBundle()];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(function ($container) {
$container->loadFromExtension('framework', [
'secret' => '$ecret',
'form' => ['enabled' => false],
]);
});
}
public function getCacheDir()
{
return sys_get_temp_dir().'/'.Kernel::VERSION.'/NoTemplatingEntryKernel/cache/'.$this->environment;
}
public function getLogDir()
{
return sys_get_temp_dir().'/'.Kernel::VERSION.'/NoTemplatingEntryKernel/logs';
}
}

View File

@@ -0,0 +1 @@
{{ {a: 'b'}|yaml_encode }}

View File

@@ -0,0 +1,125 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests\Loader;
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
use Symfony\Bundle\TwigBundle\Loader\FilesystemLoader;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
class FilesystemLoaderTest extends TestCase
{
public function testGetSourceContext()
{
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
$locator = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$locator
->expects($this->once())
->method('locate')
->willReturn(__DIR__.'/../DependencyInjection/Fixtures/Resources/views/layout.html.twig')
;
$loader = new FilesystemLoader($locator, $parser);
$loader->addPath(__DIR__.'/../DependencyInjection/Fixtures/Resources/views', 'namespace');
// Twig-style
$this->assertEquals("This is a layout\n", $loader->getSourceContext('@namespace/layout.html.twig')->getCode());
// Symfony-style
$this->assertEquals("This is a layout\n", $loader->getSourceContext('TwigBundle::layout.html.twig')->getCode());
}
public function testExists()
{
// should return true for templates that Twig does not find, but Symfony does
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
$locator = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$locator
->expects($this->once())
->method('locate')
->willReturn($template = __DIR__.'/../DependencyInjection/Fixtures/Resources/views/layout.html.twig')
;
$loader = new FilesystemLoader($locator, $parser);
$this->assertTrue($loader->exists($template));
}
public function testTwigErrorIfLocatorThrowsInvalid()
{
$this->expectException('Twig\Error\LoaderError');
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
$parser
->expects($this->once())
->method('parse')
->with('name.format.engine')
->willReturn(new TemplateReference('', '', 'name', 'format', 'engine'))
;
$locator = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$locator
->expects($this->once())
->method('locate')
->willThrowException(new \InvalidArgumentException('Unable to find template "NonExistent".'))
;
$loader = new FilesystemLoader($locator, $parser);
$loader->getCacheKey('name.format.engine');
}
public function testTwigErrorIfLocatorReturnsFalse()
{
$this->expectException('Twig\Error\LoaderError');
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
$parser
->expects($this->once())
->method('parse')
->with('name.format.engine')
->willReturn(new TemplateReference('', '', 'name', 'format', 'engine'))
;
$locator = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$locator
->expects($this->once())
->method('locate')
->willReturn(false)
;
$loader = new FilesystemLoader($locator, $parser);
$loader->getCacheKey('name.format.engine');
}
public function testTwigErrorIfTemplateDoesNotExist()
{
$this->expectException('Twig\Error\LoaderError');
$this->expectExceptionMessageMatches('/Unable to find template "name\.format\.engine" \(looked into: .*Tests.Loader.\.\..DependencyInjection.Fixtures.Resources.views\)/');
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
$locator = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$loader = new FilesystemLoader($locator, $parser);
$loader->addPath(__DIR__.'/../DependencyInjection/Fixtures/Resources/views');
$method = new \ReflectionMethod('Symfony\Bundle\TwigBundle\Loader\FilesystemLoader', 'findTemplate');
$method->setAccessible(true);
$method->invoke($loader, 'name.format.engine');
}
public function testTwigSoftErrorIfTemplateDoesNotExist()
{
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
$locator = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$loader = new FilesystemLoader($locator, $parser);
$loader->addPath(__DIR__.'/../DependencyInjection/Fixtures/Resources/views');
$method = new \ReflectionMethod('Symfony\Bundle\TwigBundle\Loader\FilesystemLoader', 'findTemplate');
$method->setAccessible(true);
$this->assertFalse($method->invoke($loader, 'name.format.engine', false));
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests;
use Symfony\Bundle\TwigBundle\TemplateIterator;
class TemplateIteratorTest extends TestCase
{
public function testGetIterator()
{
$bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\BundleInterface')->getMock();
$bundle->expects($this->any())->method('getName')->willReturn('BarBundle');
$bundle->expects($this->any())->method('getPath')->willReturn(__DIR__.'/Fixtures/templates/BarBundle');
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\Kernel')->disableOriginalConstructor()->getMock();
$kernel->expects($this->any())->method('getBundles')->willReturn([
$bundle,
]);
$iterator = new TemplateIterator($kernel, __DIR__.'/Fixtures/templates', [__DIR__.'/Fixtures/templates/Foo' => 'Foo'], __DIR__.'/DependencyInjection/Fixtures/templates');
$sorted = iterator_to_array($iterator);
sort($sorted);
$this->assertEquals(
[
'@Bar/base.html.twig',
'@Bar/index.html.twig',
'@Bar/layout.html.twig',
'@Foo/index.html.twig',
'layout.html.twig',
'sub/sub.html.twig',
],
$sorted
);
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\TwigBundle\Tests;
use PHPUnit\Framework\TestCase as PHPUnitTestCase;
class TestCase extends PHPUnitTestCase
{
}

View File

@@ -32,7 +32,8 @@ class TwigBundle extends Bundle
{
parent::build($container);
$container->addCompilerPass(new ExtensionPass());
// ExtensionPass must be run before the FragmentRendererPass as it adds tags that are processed later
$container->addCompilerPass(new ExtensionPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
$container->addCompilerPass(new TwigEnvironmentPass());
$container->addCompilerPass(new TwigLoaderPass());
$container->addCompilerPass(new ExceptionListenerPass());

View File

@@ -50,10 +50,5 @@
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
}
"minimum-stability": "dev"
}