feature #22234 [DI] Introducing autoconfigure: automatic _instanceof configuration (weaverryan)
This PR was squashed before being merged into the 3.3-dev branch (closes #22234). Discussion ---------- [DI] Introducing autoconfigure: automatic _instanceof configuration | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes (mostly, a continuation of a new feature) | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | https://github.com/symfony/symfony-docs/issues/7538 This is a proposal to allow the user to opt into some automatic `_instanceof` config. Suppose I want to auto-tag all of my voters and event subscribers ```yml # current services: _defaults: autowire: true _instanceof: Symfony\Component\Security\Core\Authorization\Voter\VoterInterface: tags: [security.voter] Symfony\Component\EventDispatcher\EventSubscriberInterface: tags: [kernel.event_subscriber] # services using the above tags AppBundle\Security\PostVoter: ~ AppBundle\EventListener\CheckRequirementsSubscriber: ~ ``` If I'm registering a service with a class that implements `VoterInterface`, when would I ever *not* want that to be tagged with `security.voter`? Here's the proposed code: ```yml # proposed services: _defaults: autowire: true autoconfigure: true # services using the auto_configure_instanceof functionality AppBundle\Security\PostVoter: ~ AppBundle\EventListener\CheckRequirementsSubscriber: ~ ``` The user must opt into this and it only applies locally to this configuration file. It works because each enabled bundle would have the opportunity to add one or more "automatic instanceof" definitions - e.g. SecurityBundle would add the `security.voter` instanceof config, FrameworkBundle would add the `kernel.event_subscriber` instanceof config, etc. For another example, you can check out the proposed changes to `symfony-demo` - symfony/symfony-demo#483 - the `_instanceof` section is pretty heavy:81694ac21e/app/config/services.yml (L20)
Thanks! Commits -------18627bf9f6
[DI] Introducing autoconfigure: automatic _instanceof configuration
This commit is contained in:
commit
f730ffae49
@ -222,6 +222,7 @@ class JsonDescriptor extends Descriptor
|
||||
'shared' => $definition->isShared(),
|
||||
'abstract' => $definition->isAbstract(),
|
||||
'autowire' => $definition->isAutowired(),
|
||||
'autoconfigure' => $definition->isAutoconfigured(),
|
||||
);
|
||||
|
||||
foreach ($definition->getAutowiringTypes(false) as $autowiringType) {
|
||||
|
@ -183,6 +183,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no')
|
||||
."\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no')
|
||||
."\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no')
|
||||
."\n".'- Autoconfigured: '.($definition->isAutoconfigured() ? 'yes' : 'no')
|
||||
;
|
||||
|
||||
foreach ($definition->getAutowiringTypes(false) as $autowiringType) {
|
||||
|
@ -372,6 +372,7 @@ class XmlDescriptor extends Descriptor
|
||||
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('autoconfigured', $definition->isAutoconfigured() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('file', $definition->getFile());
|
||||
|
||||
$calls = $definition->getMethodCalls();
|
||||
|
@ -13,30 +13,49 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Symfony\Bridge\Monolog\Processor\DebugProcessor;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Config\ResourceCheckerInterface;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Form\FormTypeGuesserInterface;
|
||||
use Symfony\Component\Form\FormTypeInterface;
|
||||
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessor;
|
||||
use Symfony\Component\Serializer\Encoder\YamlEncoder;
|
||||
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
||||
use Symfony\Component\Serializer\Encoder\CsvEncoder;
|
||||
use Symfony\Component\Serializer\Encoder\EncoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\YamlEncoder;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||
use Symfony\Component\Validator\ObjectInitializerInterface;
|
||||
use Symfony\Component\WebLink\HttpHeaderSerializer;
|
||||
use Symfony\Component\Workflow;
|
||||
|
||||
@ -225,6 +244,45 @@ class FrameworkExtension extends Extension
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller',
|
||||
));
|
||||
|
||||
$container->registerForAutoconfiguration(Command::class)
|
||||
->addTag('console.command');
|
||||
$container->registerForAutoconfiguration(ResourceCheckerInterface::class)
|
||||
->addTag('config_cache.resource_checker');
|
||||
$container->registerForAutoconfiguration(ServiceSubscriberInterface::class)
|
||||
->addTag('container.service_subscriber');
|
||||
$container->registerForAutoconfiguration(AbstractController::class)
|
||||
->addTag('controller.service_arguments');
|
||||
$container->registerForAutoconfiguration(Controller::class)
|
||||
->addTag('controller.service_arguments');
|
||||
$container->registerForAutoconfiguration(DataCollectorInterface::class)
|
||||
->addTag('data_collector');
|
||||
$container->registerForAutoconfiguration(FormTypeInterface::class)
|
||||
->addTag('form.type');
|
||||
$container->registerForAutoconfiguration(FormTypeGuesserInterface::class)
|
||||
->addTag('form.type_guesser');
|
||||
$container->registerForAutoconfiguration(CacheClearerInterface::class)
|
||||
->addTag('kernel.cache_clearer');
|
||||
$container->registerForAutoconfiguration(CacheWarmerInterface::class)
|
||||
->addTag('kernel.cache_warmer');
|
||||
$container->registerForAutoconfiguration(EventSubscriberInterface::class)
|
||||
->addTag('kernel.event_subscriber');
|
||||
$container->registerForAutoconfiguration(PropertyListExtractorInterface::class)
|
||||
->addTag('property_info.list_extractor');
|
||||
$container->registerForAutoconfiguration(PropertyTypeExtractorInterface::class)
|
||||
->addTag('property_info.type_extractor');
|
||||
$container->registerForAutoconfiguration(PropertyDescriptionExtractorInterface::class)
|
||||
->addTag('property_info.description_extractor');
|
||||
$container->registerForAutoconfiguration(PropertyAccessExtractorInterface::class)
|
||||
->addTag('property_info.access_extractor');
|
||||
$container->registerForAutoconfiguration(EncoderInterface::class)
|
||||
->addTag('serializer.encoder');
|
||||
$container->registerForAutoconfiguration(NormalizerInterface::class)
|
||||
->addTag('serializer.normalizer');
|
||||
$container->registerForAutoconfiguration(ConstraintValidatorInterface::class)
|
||||
->addTag('validator.constraint_validator');
|
||||
$container->registerForAutoconfiguration(ObjectInitializerInterface::class)
|
||||
->addTag('validator.initializer');
|
||||
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
$this->addClassesToCompile(array(
|
||||
'Symfony\\Component\\Config\\ConfigCache',
|
||||
|
@ -11,6 +11,7 @@
|
||||
"shared": true,
|
||||
"abstract": true,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": null,
|
||||
"factory_class": "Full\\Qualified\\FactoryClass",
|
||||
"factory_method": "get",
|
||||
|
@ -12,5 +12,6 @@
|
||||
- Shared: yes
|
||||
- Abstract: yes
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Factory Class: `Full\Qualified\FactoryClass`
|
||||
- Factory Method: `get`
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<alias id="alias_1" service="service_1" public="true"/>
|
||||
<definition id="service_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
|
||||
<definition id="service_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" autoconfigured="false" file="">
|
||||
<factory class="Full\Qualified\FactoryClass" method="get"/>
|
||||
</definition>
|
||||
|
@ -11,6 +11,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
"factory_method": "get",
|
||||
|
@ -12,6 +12,7 @@
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
- Factory Method: `get`
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<alias id="alias_2" service="service_2" public="false"/>
|
||||
<definition id="service_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition id="service_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
|
@ -8,6 +8,7 @@
|
||||
"shared": true,
|
||||
"abstract": true,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [
|
||||
{
|
||||
"type": "service",
|
||||
@ -22,6 +23,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [
|
||||
"arg1",
|
||||
"arg2"
|
||||
@ -43,6 +45,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [],
|
||||
"file": null,
|
||||
"tags": []
|
||||
|
@ -13,6 +13,7 @@ Definitions
|
||||
- Shared: yes
|
||||
- Abstract: yes
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Arguments: yes
|
||||
- Factory Class: `Full\Qualified\FactoryClass`
|
||||
- Factory Method: `get`
|
||||
|
@ -2,12 +2,12 @@
|
||||
<container>
|
||||
<alias id="alias_1" service="service_1" public="true"/>
|
||||
<alias id="alias_2" service="service_2" public="false"/>
|
||||
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
|
||||
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" autoconfigured="false" file="">
|
||||
<factory class="Full\Qualified\FactoryClass" method="get"/>
|
||||
<argument type="service" id="definition2"/>
|
||||
<argument>%parameter%</argument>
|
||||
<argument>
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" file="">
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="">
|
||||
<argument>arg1</argument>
|
||||
<argument>arg2</argument>
|
||||
</definition>
|
||||
@ -16,7 +16,7 @@
|
||||
<argument>foo</argument>
|
||||
<argument type="service" id="definition2"/>
|
||||
<argument>
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" file=""/>
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file=""/>
|
||||
</argument>
|
||||
</argument>
|
||||
<argument type="iterator">
|
||||
|
@ -8,6 +8,7 @@
|
||||
"shared": true,
|
||||
"abstract": true,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": null,
|
||||
"factory_class": "Full\\Qualified\\FactoryClass",
|
||||
"factory_method": "get",
|
||||
|
@ -13,6 +13,7 @@ Definitions
|
||||
- Shared: yes
|
||||
- Abstract: yes
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Factory Class: `Full\Qualified\FactoryClass`
|
||||
- Factory Method: `get`
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<container>
|
||||
<alias id="alias_1" service="service_1" public="true"/>
|
||||
<alias id="alias_2" service="service_2" public="false"/>
|
||||
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
|
||||
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" autoconfigured="false" file="">
|
||||
<factory class="Full\Qualified\FactoryClass" method="get"/>
|
||||
</definition>
|
||||
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerBuilder"/>
|
||||
|
@ -8,6 +8,7 @@
|
||||
"shared": true,
|
||||
"abstract": true,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": null,
|
||||
"factory_class": "Full\\Qualified\\FactoryClass",
|
||||
"factory_method": "get",
|
||||
@ -21,6 +22,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
"factory_method": "get",
|
||||
|
@ -13,6 +13,7 @@ Definitions
|
||||
- Shared: yes
|
||||
- Abstract: yes
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Factory Class: `Full\Qualified\FactoryClass`
|
||||
- Factory Method: `get`
|
||||
|
||||
@ -25,6 +26,7 @@ Definitions
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
- Factory Method: `get`
|
||||
|
@ -2,10 +2,10 @@
|
||||
<container>
|
||||
<alias id="alias_1" service="service_1" public="true"/>
|
||||
<alias id="alias_2" service="service_2" public="false"/>
|
||||
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
|
||||
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" autoconfigured="false" file="">
|
||||
<factory class="Full\Qualified\FactoryClass" method="get"/>
|
||||
</definition>
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
|
@ -8,6 +8,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
"factory_method": "get",
|
||||
|
@ -13,6 +13,7 @@ Definitions
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
- Factory Method: `get`
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<container>
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
|
@ -8,6 +8,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
"factory_method": "get",
|
||||
@ -25,6 +26,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
"factory_method": "get",
|
||||
|
@ -13,6 +13,7 @@ tag1
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
- Factory Method: `get`
|
||||
@ -31,6 +32,7 @@ tag2
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
- Factory Method: `get`
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<container>
|
||||
<tag name="tag1">
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
@ -9,7 +9,7 @@
|
||||
</definition>
|
||||
</tag>
|
||||
<tag name="tag2">
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
|
@ -6,6 +6,7 @@
|
||||
"shared": true,
|
||||
"abstract": true,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": null,
|
||||
"factory_class": "Full\\Qualified\\FactoryClass",
|
||||
"factory_method": "get",
|
||||
|
@ -5,5 +5,6 @@
|
||||
- Shared: yes
|
||||
- Abstract: yes
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Factory Class: `Full\Qualified\FactoryClass`
|
||||
- Factory Method: `get`
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definition class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
|
||||
<definition class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" autoconfigured="false" file="">
|
||||
<factory class="Full\Qualified\FactoryClass" method="get"/>
|
||||
</definition>
|
||||
|
@ -6,6 +6,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
"factory_method": "get",
|
||||
|
@ -5,6 +5,7 @@
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
- Factory Method: `get`
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definition class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
|
@ -6,6 +6,7 @@
|
||||
"shared": true,
|
||||
"abstract": true,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [
|
||||
{
|
||||
"type": "service",
|
||||
@ -20,6 +21,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [
|
||||
"arg1",
|
||||
"arg2"
|
||||
@ -41,6 +43,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [],
|
||||
"file": null,
|
||||
"tags": []
|
||||
|
@ -5,6 +5,7 @@
|
||||
- Shared: yes
|
||||
- Abstract: yes
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Arguments: yes
|
||||
- Factory Class: `Full\Qualified\FactoryClass`
|
||||
- Factory Method: `get`
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definition class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
|
||||
<definition class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" autoconfigured="false" file="">
|
||||
<factory class="Full\Qualified\FactoryClass" method="get"/>
|
||||
<argument type="service" id="definition2"/>
|
||||
<argument>%parameter%</argument>
|
||||
<argument>
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" file="">
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="">
|
||||
<argument>arg1</argument>
|
||||
<argument>arg2</argument>
|
||||
</definition>
|
||||
@ -13,7 +13,7 @@
|
||||
<argument>foo</argument>
|
||||
<argument type="service" id="definition2"/>
|
||||
<argument>
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" file=""/>
|
||||
<definition class="inline_service" public="true" synthetic="false" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file=""/>
|
||||
</argument>
|
||||
</argument>
|
||||
<argument type="iterator">
|
||||
|
@ -6,6 +6,7 @@
|
||||
"shared": true,
|
||||
"abstract": false,
|
||||
"autowire": false,
|
||||
"autoconfigure": false,
|
||||
"arguments": [],
|
||||
"file": "\/path\/to\/file",
|
||||
"factory_service": "factory.service",
|
||||
|
@ -5,6 +5,7 @@
|
||||
- Shared: yes
|
||||
- Abstract: no
|
||||
- Autowired: no
|
||||
- Autoconfigured: no
|
||||
- Arguments: no
|
||||
- File: `/path/to/file`
|
||||
- Factory Service: `factory.service`
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definition class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
|
||||
<definition class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" autoconfigured="false" file="/path/to/file">
|
||||
<factory service="factory.service" method="get"/>
|
||||
<calls>
|
||||
<call method="setMailer"/>
|
||||
|
@ -19,13 +19,13 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
|
||||
/**
|
||||
* SecurityExtension.
|
||||
@ -110,6 +110,9 @@ class SecurityExtension extends Extension
|
||||
$this->aclLoad($config['acl'], $container);
|
||||
}
|
||||
|
||||
$container->registerForAutoconfiguration(VoterInterface::class)
|
||||
->addTag('security.voter');
|
||||
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
// add some required classes for compilation
|
||||
$this->addClassesToCompile(array(
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Bundle\TwigBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Bridge\Twig\Extension\WebLinkExtension;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
@ -143,6 +144,11 @@ class TwigExtension extends Extension
|
||||
|
||||
$container->getDefinition('twig')->replaceArgument(1, $config);
|
||||
|
||||
$container->registerForAutoconfiguration(\Twig_ExtensionInterface::class)
|
||||
->addTag('twig.extension');
|
||||
$container->registerForAutoconfiguration(\Twig_LoaderInterface::class)
|
||||
->addTag('twig.loader');
|
||||
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
$this->addClassesToCompile(array(
|
||||
'Twig_Environment',
|
||||
|
@ -101,6 +101,7 @@ class ResolveDefinitionTemplatesPass extends AbstractRecursivePass
|
||||
$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
|
||||
@ -129,6 +130,9 @@ class ResolveDefinitionTemplatesPass extends AbstractRecursivePass
|
||||
if (isset($changes['autowired'])) {
|
||||
$def->setAutowired($definition->isAutowired());
|
||||
}
|
||||
if (isset($changes['autoconfigured'])) {
|
||||
$def->setAutoconfigured($definition->isAutoconfigured());
|
||||
}
|
||||
if (isset($changes['shared'])) {
|
||||
$def->setShared($definition->isShared());
|
||||
}
|
||||
|
@ -38,25 +38,37 @@ class ResolveInstanceofConditionalsPass implements CompilerPassInterface
|
||||
|
||||
private function processDefinition(ContainerBuilder $container, $id, Definition $definition)
|
||||
{
|
||||
if (!$instanceofConditionals = $definition->getInstanceofConditionals()) {
|
||||
$instanceofConditionals = $definition->getInstanceofConditionals();
|
||||
$automaticInstanceofConditionals = $definition->isAutoconfigured() ? $container->getAutomaticInstanceofDefinitions() : array();
|
||||
|
||||
if (!$instanceofConditionals && !$automaticInstanceofConditionals) {
|
||||
return $definition;
|
||||
}
|
||||
|
||||
if (!$class = $container->getParameterBag()->resolveValue($definition->getClass())) {
|
||||
return $definition;
|
||||
}
|
||||
|
||||
$conditionals = $this->mergeConditionals($automaticInstanceofConditionals, $instanceofConditionals);
|
||||
|
||||
$definition->setInstanceofConditionals(array());
|
||||
$parent = $shared = null;
|
||||
$instanceofTags = array();
|
||||
|
||||
foreach ($instanceofConditionals as $interface => $instanceofDef) {
|
||||
foreach ($conditionals as $interface => $instanceofDefs) {
|
||||
if ($interface !== $class && (!$container->getReflectionClass($interface) || !$container->getReflectionClass($class))) {
|
||||
continue;
|
||||
}
|
||||
if ($interface === $class || is_subclass_of($class, $interface)) {
|
||||
|
||||
if ($interface !== $class && !is_subclass_of($class, $interface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($instanceofDefs as $key => $instanceofDef) {
|
||||
/** @var ChildDefinition $instanceofDef */
|
||||
$instanceofDef = clone $instanceofDef;
|
||||
$instanceofDef->setAbstract(true)->setInheritTags(false)->setParent($parent ?: 'abstract.instanceof.'.$id);
|
||||
$parent = 'instanceof.'.$interface.'.'.$id;
|
||||
$parent = 'instanceof.'.$interface.'.'.$key.'.'.$id;
|
||||
$container->setDefinition($parent, $instanceofDef);
|
||||
$instanceofTags[] = $instanceofDef->getTags();
|
||||
$instanceofDef->setTags(array());
|
||||
@ -100,4 +112,20 @@ class ResolveInstanceofConditionalsPass implements CompilerPassInterface
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
private function mergeConditionals(array $automaticInstanceofConditionals, array $instanceofConditionals)
|
||||
{
|
||||
// make each value an array of ChildDefinition
|
||||
$conditionals = array_map(function($childDef) { return array($childDef); }, $automaticInstanceofConditionals);
|
||||
|
||||
foreach ($instanceofConditionals as $interface => $instanceofDef) {
|
||||
if (!isset($automaticInstanceofConditionals[$interface])) {
|
||||
$conditionals[$interface] = array();
|
||||
}
|
||||
|
||||
$conditionals[$interface][] = $instanceofDef;
|
||||
}
|
||||
|
||||
return $conditionals;
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
*/
|
||||
private $vendors;
|
||||
|
||||
private $automaticInstanceofDefinitions = array();
|
||||
|
||||
public function __construct(ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
parent::__construct($parameterBag);
|
||||
@ -638,6 +640,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
$this->envCounters[$env] += $count;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getAutomaticInstanceofDefinitions() as $interface => $childDefinition) {
|
||||
if (isset($this->automaticInstanceofDefinitions[$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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1259,6 +1269,31 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
return $this->expressionLanguageProviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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('');
|
||||
}
|
||||
|
||||
return $this->automaticInstanceofDefinitions[$interface];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of ChildDefinition[] keyed by interface.
|
||||
*
|
||||
* @return ChildDefinition[]
|
||||
*/
|
||||
public function getAutomaticInstanceofDefinitions()
|
||||
{
|
||||
return $this->automaticInstanceofDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves env parameter placeholders in a string or an array.
|
||||
*
|
||||
|
@ -30,6 +30,7 @@ class Definition
|
||||
private $properties = array();
|
||||
private $calls = array();
|
||||
private $instanceof = array();
|
||||
private $autoconfigured = false;
|
||||
private $configurator;
|
||||
private $tags = array();
|
||||
private $public = true;
|
||||
@ -388,6 +389,30 @@ class Definition
|
||||
return $this->instanceof;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not instanceof conditionals should be prepended with a global set.
|
||||
*
|
||||
* @param bool $autoconfigured
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAutoconfigured($autoconfigured)
|
||||
{
|
||||
$this->changes['autoconfigured'] = true;
|
||||
|
||||
$this->autoconfigured = $autoconfigured;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutoconfigured()
|
||||
{
|
||||
return $this->autoconfigured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tags for this definition.
|
||||
*
|
||||
|
@ -205,6 +205,10 @@ class XmlDumper extends Dumper
|
||||
$service->appendChild($autowiringType);
|
||||
}
|
||||
|
||||
if ($definition->isAutoconfigured()) {
|
||||
$service->setAttribute('autoconfigure', 'true');
|
||||
}
|
||||
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
$configurator = $this->document->createElement('configurator');
|
||||
|
||||
|
@ -180,6 +180,9 @@ class XmlFileLoader extends FileLoader
|
||||
if ($defaultsNode->hasAttribute('inherit-tags')) {
|
||||
$defaults['inherit-tags'] = XmlUtils::phpize($defaultsNode->getAttribute('inherit-tags'));
|
||||
}
|
||||
if ($defaultsNode->hasAttribute('autoconfigure')) {
|
||||
$defaults['autoconfigure'] = XmlUtils::phpize($defaultsNode->getAttribute('autoconfigure'));
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
@ -229,6 +232,9 @@ class XmlFileLoader extends FileLoader
|
||||
if (isset($defaults['autowire'])) {
|
||||
$definition->setAutowired($defaults['autowire']);
|
||||
}
|
||||
if (isset($defaults['autoconfigure'])) {
|
||||
$definition->setAutoconfigured($defaults['autoconfigure']);
|
||||
}
|
||||
|
||||
$definition->setChanges(array());
|
||||
}
|
||||
@ -248,6 +254,10 @@ class XmlFileLoader extends FileLoader
|
||||
$definition->setAutowired(XmlUtils::phpize($value));
|
||||
}
|
||||
|
||||
if ($value = $service->getAttribute('autoconfigure')) {
|
||||
$definition->setAutoconfigured(XmlUtils::phpize($value));
|
||||
}
|
||||
|
||||
if ($files = $this->getChildren($service, 'file')) {
|
||||
$definition->setFile($files[0]->nodeValue);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ class YamlFileLoader extends FileLoader
|
||||
'decoration_priority' => 'decoration_priority',
|
||||
'autowire' => 'autowire',
|
||||
'autowiring_types' => 'autowiring_types',
|
||||
'autoconfigure' => 'autoconfigure',
|
||||
);
|
||||
|
||||
private static $prototypeKeywords = array(
|
||||
@ -75,6 +76,7 @@ class YamlFileLoader extends FileLoader
|
||||
'tags' => 'tags',
|
||||
'inherit_tags' => 'inherit_tags',
|
||||
'autowire' => 'autowire',
|
||||
'autoconfigure' => 'autoconfigure',
|
||||
);
|
||||
|
||||
private static $instanceofKeywords = array(
|
||||
@ -86,6 +88,7 @@ class YamlFileLoader extends FileLoader
|
||||
'calls' => 'calls',
|
||||
'tags' => 'tags',
|
||||
'autowire' => 'autowire',
|
||||
'autoconfigure' => 'autoconfigure',
|
||||
);
|
||||
|
||||
private static $defaultsKeywords = array(
|
||||
@ -93,6 +96,7 @@ class YamlFileLoader extends FileLoader
|
||||
'tags' => 'tags',
|
||||
'inherit_tags' => 'inherit_tags',
|
||||
'autowire' => 'autowire',
|
||||
'autoconfigure' => 'autoconfigure',
|
||||
);
|
||||
|
||||
private $yamlParser;
|
||||
@ -369,6 +373,9 @@ class YamlFileLoader extends FileLoader
|
||||
if (isset($defaults['autowire'])) {
|
||||
$definition->setAutowired($defaults['autowire']);
|
||||
}
|
||||
if (isset($defaults['autoconfigure'])) {
|
||||
$definition->setAutoconfigured($defaults['autoconfigure']);
|
||||
}
|
||||
|
||||
$definition->setChanges(array());
|
||||
}
|
||||
@ -510,6 +517,10 @@ class YamlFileLoader extends FileLoader
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($service['autoconfigure'])) {
|
||||
$definition->setAutoconfigured($service['autoconfigure']);
|
||||
}
|
||||
|
||||
if (array_key_exists('resource', $service)) {
|
||||
if (!is_string($service['resource'])) {
|
||||
throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file));
|
||||
|
@ -104,6 +104,7 @@
|
||||
<xsd:attribute name="public" type="boolean" />
|
||||
<xsd:attribute name="autowire" type="boolean" />
|
||||
<xsd:attribute name="inherit-tags" type="boolean" />
|
||||
<xsd:attribute name="autoconfigure" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="service">
|
||||
@ -132,6 +133,7 @@
|
||||
<xsd:attribute name="decoration-priority" type="xsd:integer" />
|
||||
<xsd:attribute name="autowire" type="boolean" />
|
||||
<xsd:attribute name="inherit-tags" type="boolean" />
|
||||
<xsd:attribute name="autoconfigure" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="instanceof">
|
||||
@ -146,6 +148,7 @@
|
||||
<xsd:attribute name="public" type="boolean" />
|
||||
<xsd:attribute name="lazy" type="boolean" />
|
||||
<xsd:attribute name="autowire" type="boolean" />
|
||||
<xsd:attribute name="autoconfigure" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="prototype">
|
||||
@ -167,6 +170,7 @@
|
||||
<xsd:attribute name="parent" type="xsd:string" />
|
||||
<xsd:attribute name="autowire" type="boolean" />
|
||||
<xsd:attribute name="inherit-tags" type="boolean" />
|
||||
<xsd:attribute name="autoconfigure" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="tag">
|
||||
|
@ -130,6 +130,7 @@ class IntegrationTest extends TestCase
|
||||
// instanceof overrides defaults
|
||||
$simpleService = $container->getDefinition('service_simple');
|
||||
$this->assertFalse($simpleService->isAutowired());
|
||||
$this->assertFalse($simpleService->isAutoconfigured());
|
||||
$this->assertFalse($simpleService->isShared());
|
||||
|
||||
// all tags are kept
|
||||
@ -156,6 +157,7 @@ class IntegrationTest extends TestCase
|
||||
// service override instanceof
|
||||
$overrideService = $container->getDefinition('service_override_instanceof');
|
||||
$this->assertTrue($overrideService->isAutowired());
|
||||
$this->assertTrue($overrideService->isAutoconfigured());
|
||||
|
||||
// children definitions get no instanceof
|
||||
$childDef = $container->getDefinition('child_service');
|
||||
|
@ -381,6 +381,38 @@ class ResolveDefinitionTemplatesPassTest extends TestCase
|
||||
$this->assertSame(array(2, 1, 'foo' => 3), $def->getArguments());
|
||||
}
|
||||
|
||||
public function testSetAutoconfiguredOnServiceHasParent()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('parent', 'stdClass')
|
||||
->setAutoconfigured(true)
|
||||
;
|
||||
|
||||
$container->setDefinition('child1', new ChildDefinition('parent'))
|
||||
->setAutoconfigured(false)
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertFalse($container->getDefinition('child1')->isAutoconfigured());
|
||||
}
|
||||
|
||||
public function testSetAutoconfiguredOnServiceIsParent()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('parent', 'stdClass')
|
||||
->setAutoconfigured(true)
|
||||
;
|
||||
|
||||
$container->setDefinition('child1', new ChildDefinition('parent'));
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertTrue($container->getDefinition('child1')->isAutoconfigured());
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new ResolveDefinitionTemplatesPass();
|
||||
|
@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveTagsInheritancePass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class ResolveInstanceofConditionalsPassTest extends TestCase
|
||||
@ -29,7 +30,7 @@ class ResolveInstanceofConditionalsPassTest extends TestCase
|
||||
|
||||
(new ResolveInstanceofConditionalsPass())->process($container);
|
||||
|
||||
$parent = 'instanceof.'.parent::class.'.foo';
|
||||
$parent = 'instanceof.'.parent::class.'.0.foo';
|
||||
$def = $container->getDefinition('foo');
|
||||
$this->assertEmpty($def->getInstanceofConditionals());
|
||||
$this->assertInstanceof(ChildDefinition::class, $def);
|
||||
@ -106,4 +107,51 @@ class ResolveInstanceofConditionalsPassTest extends TestCase
|
||||
$this->assertTrue($def->isLazy());
|
||||
$this->assertTrue($def->isShared());
|
||||
}
|
||||
|
||||
public function testProcessUsesAutomaticInstanceofDefinitions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$def = $container->register('normal_service', self::class);
|
||||
$def->setInstanceofConditionals(array(
|
||||
parent::class => (new ChildDefinition(''))
|
||||
->addTag('local_instanceof_tag')
|
||||
->setFactory('locally_set_factory'),
|
||||
));
|
||||
$def->setAutoconfigured(true);
|
||||
$container->registerForAutoconfiguration(parent::class)
|
||||
->addTag('automatic_instanceof_tag')
|
||||
->setAutowired(true)
|
||||
->setFactory('automatically_set_factory');
|
||||
|
||||
(new ResolveInstanceofConditionalsPass())->process($container);
|
||||
(new ResolveTagsInheritancePass())->process($container);
|
||||
(new ResolveDefinitionTemplatesPass())->process($container);
|
||||
|
||||
$def = $container->getDefinition('normal_service');
|
||||
// autowired thanks to the automatic instanceof
|
||||
$this->assertTrue($def->isAutowired());
|
||||
// factory from the specific instanceof overrides global one
|
||||
$this->assertEquals('locally_set_factory', $def->getFactory());
|
||||
// tags are merged, the locally set one is first
|
||||
$this->assertSame(array('local_instanceof_tag' => array(array()), 'automatic_instanceof_tag' => array(array())), $def->getTags());
|
||||
}
|
||||
|
||||
public function testProcessDoesNotUseAutomaticInstanceofDefinitionsIfNotEnabled()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$def = $container->register('normal_service', self::class);
|
||||
$def->setInstanceofConditionals(array(
|
||||
parent::class => (new ChildDefinition(''))
|
||||
->addTag('foo_tag'),
|
||||
));
|
||||
$container->registerForAutoconfiguration(parent::class)
|
||||
->setAutowired(true);
|
||||
|
||||
(new ResolveInstanceofConditionalsPass())->process($container);
|
||||
(new ResolveDefinitionTemplatesPass())->process($container);
|
||||
|
||||
$def = $container->getDefinition('normal_service');
|
||||
// no automatic_tag, it was not enabled on the Definition
|
||||
$this->assertFalse($def->isAutowired());
|
||||
}
|
||||
}
|
||||
|
@ -567,6 +567,26 @@ class ContainerBuilderTest extends TestCase
|
||||
$this->assertSame(array('%env(Bar)%'), $config->resolveEnvPlaceholders(array($bag->get('env(Bar)'))));
|
||||
$container->merge($config);
|
||||
$this->assertEquals(array('Foo' => 0, 'Bar' => 1), $container->getEnvCounters());
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$config = new ContainerBuilder();
|
||||
$childDefA = $container->registerForAutoconfiguration('AInterface');
|
||||
$childDefB = $config->registerForAutoconfiguration('BInterface');
|
||||
$container->merge($config);
|
||||
$this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutomaticInstanceofDefinitions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage AInterface has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.
|
||||
*/
|
||||
public function testMergeThrowsExceptionForDuplicateAutomaticInstanceofDefinitions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$config = new ContainerBuilder();
|
||||
$container->registerForAutoconfiguration('AInterface');
|
||||
$config->registerForAutoconfiguration('AInterface');
|
||||
$container->merge($config);
|
||||
}
|
||||
|
||||
public function testResolveEnvValues()
|
||||
@ -1097,6 +1117,17 @@ class ContainerBuilderTest extends TestCase
|
||||
$this->assertInstanceOf(ServiceLocator::class, $foo = $container->get('foo_service'));
|
||||
$this->assertSame($container->get('bar_service'), $foo->get('bar'));
|
||||
}
|
||||
|
||||
public function testRegisterForAutoconfiguration()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$childDefA = $container->registerForAutoconfiguration('AInterface');
|
||||
$childDefB = $container->registerForAutoconfiguration('BInterface');
|
||||
$this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutomaticInstanceofDefinitions());
|
||||
|
||||
// when called multiple times, the same instance is returned
|
||||
$this->assertSame($childDefA, $container->registerForAutoconfiguration('AInterface'));
|
||||
}
|
||||
}
|
||||
|
||||
class FooClass
|
||||
|
@ -344,6 +344,7 @@ class DefinitionTest extends TestCase
|
||||
$def->addTag('foo_tag');
|
||||
$def->addMethodCall('methodCall');
|
||||
$def->setProperty('fooprop', true);
|
||||
$def->setAutoconfigured(true);
|
||||
|
||||
$this->assertSame(array(
|
||||
'class' => true,
|
||||
@ -356,6 +357,7 @@ class DefinitionTest extends TestCase
|
||||
'lazy' => true,
|
||||
'public' => true,
|
||||
'shared' => true,
|
||||
'autoconfigured' => true,
|
||||
), $def->getChanges());
|
||||
|
||||
$def->setChanges(array());
|
||||
@ -377,4 +379,12 @@ class DefinitionTest extends TestCase
|
||||
$this->assertSame($def, $def->removeAutowiringType('Foo'));
|
||||
$this->assertEquals(array('Bar'), $def->getAutowiringTypes());
|
||||
}
|
||||
|
||||
public function testShouldAutoconfigure()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertFalse($def->isAutoconfigured());
|
||||
$def->setAutoconfigured(true);
|
||||
$this->assertTrue($def->isAutoconfigured());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
<services>
|
||||
<defaults autoconfigure="true" />
|
||||
|
||||
<service id="use_defaults_settings" />
|
||||
<service id="override_defaults_settings_to_false" autoconfigure="false" />
|
||||
</services>
|
||||
</container>
|
@ -0,0 +1,9 @@
|
||||
|
||||
services:
|
||||
_defaults:
|
||||
autoconfigure: true
|
||||
|
||||
use_defaults_settings: ~
|
||||
|
||||
override_defaults_settings_to_false:
|
||||
autoconfigure: false
|
@ -1,11 +1,13 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
_instanceof:
|
||||
Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStubParent:
|
||||
# should override _defaults
|
||||
autowire: false
|
||||
autoconfigure: false
|
||||
shared: false
|
||||
tags:
|
||||
- { name: foo_tag, tag_option: from_instanceof }
|
||||
@ -30,6 +32,7 @@ services:
|
||||
class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub
|
||||
# override instanceof
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
parent_service:
|
||||
abstract: true
|
||||
|
@ -693,6 +693,16 @@ class XmlFileLoaderTest extends TestCase
|
||||
$this->assertTrue($definition->isLazy());
|
||||
$this->assertSame(array('foo' => array(array()), 'bar' => array(array())), $definition->getTags());
|
||||
}
|
||||
|
||||
public function testAutoConfigureInstanceof()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
|
||||
$loader->load('services_autoconfigure.xml');
|
||||
|
||||
$this->assertTrue($container->getDefinition('use_defaults_settings')->isAutoconfigured());
|
||||
$this->assertFalse($container->getDefinition('override_defaults_settings_to_false')->isAutoconfigured());
|
||||
}
|
||||
}
|
||||
|
||||
interface BarInterface
|
||||
|
@ -567,6 +567,16 @@ class YamlFileLoaderTest extends TestCase
|
||||
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$loader->load('anonymous_services_in_parameters.yml');
|
||||
}
|
||||
|
||||
public function testAutoConfigureInstanceof()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$loader->load('services_autoconfigure.yml');
|
||||
|
||||
$this->assertTrue($container->getDefinition('use_defaults_settings')->isAutoconfigured());
|
||||
$this->assertFalse($container->getDefinition('override_defaults_settings_to_false')->isAutoconfigured());
|
||||
}
|
||||
}
|
||||
|
||||
interface FooInterface
|
||||
|
Reference in New Issue
Block a user