Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Moves default and user-configured overridden bundle path registration to a CompilerPass #30360

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;

use Symfony\Component\Config\Resource\FileExistenceResource;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Registers the default and user-configured overriding bundles paths.
*/
final class OverriddenBundlePathPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$twigLoaderFilesystemId = 'twig.loader.native_filesystem';
if (false === $container->hasDefinition($twigLoaderFilesystemId)) {
return;
}
$twigLoaderFilesystemDefinition = $container->getDefinition($twigLoaderFilesystemId);

$twigDefaultPath = $container->getParameter('twig.default_path');

// Adds Twig default_path relative overriden path on top
foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) {
$defaultOverrideBundlePath = $container->getParameterBag()->resolveValue($twigDefaultPath).'/bundles/'.$name;

if (file_exists($dir = $container->getParameter('kernel.root_dir').'/Resources/'.$name.'/views')) {
@trigger_error(sprintf('Templates directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultOverrideBundlePath), E_USER_DEPRECATED);

$twigLoaderFilesystemDefinition->addMethodCall(
'prependPath',
[$dir, $this->normalizeBundleName($name)]
);
}
$container->addResource(new FileExistenceResource($dir));

if (file_exists($defaultOverrideBundlePath)) {
$twigLoaderFilesystemDefinition->addMethodCall(
'prependPath',
[$defaultOverrideBundlePath, $this->normalizeBundleName($name)]
);
}
$container->addResource(new FileExistenceResource($defaultOverrideBundlePath));
}

// Adds user-configured namespaced paths
foreach ($container->getParameter('twig.namespaced_user_configured_paths') as $namespace => $paths) {
foreach ($paths as $path) {
$twigLoaderFilesystemDefinition->addMethodCall(
'prependPath',
[$path, $namespace]
);
}
}
}

private function normalizeBundleName(string $name): string
{
if ('Bundle' === substr($name, -6)) {
$name = substr($name, 0, -6);
}

return $name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,19 @@ public function load(array $configs, ContainerBuilder $container)
}

// register user-configured paths
$namespacedUserConfiguredPaths = [];
foreach ($config['paths'] as $path => $namespace) {
if (!$namespace) {
$twigFilesystemLoaderDefinition->addMethodCall('addPath', [$path]);
} else {
$twigFilesystemLoaderDefinition->addMethodCall('addPath', [$path, $namespace]);
if (isset($namespacedUserConfiguredPaths[$namespace])) {
array_unshift($namespacedUserConfiguredPaths[$namespace], $path);
} else {
$namespacedUserConfiguredPaths[$namespace] = [$path];
}
}
}
$container->setParameter('twig.namespaced_user_configured_paths', $namespacedUserConfiguredPaths);

// paths are modified in ExtensionPass if forms are enabled
$container->getDefinition('twig.cache_warmer')->replaceArgument(2, $config['paths']);
Expand Down Expand Up @@ -169,20 +175,6 @@ private function getBundleTemplatePaths(ContainerBuilder $container, array $conf
{
$bundleHierarchy = [];
foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) {
$defaultOverrideBundlePath = $container->getParameterBag()->resolveValue($config['default_path']).'/bundles/'.$name;

if (file_exists($dir = $container->getParameter('kernel.root_dir').'/Resources/'.$name.'/views')) {
@trigger_error(sprintf('Templates directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultOverrideBundlePath), E_USER_DEPRECATED);

$bundleHierarchy[$name][] = $dir;
}
$container->addResource(new FileExistenceResource($dir));

if (file_exists($defaultOverrideBundlePath)) {
$bundleHierarchy[$name][] = $defaultOverrideBundlePath;
}
$container->addResource(new FileExistenceResource($defaultOverrideBundlePath));

if (file_exists($dir = $bundle['path'].'/Resources/views')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @alterphp, re-thinking this in another way... instead, what about moving this registration (as late as possible) into the compiler pass and call to addPath always?

I mean, G1 and G2 as before in the same place, and only G3 into the compiler pass, thus other bundles would addPath before G3 keeping the priority/order and also less changes than now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me some minutes to understand ... and it sounds far better than what I have done until now. I'm gonna take the time to refactor this.

Thanks for review !

$bundleHierarchy[$name][] = $dir;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection;

use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\OverriddenBundlePathPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\RuntimeLoaderPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\TwigExtension;
use Symfony\Bundle\TwigBundle\Tests\TestCase;
Expand Down Expand Up @@ -177,64 +178,83 @@ public function testTwigLoaderPaths($format)
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'full', $format);
$this->loadFromFile($container, 'extra', $format);
$container->addCompilerPass(new OverriddenBundlePathPass(), PassConfig::TYPE_BEFORE_REMOVING);
$this->compileContainer($container);

$def = $container->getDefinition('twig.loader.native_filesystem');
$paths = [];
$addedPaths = [];
foreach ($def->getMethodCalls() as $call) {
if ('addPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
$paths[] = $call[1];
$addedPaths[] = $call[1];
}
}
$prependedPaths = [];
foreach ($def->getMethodCalls() as $call) {
if ('prependPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
$prependedPaths[] = $call[1];
}
}

$this->assertEquals([
['path1'],
['path2'],
['namespaced_path1', 'namespace1'],
['namespaced_path2', 'namespace2'],
['namespaced_path3', 'namespace3'],
[__DIR__.'/Fixtures/templates/bundles/TwigBundle', 'Twig'],
[realpath(__DIR__.'/../..').'/Resources/views', 'Twig'],
[realpath(__DIR__.'/../..').'/Resources/views', '!Twig'],
[__DIR__.'/Fixtures/templates'],
], $paths);
], $addedPaths);
$this->assertEquals([
[__DIR__.'/Fixtures/templates/bundles/TwigBundle', 'Twig'],
['namespaced_path1', 'namespace1'],
['namespaced_path2', 'namespace2'],
['namespaced_path3', 'namespace3'],
], $prependedPaths);
}

/**
* @group legacy
* @dataProvider getFormats
* @expectedDeprecation Templates directory "%s/Resources/TwigBundle/views" is deprecated since Symfony 4.2, use "%s/templates/bundles/TwigBundle" instead.
* @dataProvider getFormats
* @expectedDeprecation Templates directory "%s/Resources/views" is deprecated since Symfony 4.2, use "%s/templates" instead.
* @expectedDeprecation Templates directory "%s/Resources/TwigBundle/views" is deprecated since Symfony 4.2, use "%s/templates/bundles/TwigBundle" instead.
*/
public function testLegacyTwigLoaderPaths($format)
{
$container = $this->createContainer(__DIR__.'/../Fixtures/templates');
$container->registerExtension(new TwigExtension());
$this->loadFromFile($container, 'full', $format);
$this->loadFromFile($container, 'extra', $format);
$container->addCompilerPass(new OverriddenBundlePathPass(), PassConfig::TYPE_BEFORE_REMOVING);
$this->compileContainer($container);

$def = $container->getDefinition('twig.loader.native_filesystem');
$paths = [];
$addedPaths = [];
foreach ($def->getMethodCalls() as $call) {
if ('addPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
$paths[] = $call[1];
$addedPaths[] = $call[1];
}
}
$prependedPaths = [];
foreach ($def->getMethodCalls() as $call) {
if ('prependPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
$prependedPaths[] = $call[1];
}
}

$this->assertEquals([
['path1'],
['path2'],
['namespaced_path1', 'namespace1'],
['namespaced_path2', 'namespace2'],
['namespaced_path3', 'namespace3'],
[__DIR__.'/../Fixtures/templates/Resources/TwigBundle/views', 'Twig'],
[__DIR__.'/Fixtures/templates/bundles/TwigBundle', 'Twig'],
[realpath(__DIR__.'/../..').'/Resources/views', 'Twig'],
[realpath(__DIR__.'/../..').'/Resources/views', '!Twig'],
[__DIR__.'/../Fixtures/templates/Resources/views'],
[__DIR__.'/Fixtures/templates'],
], $paths);
], $addedPaths);
$this->assertEquals([
[__DIR__.'/../Fixtures/templates/Resources/TwigBundle/views', 'Twig'],
[__DIR__.'/Fixtures/templates/bundles/TwigBundle', 'Twig'],
['namespaced_path1', 'namespace1'],
['namespaced_path2', 'namespace2'],
['namespaced_path3', 'namespace3'],
], $prependedPaths);
}

public function getFormats()
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/TwigBundle/TwigBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\ExceptionListenerPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\ExtensionPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\OverriddenBundlePathPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\RuntimeLoaderPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigEnvironmentPass;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigLoaderPass;
Expand All @@ -37,6 +38,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new TwigLoaderPass());
$container->addCompilerPass(new ExceptionListenerPass());
$container->addCompilerPass(new RuntimeLoaderPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new OverriddenBundlePathPass(), PassConfig::TYPE_BEFORE_REMOVING);
}

public function registerCommands(Application $application)
Expand Down