This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php
Fabien Potencier 833909bd68 feature #26921 [DI][FrameworkBundle] Hide service ids that start with a dot (nicolas-grekas)
This PR was merged into the 4.1-dev branch.

Discussion
----------

[DI][FrameworkBundle] Hide service ids that start with a dot

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #26630
| License       | MIT
| Doc PR        | -

Now that services are private by default, `debug:container` should display them by default.
In fact, the public/private concept should not trigger a difference in visibility for this command.

Instead, I propose to handle service ids that start with a dot as hidden services.

PR should be ready.

(For reference, I tried using a tag instead in #26891, but that doesn't work in practice when working on the implementation.)

Commits
-------

cea051ee5e [DI][FrameworkBundle] Hide service ids that start with a dot
2018-04-20 15:23:35 +02:00

161 lines
6.1 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ChildDefinition;
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.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ResolveInstanceofConditionalsPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
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));
}
}
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition instanceof ChildDefinition) {
// don't apply "instanceof" to children: it will be applied to their parent
continue;
}
$container->setDefinition($id, $this->processDefinition($container, $id, $definition));
}
}
private function processDefinition(ContainerBuilder $container, $id, Definition $definition)
{
$instanceofConditionals = $definition->getInstanceofConditionals();
$autoconfiguredInstanceof = $definition->isAutoconfigured() ? $container->getAutoconfiguredInstanceof() : array();
if (!$instanceofConditionals && !$autoconfiguredInstanceof) {
return $definition;
}
if (!$class = $container->getParameterBag()->resolveValue($definition->getClass())) {
return $definition;
}
$conditionals = $this->mergeConditionals($autoconfiguredInstanceof, $instanceofConditionals, $container);
$definition->setInstanceofConditionals(array());
$parent = $shared = null;
$instanceofTags = array();
$instanceofCalls = array();
foreach ($conditionals as $interface => $instanceofDefs) {
if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
continue;
}
if ($interface !== $class && !is_subclass_of($class, $interface)) {
continue;
}
foreach ($instanceofDefs as $key => $instanceofDef) {
/** @var ChildDefinition $instanceofDef */
$instanceofDef = clone $instanceofDef;
$instanceofDef->setAbstract(true)->setParent($parent ?: '.abstract.instanceof.'.$id);
$parent = '.instanceof.'.$interface.'.'.$key.'.'.$id;
$container->setDefinition($parent, $instanceofDef);
$instanceofTags[] = $instanceofDef->getTags();
foreach ($instanceofDef->getMethodCalls() as $methodCall) {
$instanceofCalls[] = $methodCall;
}
$instanceofDef->setTags(array());
$instanceofDef->setMethodCalls(array());
if (isset($instanceofDef->getChanges()['shared'])) {
$shared = $instanceofDef->isShared();
}
}
}
if ($parent) {
$bindings = $definition->getBindings();
$abstract = $container->setDefinition('.abstract.instanceof.'.$id, $definition);
// cast Definition to ChildDefinition
$definition->setBindings(array());
$definition = serialize($definition);
$definition = substr_replace($definition, '53', 2, 2);
$definition = substr_replace($definition, 'Child', 44, 0);
/** @var ChildDefinition $definition */
$definition = unserialize($definition);
$definition->setParent($parent);
if (null !== $shared && !isset($definition->getChanges()['shared'])) {
$definition->setShared($shared);
}
$i = count($instanceofTags);
while (0 <= --$i) {
foreach ($instanceofTags[$i] as $k => $v) {
foreach ($v as $v) {
if ($definition->hasTag($k) && in_array($v, $definition->getTag($k))) {
continue;
}
$definition->addTag($k, $v);
}
}
}
$definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls()));
// reset fields with "merge" behavior
$abstract
->setBindings($bindings)
->setArguments(array())
->setMethodCalls(array())
->setDecoratedService(null)
->setTags(array())
->setAbstract(true);
}
return $definition;
}
private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container)
{
// make each value an array of ChildDefinition
$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($autoconfiguredInstanceof[$interface])) {
$conditionals[$interface] = array();
}
$conditionals[$interface][] = $instanceofDef;
}
return $conditionals;
}
}