Skip to content

Commit

Permalink
[FrameworkBundle] Fix config builder with extensions extended in `bui…
Browse files Browse the repository at this point in the history
…ld()`
  • Loading branch information
HypeMC committed Feb 19, 2024
1 parent 8306a88 commit 413c495
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@ public function __construct(KernelInterface $kernel, ?LoggerInterface $logger =
*/
public function warmUp(string $cacheDir)
{
$generator = new ConfigBuilderGenerator($this->kernel->getBuildDir());
/** @var ContainerBuilder $container */
$container = \Closure::bind(function (KernelInterface $kernel) {
$containerBuilder = $kernel->getContainerBuilder();

Check failure on line 52 in src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php:52:42: UndefinedInterfaceMethod: Method Symfony\Component\HttpKernel\KernelInterface::getContainerBuilder does not exist (see https://psalm.dev/181)

Check failure on line 52 in src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php:52:42: UndefinedInterfaceMethod: Method Symfony\Component\HttpKernel\KernelInterface::getContainerBuilder does not exist (see https://psalm.dev/181)
$kernel->prepareContainer($containerBuilder);

Check failure on line 53 in src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php:53:22: UndefinedInterfaceMethod: Method Symfony\Component\HttpKernel\KernelInterface::prepareContainer does not exist (see https://psalm.dev/181)

Check failure on line 53 in src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php:53:22: UndefinedInterfaceMethod: Method Symfony\Component\HttpKernel\KernelInterface::prepareContainer does not exist (see https://psalm.dev/181)

foreach ($this->kernel->getBundles() as $bundle) {
$extension = $bundle->getContainerExtension();
if (null === $extension) {
continue;
}
return $containerBuilder;
}, null, $this->kernel)($this->kernel);

$generator = new ConfigBuilderGenerator($this->kernel->getBuildDir());

foreach ($container->getExtensions() as $extension) {
try {
$this->dumpExtension($extension, $generator);
} catch (\Exception $e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@
use Symfony\Bundle\FrameworkBundle\CacheWarmer\ConfigBuilderCacheWarmer;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\Kernel;

class ConfigBuilderCacheWarmerTest extends TestCase
Expand All @@ -38,41 +45,248 @@ protected function tearDown(): void

public function testBuildDirIsUsedAsConfigBuilderOutputDir()
{
$kernel = new class($this->varDir) extends Kernel {
private $varDir;
$kernel = new TestKernel($this->varDir);
$kernel->boot();

$warmer = new ConfigBuilderCacheWarmer($kernel);
$warmer->warmUp($kernel->getCacheDir());

self::assertDirectoryExists($kernel->getBuildDir().'/Symfony');
self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony');
}

public function __construct(string $varDir)
public function testExtensionAddedInKernel()
{
$kernel = new class($this->varDir) extends TestKernel {
protected function build(ContainerBuilder $container): void
{
parent::__construct('test', false);
$container->registerExtension(new class() extends Extension implements ConfigurationInterface {
public function load(array $configs, ContainerBuilder $container): void
{
}

public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('app');
$rootNode = $treeBuilder->getRootNode();

$rootNode
->children()
->scalarNode('provider')->end()
->end()
;

return $treeBuilder;
}

$this->varDir = $varDir;
public function getAlias(): string
{
return 'app';
}
});
}
};
$kernel->boot();

public function registerBundles(): iterable
$warmer = new ConfigBuilderCacheWarmer($kernel);
$warmer->warmUp($kernel->getCacheDir());

self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/AppConfig.php');
}

public function testKernelAsExtension()
{
$kernel = new class($this->varDir) extends TestKernel implements ExtensionInterface, ConfigurationInterface {
public function load(array $configs, ContainerBuilder $container): void
{
yield new FrameworkBundle();
}

public function getBuildDir(): string
public function getXsdValidationBasePath()
{
return $this->varDir.'/build';
return false;
}

public function getCacheDir(): string
public function getNamespace(): string
{
return $this->varDir.'/cache';
return 'http://www.example.com/schema/acme';
}

public function registerContainerConfiguration(LoaderInterface $loader)
public function getAlias(): string
{
return 'kernel';
}

public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('kernel');
$rootNode = $treeBuilder->getRootNode();

$rootNode
->children()
->scalarNode('provider')->end()
->end()
;

return $treeBuilder;
}
};
$kernel->boot();

$warmer = new ConfigBuilderCacheWarmer($kernel);
$warmer->warmUp($kernel->getCacheDir());

self::assertDirectoryExists($kernel->getBuildDir().'/Symfony');
self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/KernelConfig.php');
}

public function testExtensionsExtendedInBuildMethods()
{
$kernel = new class($this->varDir) extends TestKernel {
protected function build(ContainerBuilder $container): void
{
/** @var TestSecurityExtension $extension */
$extension = $container->getExtension('test_security');
$extension->addAuthenticatorFactory(new class() implements TestAuthenticatorFactoryInterface {
public function getKey(): string
{
return 'token';
}

public function addConfiguration(NodeDefinition $node): void
{
}
});
}

public function registerBundles(): iterable
{
yield from parent::registerBundles();

yield new class() extends Bundle {
public function getContainerExtension(): ExtensionInterface
{
return new TestSecurityExtension();
}
};

yield new class() extends Bundle {
public function build(ContainerBuilder $container): void
{
/** @var TestSecurityExtension $extension */
$extension = $container->getExtension('test_security');
$extension->addAuthenticatorFactory(new class() implements TestAuthenticatorFactoryInterface {
public function getKey(): string
{
return 'form-login';
}

public function addConfiguration(NodeDefinition $node): void
{
$node
->children()
->scalarNode('provider')->end()
->end()
;
}
});
}
};
}
};
$kernel->boot();

$warmer = new ConfigBuilderCacheWarmer($kernel);
$warmer->warmUp($kernel->getCacheDir());

self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/SecurityConfig.php');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig.php');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig/FormLoginConfig.php');
self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig/TokenConfig.php');
}
}

class TestKernel extends Kernel
{
private $varDir;

public function __construct(string $varDir)
{
parent::__construct('test', false);

$this->varDir = $varDir;
}

public function registerBundles(): iterable
{
yield new FrameworkBundle();
}

public function getBuildDir(): string
{
return $this->varDir.'/build';
}

public function getCacheDir(): string
{
return $this->varDir.'/cache';
}

public function registerContainerConfiguration(LoaderInterface $loader): void
{
}
}

interface TestAuthenticatorFactoryInterface
{
public function getKey(): string;

public function addConfiguration(NodeDefinition $builder): void;
}

class TestSecurityExtension extends Extension implements ConfigurationInterface
{
/** @var TestAuthenticatorFactoryInterface[] */
private $factories;

public function load(array $configs, ContainerBuilder $container): void
{
}

public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface
{
return $this;
}

public function addAuthenticatorFactory(TestAuthenticatorFactoryInterface $factory): void
{
$this->factories[] = $factory;
}

public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('security');
$rootNode = $treeBuilder->getRootNode();

$firewallNodeBuilder = $rootNode
->fixXmlConfig('firewall')
->children()
->arrayNode('firewalls')
->isRequired()
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->prototype('array')
->children()
;

foreach ($this->factories as $factory) {
$name = str_replace('-', '_', $factory->getKey());
$factoryNode = $firewallNodeBuilder->arrayNode($name);

$factory->addConfiguration($factoryNode);
}

return $treeBuilder;
}
}

0 comments on commit 413c495

Please sign in to comment.