Skip to content

Commit

Permalink
feature #52636 [DependencyInjection] Prepend extension config with `C…
Browse files Browse the repository at this point in the history
…ontainerConfigurator` (yceruto)

This PR was merged into the 7.1 branch.

Discussion
----------

[DependencyInjection] Prepend extension config with `ContainerConfigurator`

| Q             | A
| ------------- | ---
| Branch?       | 7.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

I found this by fixing an issue in a bundle that was trying to prepend extension configs using `$container->extension('namespace', [...])` in `AbstractBundle::prependExtension()`, which indeed was appending that config instead of prepending it. Most importantly, the append strategy requires the extension namespace to be loaded beforehand, which is not required when prepend is used.

This title DX improvement helps to avoid the confusion between `ContainerConfigurator $container` and `ContainerBuilder $builder` to prepend extension config by allowing `ContainerConfigurator` to do the same now.

Example:
```php
class AcmeFooBundle extends AbstractBundle
{
    public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
    {
        // Before (only way)
        $builder->prependExtensionConfig('namespace', ['foo' => 'bar']);

        // After (also this way) passing "true" as the 3rd parameter
        $container->extension('namespace', ['foo' => 'bar'], true);
    }
}
```
Instead of adding a new `$prepend` argument to the existing method, I could create a new method, e.g., `ContainerConfigurator::prependExtension()`. What do you prefer?

This also helps when you want to prepend several or large configs in your bundle or extension class. Actually, using just `$container->import('...')` doesn't work because internally it will always append the configs, unless you do the following hidden trick below.

```php
// acme-bundle/config/packages/configs.php
use Symfony\Component\DependencyInjection\ContainerBuilder;

return static function (ContainerBuilder $container) {
    $container->prependExtensionConfig('namespace', ['large' => 'config', ...]);
};
```
If you type `ContainerBuilder` instead of `ContainerConfigurator` in the external PHP config file, the builder instance will be passed instead, allowing you to use the `prependExtensionConfig()` method.

But with this proposal, it's simpler as you can keep using `ContainerConfigurator` to prepend extension configs without doing any tactic.

Commits
-------

137518d add argument to prepend extension config
  • Loading branch information
nicolas-grekas committed Nov 20, 2023
2 parents 19f5240 + 137518d commit 0693c5a
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.1
---

* Add argument `$prepend` to `ContainerConfigurator::extension()` to prepend the configuration instead of appending it

7.0
---

Expand Down
Expand Up @@ -48,8 +48,14 @@ public function __construct(ContainerBuilder $container, PhpFileLoader $loader,
$this->env = $env;
}

final public function extension(string $namespace, array $config): void
final public function extension(string $namespace, array $config, bool $prepend = false): void
{
if ($prepend) {
$this->container->prependExtensionConfig($namespace, static::processValue($config));

return;
}

if (!$this->container->hasExtension($namespace)) {
$extensions = array_filter(array_map(fn (ExtensionInterface $ext) => $ext->getAlias(), $this->container->getExtensions()));
throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $namespace, $this->file, $namespace, $extensions ? implode('", "', $extensions) : 'none'));
Expand Down
Expand Up @@ -63,7 +63,7 @@ public function prependExtension(ContainerConfigurator $container, ContainerBuil
$container->extension('third', ['foo' => 'append']);

// prepend config
$builder->prependExtensionConfig('third', ['foo' => 'prepend']);
$container->extension('third', ['foo' => 'prepend'], true);
}
};

Expand Down
Expand Up @@ -31,7 +31,7 @@ public function configure(DefinitionConfigurator $definition): void

public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
{
$container->extension('loaded', ['bar' => 'baz']);
$container->extension('loaded', ['bar' => 'baz'], true);
}

public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
Expand Down

0 comments on commit 0693c5a

Please sign in to comment.