8000 Not allowing autoconfigure, instanceofConditionals or defaults for ChildDefinition by weaverryan · Pull Request #22563 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Not allowing autoconfigure, instanceofConditionals or defaults for ChildDefinition #22563

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
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
17 changes: 17 additions & 0 deletions src/Symfony/Component/DependencyInjection/ChildDefinition.php
10000
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;

Expand Down Expand Up @@ -134,6 +135,22 @@ public function replaceArgument($index, $value)

return $this;
}

/**
* @internal
*/
public function setAutoconfigured($autoconfigured)
{
throw new BadMethodCallException('A ChildDefinition cannot be autoconfigured.');
}

/**
* @internal
*/
public function setInstanceofConditionals(array $instanceof)
{
throw new BadMethodCallException('A ChildDefinition cannot have instanceof conditionals set on it.');
}
}

class_alias(ChildDefinition::class, DefinitionDecorator::class);
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ private function doResolveDefinition(ChildDefinition $definition)
$def->setPublic($parentDef->isPublic());
$def->setLazy($parentDef->isLazy());
$def->setAutowired($parentDef->isAutowired());
$def->setAutoconfigured($parentDef->isAutoconfigured());
$def->setChanges($parentDef->getChanges());

// overwrite with values specified in the decorator
Expand Down Expand Up @@ -130,9 +129,6 @@ private function doResolveDefinition(ChildDefinition $definition)
if (isset($changes['autowired'])) {
$def->setAutowired($definition->isAutowired());
}
if (isset($changes['autoconfigured'])) {
$def->setAutoconfigured($definition->isAutoconfigured());
}
if (isset($changes['shared'])) {
$def->setShared($definition->isShared());
}
Expand Down Expand Up @@ -174,6 +170,9 @@ private function doResolveDefinition(ChildDefinition $definition)
// these attributes are always taken from the child
$def->setAbstract($definition->isAbstract());
$def->setTags($definition->get 6D47 Tags());
// autoconfigure is never taken from parent (on purpose)
// and it's not legal on an instanceof
$def->setAutoconfigured($definition->isAutoconfigured());

return $def;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;

/**
* Applies instanceof conditionals to definitions.
Expand All @@ -28,6 +29,15 @@ class ResolveInstanceofConditionalsPass implements CompilerPassInterface
*/
public function process(ContainerBuilder $container)
{
foreach ($container->getAutoconfiguredInstanceof() as $interface => $definition) {
if ($definition->getArguments()) {
throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface));
}
if ($definition->getMethodCalls()) {
throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines method calls but these are not supported and should be removed.', $interface));
}
}

foreach ($container->getDefinitions() as $id => $definition) {
if ($definition instanceof ChildDefinition) {
// don't apply "instanceof" to children: it will be applied to their parent
Expand All @@ -40,16 +50,16 @@ public function process(ContainerBuilder $container)
private function processDefinition(ContainerBuilder $container, $id, Definition $definition)
{
$instanceofConditionals = $definition->getInstanceofConditionals();
$automaticInstanceofConditionals = $definition->isAutoconfigured() ? $container->getAutomaticInstanceofDefinitions() : array();
if (!$instanceofConditionals && !$automaticInstanceofConditionals) {
$autoconfiguredInstanceof = $definition->isAutoconfigured() ? $container->getAutoconfiguredInstanceof() : array();
if (!$instanceofConditionals && !$autoconfiguredInstanceof) {
return $definition;
}

if (!$class = $container->getParameterBag()->resolveValue($definition->getClass())) {
return $definition;
}

$conditionals = $this->mergeConditionals($automaticInstanceofConditionals, $instanceofConditionals, $container);
$conditionals = $this->mergeConditionals($autoconfiguredInstanceof, $instanceofConditionals, $container);

$definition->setInstanceofConditionals(array());
$parent = $shared = null;
Expand Down Expand Up @@ -113,18 +123,18 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
return $definition;
}

private function mergeConditionals(array $automaticInstanceofConditionals, array $instanceofConditionals, ContainerBuilder $container)
private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container)
{
// make each value an array of ChildDefinition
$conditionals = array_map(function ($childDef) { return array($childDef); }, $automaticInstanceofConditionals);
$conditionals = array_map(function ($childDef) { return array($childDef); }, $autoconfiguredInstanceof);

foreach ($instanceofConditionals as $interface => $instanceofDef) {
// make sure the interface/class exists (but don't validate automaticInstanceofConditionals)
if (!$container->getReflectionClass($interface)) {
throw new RuntimeException(sprintf('"%s" is set as an "instanceof" conditional, but it does not exist.', $interface));
}

if (!isset($automaticInstanceofConditionals[$interface])) {
if (!isset($autoconfiguredInstanceof[$interface])) {
$conditionals[$interface] = array();
}

Expand Down
19 changes: 10 additions & 9 deletions src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private $vendors;

private $automaticInstanceofDefinitions = array();
private $autoconfiguredInstanceof = array();

public function __construct(ParameterBagInterface $parameterBag = null)
{
Expand Down Expand Up @@ -641,12 +641,12 @@ public function merge(ContainerBuilder $container)
}
}

foreach ($container->getAutomaticInstanceofDefinitions() as $interface => $childDefinition) {
if (isset($this->automaticInstanceofDefinitions[$interface])) {
foreach ($container->getAutoconfiguredInstanceof() as $interface => $childDefinition) {
if (isset($this->autoconfiguredInstanceof[$interface])) {
throw new InvalidArgumentException(sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.', $interface));
}

$this->automaticInstanceofDefinitions[$interface] = $childDefinition;
$this->autoconfiguredInstanceof[$interface] = $childDefinition;
}
}

Expand Down Expand Up @@ -1272,25 +1272,26 @@ public function getExpressionLanguageProviders()
* Returns a ChildDefinition that will be used for autoconfiguring the interface/class.
*
* @param string $interface The class or interface to match
*
* @return ChildDefinition
*/
public function registerForAutoconfiguration($interface)
{
if (!isset($this->automaticInstanceofDefinitions[$interface])) {
$this->automaticInstanceofDefinitions[$interface] = new ChildDefinition('');
if (!isset($this->autoconfiguredInstanceof[$interface])) {
$this->autoconfiguredInstanceof[$interface] = new ChildDefinition('');
}

return $this->automaticInstanceofDefinitions[$interface];
return $this->autoconfiguredInstanceof[$interface];
}

/**
* Returns an array of ChildDefinition[] keyed by interface.
*
* @return ChildDefinition[]
*/
public function getAutomaticInstanceofDefinitions()
public function getAutoconfiguredInstanceof()
{
return $this->automaticInstanceofDefinitions;
return $this->autoconfiguredInstanceof;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ protected function setDefinition($id, Definition $definition)
}
$this->instanceof[$id] = $definition;
} else {
$this->container->setDefinition($id, $definition->setInstanceofConditionals($this->instanceof));
$this->container->setDefinition($id, $definition instanceof ChildDefinition ? $definition : $definition->setInstanceofConditionals($this->instanceof));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults =
if ($this->isLoadingInstanceof) {
$definition = new ChildDefinition('');
} elseif ($parent = $service->getAttribute('parent')) {
if (!empty($this->instanceof)) {
throw new InvalidArgumentException(sprintf('The service "%s" cannot use the "parent" option in the same file where "instanceof" configuration is defined as using both is not supported. Try moving your child definitions to a different file.', $service->getAttribute('id')));
}

if (!empty($defaults)) {
throw new InvalidArgumentException(sprintf('The service "%s" cannot use the "parent" option in the same file where "defaults" configuration is defined as using both is not supported. Try moving your child definitions to a different file.', $service->getAttribute('id')));
}

$definition = new ChildDefinition($parent);

if ($value = $service->getAttribute('inherit-tags')) {
Expand Down Expand Up @@ -255,7 +263,11 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults =
}

if ($value = $service->getAttribute('autoconfigure')) {
$definition->setAutoconfigured(XmlUtils::phpize($value));
if (!$definition instanceof ChildDefinition) {
$definition->setAutoconfigured(XmlUtils::phpize($value));
} elseif ($value = XmlUtils::phpize($value)) {
throw new InvalidArgumentException(sprintf('The service "%s" cannot have a "parent" and also have "autoconfigure". Try setting autoconfigure="false" for the service.', $service->getAttribute('id')));
}
}

if ($files = $this->getChildren($service, 'file')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ class YamlFileLoader extends FileLoader
'calls' => 'calls',
'tags' => 'tags',
'autowire' => 'autowire',
'autoconfigure' => 'autoconfigure',
);

private static $defaultsKeywords = array(
Expand Down Expand Up @@ -357,6 +356,14 @@ private function parseDefinition($id, $service, $file, array $defaults)
if ($this->isLoadingInstanceof) {
$definition = new ChildDefinition('');
} elseif (isset($service['parent'])) {
if (!empty($this->instanceof)) {
throw new InvalidArgumentException(sprintf('The service "%s" cannot use the "parent" option in the same file where "_instanceof" configuration is defined as using both is not supported. Try moving your child definitions to a different file.', $id));
}

if (!empty($defaults)) {
throw new InvalidArgumentException(sprintf('The service "%s" cannot use the "parent" option in the same file where "_defaults" configuration is defined as using both is not supported. Try moving your child definitions to a different file.', $id));
}

$definition = new ChildDefinition($service['parent']);

$inheritTag = isset($service['inherit_tags']) ? $service['inherit_tags'] : (isset($defaults['inherit_tags']) ? $defaults['inherit_tags'] : null);
Expand Down Expand Up @@ -518,7 +525,11 @@ private function parseDefinition($id, $service, $file, array $defaults)
}

if (isset($service['autoconfigure'])) {
$definition->setAutoconfigured($service['autoconfigure']);
if (!$definition instanceof ChildDefinition) {
$definition->setAutoconfigured($service['autoconfigure']);
} elseif ($service['autoconfigure']) {
throw new InvalidArgumentException(sprintf('The service "%s" cannot have a "parent" and also have "autoconfigure". Try setting "autoconfigure: false" for the service.', $id));
}
}

if (array_key_exists('resource', $service)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,22 @@ public function testDefinitionDecoratorAliasExistsForBackwardsCompatibility()
{
$this->assertInstanceOf(ChildDefinition::class, new DefinitionDecorator('foo'));
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\BadMethodCallException
*/
public function testCannotCallSetAutoconfigured()
{
$def = new ChildDefinition('foo');
$def->setAutoconfigured(true);
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\BadMethodCallException
*/
public function testCannotCallSetInstanceofConditionals()
{
$def = new ChildDefinition('foo');
$def->setInstanceofConditionals(array('Foo' => new ChildDefinition('')));
}
}
Loading
0