Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
feature #21530 [DependencyInjection] Add "instanceof" section for loc…
…al interface-defined configs (nicolas-grekas, dunglas) This PR was merged into the 3.3-dev branch. Discussion ---------- [DependencyInjection] Add "instanceof" section for local interface-defined configs | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This is a direction follow up of #21357 on which we're working together with @dunglas. From the description posted there: There is some work being done to include features of [DunglasActionBundle](https://github.com/dunglas/DunglasActionBundle) in the core of Symfony. The goal of all those PRs is to improve the developper experience of the framework, allow to develop faster while preserving all benefits of using Symfony (strictness, modularity, extensibility...) and make it easier to learn for newcomers. This PR implements the tagging feature of ActionBundle in a more generic way. It will help to get rid of `AppBundle` in the the standard edition and to register automatically some classes including commands. Here is an example of config (that can be embedded in the standard edition) to enable those features: ```yaml # config/services.yml services: _defaults: autowire: ['get*', 'set*'] # Enable constructor, getter and setter autowiring for all services defined in this file _instanceof: Symfony\Component\Console\Command: # Add the console.command tag to all services defined in this file having this type tags: ['console.command'] # Set tags but also other settings like "public", "autowire" or "shared" here Twig_ExtensionInterface: tags: ['twig.extension'] Symfony\Component\EventDispatcher\EventSubscriberInterface: tags: ['kernel.event_subscriber'] App\: # Register all classes in the src/Controller directory as services psr4: ../src/{Controller,Command,Twig,EventSubscriber} ``` It's part of our 0 config initiative: controllers and commands will be automatically registered as services and "autowired", allowing the user to create and inject new services without having to write a single line of YAML or XML. When refactoring changes are also automatically updated and don't require to update config files. It's a big win for rapid application development and prototyping. Of course, this is fully compatible with the actual way of defining services and it's possible to switch (or mix) approaches very easily. It's even possible to start prototyping using 0config features then switch to explicit services definitions when the project becomes mature. Commits ------- 773eca7 [DependencyInjection] Tests + refacto for "instanceof" definitions 2fb6019 [DependencyInjection] Add "instanceof" section for local interface-defined configs
- Loading branch information
Showing
15 changed files
with
367 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionInheritancePass.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?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\Definition; | ||
|
||
/** | ||
* Applies tags and instanceof inheritance to definitions. | ||
* | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class ResolveDefinitionInheritancePass extends AbstractRecursivePass | ||
{ | ||
protected function processValue($value, $isRoot = false) | ||
{ | ||
if (!$value instanceof Definition) { | ||
return parent::processValue($value, $isRoot); | ||
} | ||
if ($value instanceof ChildDefinition) { | ||
$this->resolveDefinition($value); | ||
} | ||
$class = $value->getClass(); | ||
if (!$class || false !== strpos($class, '%') || !$instanceof = $value->getInstanceofConditionals()) { | ||
return parent::processValue($value, $isRoot); | ||
} | ||
|
||
foreach ($instanceof as $interface => $definition) { | ||
if ($interface !== $class && (!$this->container->getReflectionClass($interface) || !$this->container->getReflectionClass($class))) { | ||
continue; | ||
} | ||
if ($interface === $class || is_subclass_of($class, $interface)) { | ||
$this->mergeDefinition($value, $definition); | ||
} | ||
} | ||
|
||
return parent::processValue($value, $isRoot); | ||
} | ||
|
||
/** | ||
* Populates the class and tags from parent definitions. | ||
*/ | ||
private function resolveDefinition(ChildDefinition $definition) | ||
{ | ||
if (!$this->container->has($parent = $definition->getParent())) { | ||
return; | ||
} | ||
|
||
$parentDef = $this->container->findDefinition($parent); | ||
if ($parentDef instanceof ChildDefinition) { | ||
$this->resolveDefinition($parentDef); | ||
} | ||
|
||
if (!isset($definition->getChanges()['class'])) { | ||
$definition->setClass($parentDef->getClass()); | ||
} | ||
|
||
// append parent tags when inheriting is enabled | ||
if ($definition->getInheritTags()) { | ||
foreach ($parentDef->getTags() as $k => $v) { | ||
foreach ($v as $v) { | ||
$definition->addTag($k, $v); | ||
} | ||
} | ||
} | ||
|
||
$definition->setInheritTags(false); | ||
} | ||
|
||
private function mergeDefinition(Definition $def, ChildDefinition $definition) | ||
{ | ||
$changes = $definition->getChanges(); | ||
if (isset($changes['shared'])) { | ||
$def->setShared($definition->isShared()); | ||
} | ||
if (isset($changes['abstract'])) { | ||
$def->setAbstract($definition->isAbstract()); | ||
} | ||
if (isset($changes['autowired_calls'])) { | ||
$autowiredCalls = $def->getAutowiredCalls(); | ||
} | ||
|
||
ResolveDefinitionTemplatesPass::mergeDefinition($def, $definition); | ||
|
||
// merge autowired calls | ||
if (isset($changes['autowired_calls'])) { | ||
$def->setAutowiredCalls(array_merge($autowiredCalls, $def->getAutowiredCalls())); | ||
} | ||
|
||
// merge tags | ||
foreach ($definition->getTags() as $k => $v) { | ||
foreach ($v as $v) { | ||
$def->addTag($k, $v); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.