-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DI] Add "inherit-tags" with configurable defaults + same for "public", "tags" & "autowire" #21071
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,6 +52,7 @@ class YamlFileLoader extends FileLoader | |
'configurator' => 'configurator', | ||
'calls' => 'calls', | ||
'tags' => 'tags', | ||
'inherit_tags' => 'inherit_tags', | ||
'decorates' => 'decorates', | ||
'decoration_inner_name' => 'decoration_inner_name', | ||
'decoration_priority' => 'decoration_priority', | ||
|
@@ -148,9 +149,56 @@ private function parseDefinitions($content, $file) | |
if (!is_array($content['services'])) { | ||
throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file)); | ||
} | ||
if (isset($content['services']['_defaults'])) { | ||
if (!is_array($defaults = $content['services']['_defaults'])) { | ||
throw new InvalidArgumentException(sprintf('Service defaults must be an array, "%s" given in "%s".', gettype($defaults), $file)); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would validate the default value for |
||
if (isset($defaults['alias']) || isset($defaults['class']) || isset($defaults['factory'])) { | ||
@trigger_error('Giving a service the "_defaults" name is deprecated since Symfony 3.3 and will be forbidden in 4.0. Rename your service.', E_USER_DEPRECATED); | ||
$defaults = array(); | ||
} else { | ||
$defaultKeys = array('public', 'tags', 'inherit_tags', 'autowire'); | ||
unset($content['services']['_defaults']); | ||
|
||
foreach ($defaults as $key => $default) { | ||
if (!in_array($key, $defaultKeys)) { | ||
throw new InvalidArgumentException(sprintf('The configuration key "%s" cannot be used to define a default value in "%s". Allowed keys are "%s".', $key, $file, implode('", "', $defaultKeys))); | ||
} | ||
} | ||
if (isset($defaults['tags'])) { | ||
if (!is_array($tags = $defaults['tags'])) { | ||
throw new InvalidArgumentException(sprintf('Parameter "tags" in "_defaults" must be an array in %s. Check your YAML syntax.', $file)); | ||
} | ||
|
||
foreach ($tags as $tag) { | ||
if (!is_array($tag)) { | ||
$tag = array('name' => $tag); | ||
} | ||
|
||
if (!isset($tag['name'])) { | ||
throw new InvalidArgumentException(sprintf('A "tags" entry in "_defaults" is missing a "name" key in %s.', $file)); | ||
} | ||
$name = $tag['name']; | ||
unset($tag['name']); | ||
|
||
if (!is_string($name) || '' === $name) { | ||
throw new InvalidArgumentException(sprintf('The tag name in "_defaults" must be a non-empty string in %s.', $file)); | ||
} | ||
|
||
foreach ($tag as $attribute => $value) { | ||
if (!is_scalar($value) && null !== $value) { | ||
throw new InvalidArgumentException(sprintf('Tag "%s", attribute "%s" in "_defaults" must be of a scalar-type in %s. Check your YAML syntax.', $name, $attribute, $file)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
$defaults = array(); | ||
} | ||
|
||
foreach ($content['services'] as $id => $service) { | ||
$this->parseDefinition($id, $service, $file); | ||
$this->parseDefinition($id, $service, $file, $defaults); | ||
} | ||
} | ||
|
||
|
@@ -160,10 +208,11 @@ private function parseDefinitions($content, $file) | |
* @param string $id | ||
* @param array $service | ||
* @param string $file | ||
* @param array $defaults | ||
* | ||
* @throws InvalidArgumentException When tags are invalid | ||
*/ | ||
private function parseDefinition($id, $service, $file) | ||
private function parseDefinition($id, $service, $file, array $defaults) | ||
{ | ||
if (is_string($service) && 0 === strpos($service, '@')) { | ||
$this->container->setAlias($id, substr($service, 1)); | ||
|
@@ -178,7 +227,7 @@ private function parseDefinition($id, $service, $file) | |
static::checkDefinition($id, $service, $file); | ||
|
||
if (isset($service['alias'])) { | ||
$public = !array_key_exists('public', $service) || (bool) $service['public']; | ||
$public = array_key_exists('public', $service) ? (bool) $service['public'] : !empty($defaults['public']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason to define this variable twice? One doing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these are not on the same path, and don't have the same semantic (don't forget about ChildDefinition on the other path.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had services defined: (Symfony 3.1.8): foo:
class: My\FooService
bar:
alias: foo I could access Shouldn't this be mentioned somewhere? I couldn't find any info about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. That's a bug. See #21219 |
||
$this->container->setAlias($id, new Alias($service['alias'], $public)); | ||
|
||
foreach ($service as $key => $value) { | ||
|
@@ -192,6 +241,12 @@ private function parseDefinition($id, $service, $file) | |
|
||
if (isset($service['parent'])) { | ||
$definition = new ChildDefinition($service['parent']); | ||
|
||
$inheritTag = isset($service['inherit_tags']) ? $service['inherit_tags'] : (isset($defaults['inherit_tags']) ? $defaults['inherit_tags'] : null); | ||
if (null !== $inheritTag) { | ||
$definition->setInheritTags($inheritTag); | ||
} | ||
$defaults = array(); | ||
} else { | ||
$definition = new Definition(); | ||
} | ||
|
@@ -212,8 +267,9 @@ private function parseDefinition($id, $service, $file) | |
$definition->setLazy($service['lazy']); | ||
} | ||
|
||
if (isset($service['public'])) { | ||
$definition->setPublic($service['public']); | ||
$public = isset($service['public']) ? $service['public'] : (isset($defaults['public']) ? $defaults['public'] : null); | ||
if (null !== $public) { | ||
$definition->setPublic($public); | ||
} | ||
|
||
if (isset($service['abstract'])) { | ||
|
@@ -262,27 +318,38 @@ private function parseDefinition($id, $service, $file) | |
} | ||
} | ||
|
||
if (isset($service['tags'])) { | ||
if (!is_array($service['tags'])) { | ||
$tags = isset($service['tags']) ? $service['tags'] : array(); | ||
|
||
if (!isset($defaults['tags'])) { | ||
// no-op | ||
} elseif (!isset($service['inherit_tags'])) { | ||
if (!isset($service['tags'])) { | ||
$tags = $defaults['tags']; | ||
} | ||
} elseif ($service['inherit_tags']) { | ||
$tags = array_merge($tags, $defaults['tags']); | ||
} | ||
|
||
if (null !== $tags) { | ||
if (!is_array($tags)) { | ||
throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); | ||
} | ||
|
||
foreach ($service['tags'] as $tag) { | ||
foreach ($tags as $tag) { | ||
if (!is_array($tag)) { | ||
$tag = array('name' => $tag); | ||
} | ||
|
||
if (!isset($tag['name'])) { | ||
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file)); | ||
} | ||
$name = $tag['name']; | ||
unset($tag['name']); | ||
|
||
if (!is_string($tag['name']) || '' === $tag['name']) { | ||
if (!is_string($name) || '' === $name) { | ||
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file)); | ||
} | ||
|
||
$name = $tag['name']; | ||
unset($tag['name']); | ||
|
||
foreach ($tag as $attribute => $value) { | ||
if (!is_scalar($value) && null !== $value) { | ||
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your YAML syntax.', $id, $name, $attribute, $file)); | ||
|
@@ -303,11 +370,12 @@ private function parseDefinition($id, $service, $file) | |
$definition->setDecoratedService($service['decorates'], $renameId, $priority); | ||
} | ||
|
||
if (isset($service['autowire'])) { | ||
if (is_array($service['autowire'])) { | ||
$definition->setAutowiredMethods($service['autowire']); | ||
$autowire = isset($service['autowire']) ? $service['autowire'] : (isset($defaults['autowire']) ? $defaults['autowire'] : null); | ||
if (null !== $autowire) { | ||
if (is_array($autowire)) { | ||
$definition->setAutowiredMethods($autowire); | ||
} else { | ||
$definition->setAutowired($service['autowire']); | ||
$definition->setAutowired($autowire); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we check whether the array contains extra keys likely to be used by a real service, and treat it as a service instead in this case (but with a deprecation warning) ? I would say that
alias
,class
andfactory
would cover itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with deprecation. Other comments addressed also.