diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php new file mode 100644 index 0000000000..39a4e13bbd --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +class TemplatingAssetHelperPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('templating.helper.assets')) { + return; + } + + $assetsHelperDefinition = $container->getDefinition('templating.helper.assets'); + $args = $assetsHelperDefinition->getArguments(); + + if ('request' === $this->getPackageScope($container, $args[0])) { + $assetsHelperDefinition->setScope('request'); + + return; + } + + if (!array_key_exists(1, $args)) { + return; + } + + if (!is_array($args[1])) { + return; + } + + foreach ($args[1] as $arg) { + if ('request' === $this->getPackageScope($container, $arg)) { + $assetsHelperDefinition->setScope('request'); + + break; + } + } + } + + private function getPackageScope(ContainerBuilder $container, $package) + { + if ($package instanceof Reference) { + return $container->findDefinition((string) $package)->getScope(); + } + + if ($package instanceof Definition) { + return $package->getScope(); + } + + // Someone did some voodoo with a compiler pass. So we ignore this + // 'package'. Can we be sure, it's a package anyway? + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 4aa7cef82f..9a9d16eaa3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -484,19 +484,6 @@ class FrameworkExtension extends Extension $namedPackages, )); - // Apply request scope to assets helper if one or more packages are request-scoped - $requireRequestScope = array_reduce( - $namedPackages, - function ($v, Reference $ref) use ($container) { - return $v || 'request' === $container->getDefinition($ref)->getScope(); - }, - 'request' === $defaultPackage->getScope() - ); - - if ($requireRequestScope) { - $container->getDefinition('templating.helper.assets')->setScope('request'); - } - if (!empty($config['loaders'])) { $loaders = array_map(function ($loader) { return new Reference($loader); }, $config['loaders']); diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 30d06fd7af..387031ddc3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInit use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingAssetHelperPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass; @@ -70,6 +71,7 @@ class FrameworkBundle extends Bundle // but as late as possible to get resolved parameters $container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); + $container->addCompilerPass(new TemplatingAssetHelperPass()); $container->addCompilerPass(new AddConstraintValidatorsPass()); $container->addCompilerPass(new AddValidatorInitializersPass()); $container->addCompilerPass(new AddConsoleCommandPass()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php new file mode 100644 index 0000000000..3a096715e1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; + +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingAssetHelperPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +class TemplatingAssetHelperPassTest extends \PHPUnit_Framework_TestCase +{ + public function getScopesTests() + { + return array( + array('container'), + array('request'), + ); + } + + /** @dataProvider getScopesTests */ + public function testFindLowestScopeInDefaultPackageWithReference($scope) + { + $container = new ContainerBuilder(); + + $defaultPackage = new Definition('stdClass'); + $defaultPackage->setScope($scope); + $container->setDefinition('default_package', $defaultPackage); + + $definition = new Definition('stdClass', array(new Reference('default_package'))); + $container->setDefinition('templating.helper.assets', $definition); + + $profilerPass = new TemplatingAssetHelperPass(); + $profilerPass->process($container); + + $this->assertSame($scope, $definition->getScope()); + } + + /** @dataProvider getScopesTests */ + public function testFindLowestScopeInDefaultPackageWithDefinition($scope) + { + $container = new ContainerBuilder(); + + $defaultPackage = new Definition('stdClass'); + $defaultPackage->setScope($scope); + + $definition = new Definition('stdClass', array($defaultPackage)); + $container->setDefinition('templating.helper.assets', $definition); + + $profilerPass = new TemplatingAssetHelperPass(); + $profilerPass->process($container); + + $this->assertSame($scope, $definition->getScope()); + } + + /** @dataProvider getScopesTests */ + public function testFindLowestScopeInNamedPackageWithReference($scope) + { + $container = new ContainerBuilder(); + + $defaultPackage = new Definition('stdClass'); + $container->setDefinition('default_package', $defaultPackage); + + $aPackage = new Definition('stdClass'); + $container->setDefinition('a_package', $aPackage); + + $bPackage = new Definition('stdClass'); + $bPackage->setScope($scope); + $container->setDefinition('b_package', $bPackage); + + $cPackage = new Definition('stdClass'); + $container->setDefinition('c_package', $cPackage); + + $definition = new Definition('stdClass', array(new Reference('default_package'), array( + new Reference('a_package'), + new Reference('b_package'), + new Reference('c_package'), + ))); + $container->setDefinition('templating.helper.assets', $definition); + + $profilerPass = new TemplatingAssetHelperPass(); + $profilerPass->process($container); + + $this->assertSame($scope, $definition->getScope()); + } + + /** @dataProvider getScopesTests */ + public function testFindLowestScopeInNamedPackageWithDefinition($scope) + { + $container = new ContainerBuilder(); + + $defaultPackage = new Definition('stdClass'); + + $aPackage = new Definition('stdClass'); + + $bPackage = new Definition('stdClass'); + $bPackage->setScope($scope); + + $cPackage = new Definition('stdClass'); + + $definition = new Definition('stdClass', array($defaultPackage, array( + $aPackage, + $bPackage, + $cPackage, + ))); + $container->setDefinition('templating.helper.assets', $definition); + + $profilerPass = new TemplatingAssetHelperPass(); + $profilerPass->process($container); + + $this->assertSame($scope, $definition->getScope()); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 6c1fcdc5a3..b09e504178 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -186,8 +186,6 @@ abstract class FrameworkExtensionTest extends TestCase $this->assertTrue($container->hasDefinition('templating.name_parser'), '->registerTemplatingConfiguration() loads templating.xml'); - $this->assertEquals('request', $container->getDefinition('templating.helper.assets')->getScope(), '->registerTemplatingConfiguration() sets request scope on assets helper if one or more packages are request-scoped'); - // default package should have one HTTP base URL and path package SSL URL $this->assertTrue($container->hasDefinition('templating.asset.default_package.http')); $package = $container->getDefinition('templating.asset.default_package.http');