8000 [DependencyInjection] Add ContainerBuilder::willBeAvailable() to help with conditional configuration by nicolas-grekas · Pull Request #40140 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DependencyInjection] Add ContainerBuilder::willBeAvailable() to help with conditional configuration #40140

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

Merged
merged 1 commit into from
Feb 25, 2021
Merged
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
Expand Up @@ -13,7 +13,6 @@

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;

/**
* DebugExtension configuration structure.
Expand Down Expand Up @@ -51,21 +50,13 @@ public function getConfigTreeBuilder()
->example('php://stderr, or tcp://%env(VAR_DUMPER_SERVER)% when using the "server:dump" command')
->defaultNull()
->end()
->end()
;

if (method_exists(HtmlDumper::class, 'setTheme')) {
$rootNode
->children()
->enumNode('theme')
->info('Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light"')
->example('dark')
->values(['dark', 'light'])
->defaultValue('dark')
->end()
->enumNode('theme')
->info('Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light"')
->example('dark')
->values(['dark', 'light'])
->defaultValue('dark')
->end()
;
}

return $treeBuilder;
}
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ protected static function getBundleDefaultConfig()
'mapping' => ['paths' => []],
],
'property_access' => [
'enabled' => true,
'magic_call' => false,
'magic_get' => true,
'magic_set' => true,
Expand Down Expand Up @@ -566,7 +567,7 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
'limiters' => [],
],
'uid' => [
'enabled' => class_exists(UuidFactory::class),
'enabled' => !class_exists(FullStack::class) && class_exists(UuidFactory::class),
'default_uuid_version' => 6,
'name_based_uuid_version' => 5,
'time_based_uuid_version' => 6,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Bundle\SecurityBundle\DependencyInjection;

use Symfony\Bridge\Twig\Extension\LogoutUrlExtension;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\FirewallListenerFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory;
Expand All @@ -31,6 +32,7 @@
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\PasswordHasher\Hasher\NativePasswordHasher;
use Symfony\Component\PasswordHasher\Hasher\Pbkdf2PasswordHasher;
Expand All @@ -42,7 +44,6 @@
use Symfony\Component\Security\Core\User\ChainUserProvider;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
use Twig\Extension\AbstractExtension;

/**
* SecurityExtension.
Expand Down Expand Up @@ -130,7 +131,7 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('security_legacy.php');
}

if (class_exists(AbstractExtension::class)) {
if ($container::willBeAvailable('symfony/twig-bridge', LogoutUrlExtension::class, ['symfony/security-bundle'])) {
$loader->load('templating_twig.php');
}

Expand All @@ -141,7 +142,7 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('security_debug.php');
}

if (!class_exists(\Symfony\Component\ExpressionLanguage\ExpressionLanguage::class)) {
if (!$container::willBeAvailable('symfony/expression-language', ExpressionLanguage::class, ['symfony/security-bundle'])) {
$container->removeDefinition('security.expression_language');
$container->removeDefinition('security.access.expression_voter');
}
Expand Down Expand Up @@ -982,8 +983,8 @@ private function createExpression(ContainerBuilder $container, string $expressio
return $this->expressions[$id];
}

if (!class_exists(\Symfony\Component\ExpressionLanguage\ExpressionLanguage::class)) {
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
if (!$container::willBeAvailable('symfony/expression-language', ExpressionLanguage::class, ['symfony/security-bundle'])) {
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
}

$container
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/SecurityBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"php": ">=7.2.5",
"ext-xml": "*",
"symfony/config": "^4.4|^5.0",
"symfony/dependency-injection": "^5.2",
"symfony/dependency-injection": "^5.3",
"symfony/deprecation-contracts": "^2.1",
"symfony/event-dispatcher": "^5.1",
"symfony/http-kernel": "^5.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@

namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;

use Symfony\Component\Asset\Packages;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Yaml\Yaml;

/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
Expand All @@ -23,19 +27,19 @@ class ExtensionPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!class_exists(\Symfony\Component\Asset\Packages::class)) {
if (!$container::willBeAvailable('symfony/asset', Packages::class, ['symfony/twig-bundle'])) {
$container->removeDefinition('twig.extension.assets');
}

if (!class_exists(\Symfony\Component\ExpressionLanguage\Expression::class)) {
if (!$container::willBeAvailable('symfony/expression-language', Expression::class, ['symfony/twig-bundle'])) {
$container->removeDefinition('twig.extension.expression');
}

if (!interface_exists(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class)) {
if (!$container::willBeAvailable('symfony/routing', UrlGeneratorInterface::class, ['symfony/twig-bundle'])) {
$container->removeDefinition('twig.extension.routing');
}

if (!class_exists(\Symfony\Component\Yaml\Yaml::class)) {
if (!$container::willBeAvailable('symfony/yaml', Yaml::class, ['symfony/twig-bundle'])) {
$container->removeDefinition('twig.extension.yaml');
}

Expand Down Expand Up @@ -111,7 +115,7 @@ public function process(ContainerBuilder $container)
$container->getDefinition('twig.extension.expression')->addTag('twig.extension');
}

if (!class_exists(Workflow::class) || !$container->has('workflow.registry')) {
if (!$container::willBeAvailable('symfony/workflow', Workflow::class, ['symfony/twig-bundle']) || !$container->has('workflow.registry')) {
$container->removeDefinition('workflow.twig_extension');
} else {
$container->getDefinition('workflow.twig_extension')->addTag('twig.extension');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Translation\Translator;
Expand All @@ -37,19 +38,19 @@ public function load(array $configs, ContainerBuilder $container)
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('twig.php');

if (class_exists(\Symfony\Component\Form\Form::class)) {
if ($container::willBeAvailable('symfony/form', Form::class, ['symfony/twig-bundle'])) {
$loader->load('form.php');
}

if (class_exists(Application::class)) {
if ($container::willBeAvailable('symfony/console', Application::class, ['symfony/twig-bundle'])) {
$loader->load('console.php');
}

if (class_exists(Mailer::class)) {
if ($container::willBeAvailable('symfony/mailer', Mailer::class, ['symfony/twig-bundle'])) {
$loader->load('mailer.php');
}

if (!class_exists(Translator::class)) {
if (!$container::willBeAvailable('symfony/translation', Translator::class, ['symfony/twig-bundle'])) {
$container->removeDefinition('twig.translation.extractor');
}

Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bundle/TwigBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"require-dev": {
"symfony/asset": "^4.4|^5.0",
"symfony/stopwatch": "^4.4|^5.0",
"symfony/dependency-injection": "^5.2",
"symfony/dependency-injection": "^5.3",
"symfony/expression-language": "^4.4|^5.0",
"symfony/finder": "^4.4|^5.0",
"symfony/form": "^4.4|^5.0",
Expand All @@ -40,7 +40,7 @@
"doctrine/cache": "~1.0"
},
"conflict": {
"symfony/dependency-injection": "<5.2",
"symfony/dependency-injection": "<5.3",
"symfony/framework-bundle": "<5.0",
"symfony/translation": "<5.0"
},
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CHANGELOG
* Add support for loading autoconfiguration rules via the `#[Autoconfigure]` and `#[AutoconfigureTag]` attributes on PHP 8
* Add autoconfigurable attributes
* Add support for per-env configuration in loaders
* Add `ContainerBuilder::willBeAvailable()` to help with conditional configuration

5.2.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private function getExpressionLanguage(): ExpressionLanguage
{
if (null === $this->expressionLanguage) {
if (!class_exists(ExpressionLanguage::class)) {
throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
}

$providers = $this->container->getExpressionLanguageProviders();
Expand Down
29 changes: 29 additions & 0 deletions src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\DependencyInjection;

use Composer\InstalledVersions;
use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\Config\Resource\ClassExistenceResource;
use Symfony\Component\Config\Resource\ComposerResource;
Expand Down Expand Up @@ -1467,6 +1468,34 @@ public function log(CompilerPassInterface $pass, string $message)
$this->getCompiler()->log($pass, $this->resolveEnvPlaceholders($message));
}

/**
* Checks whether a class is available and will remain available in the "no-dev" mode of Composer.
*
* When parent packages are provided and if any of them is in dev-only mode,
* the class will be considered available even if it is also in dev-only mode.
*/
final public static function willBeAvailable(string $package, string $class, array $parentPackages): bool
{
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) {
return false;
}

if (!class_exists(InstalledVersions::class) || !InstalledVersions::isInstalled($package) || InstalledVersions::isInstalled($package, false)) {
return true;
}

// the package is installed but in dev-mode only, check if this applies to one of the parent packages too

$rootPackage = InstalledVersions::getRootPackage()['name'] ?? '';
foreach ($parentPackages as $parentPackage) {
if ($rootPackage === $parentPackage || (InstalledVersions::isInstalled($parentPackage) && !InstalledVersions::isInstalled($parentPackage, false))) {
return true;
}
}

return false;
}

/**
* Gets removed binding ids.
*
Expand Down
0