feature #14984 [DependencyInjection] Deprecate scope concept (dosten)

This PR was merged into the 2.8 branch.

Discussion
----------

[DependencyInjection] Deprecate scope concept

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| License       | MIT

This PR mark as deprecated the concept of scopes in the DI container. See https://github.com/symfony/symfony/issues/10557#issuecomment-38811755.
Also adds a new `shared` flag to the service definitions in replacement of the `prototype` scope.

Commits
-------

6c4a676 Add "shared" flag and deprecate scopes concept
This commit is contained in:
Fabien Potencier 2015-06-24 18:13:46 +02:00
commit 50e752b862
84 changed files with 515 additions and 90 deletions

View File

@ -65,3 +65,74 @@ Translator
$messages = array_replace_recursive($catalogue->all(), $messages);
}
```
DependencyInjection
-------------------
* The concept of scopes were deprecated, the deprecated methods are:
- `Symfony\Component\DependencyInjection\ContainerBuilder::getScopes()`
- `Symfony\Component\DependencyInjection\ContainerBuilder::getScopeChildren()`
- `Symfony\Component\DependencyInjection\ContainerInterface::enterScope()`
- `Symfony\Component\DependencyInjection\ContainerInterface::leaveScope()`
- `Symfony\Component\DependencyInjection\ContainerInterface::addScope()`
- `Symfony\Component\DependencyInjection\ContainerInterface::hasScope()`
- `Symfony\Component\DependencyInjection\ContainerInterface::isScopeActive()`
- `Symfony\Component\DependencyInjection\Definition::setScope()`
- `Symfony\Component\DependencyInjection\Definition::getScope()`
- `Symfony\Component\DependencyInjection\Reference::isStrict()`
Also, the `$scope` and `$strict` parameters of `Symfony\Component\DependencyInjection\ContainerInterface::set()` and `Symfony\Component\DependencyInjection\Reference` respectively were deprecated.
* A new `shared` flag has been added to the service definition
in replacement of the `prototype` scope.
Before:
```php
use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();
$container
->register('foo', 'stdClass')
->setScope(ContainerBuilder::SCOPE_PROTOTYPE)
;
```
```yml
services:
foo:
class: stdClass
scope: prototype
```
```xml
<services>
<service id="foo" class="stdClass" scope="prototype" />
</services>
```
After:
```php
use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();
$container
->register('foo', 'stdClass')
->setShared(false)
;
```
```yml
services:
foo:
class: stdClass
shared: false
```
```xml
<services>
<service id="foo" class="stdClass" shared="false" />
</services>
```

View File

@ -68,9 +68,9 @@ class ProxyDumper implements DumperInterface
{
$instantiation = 'return';
if (ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
if ($definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
$instantiation .= " \$this->services['$id'] =";
} elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
} elseif ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
$instantiation .= " \$this->services['$id'] = \$this->scopedServices['$scope']['$id'] =";
}

View File

@ -17,7 +17,7 @@
],
"require": {
"php": ">=5.3.9",
"symfony/dependency-injection": "~2.3|~3.0.0",
"symfony/dependency-injection": "~2.8|~3.0.0",
"ocramius/proxy-manager": "~0.4|~1.0"
},
"require-dev": {

View File

@ -213,12 +213,16 @@ class JsonDescriptor extends Descriptor
{
$data = array(
'class' => (string) $definition->getClass(),
'scope' => $definition->getScope(),
'scope' => $definition->getScope(false),
'public' => $definition->isPublic(),
'synthetic' => $definition->isSynthetic(),
'lazy' => $definition->isLazy(),
);
if (method_exists($definition, 'isShared')) {
$data['shared'] = $definition->isShared();
}
if (method_exists($definition, 'isSynchronized')) {
$data['synchronized'] = $definition->isSynchronized(false);
}

View File

@ -179,12 +179,16 @@ class MarkdownDescriptor extends Descriptor
protected function describeContainerDefinition(Definition $definition, array $options = array())
{
$output = '- Class: `'.$definition->getClass().'`'
."\n".'- Scope: `'.$definition->getScope().'`'
."\n".'- Scope: `'.$definition->getScope(false).'`'
."\n".'- Public: '.($definition->isPublic() ? 'yes' : 'no')
."\n".'- Synthetic: '.($definition->isSynthetic() ? 'yes' : 'no')
."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no')
;
if (method_exists($definition, 'isShared')) {
$output .= "\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no');
}
if (method_exists($definition, 'isSynchronized')) {
$output .= "\n".'- Synchronized: '.($definition->isSynchronized(false) ? 'yes' : 'no');
}

View File

@ -174,7 +174,7 @@ class TextDescriptor extends Descriptor
$serviceIds = isset($options['tag']) && $options['tag'] ? array_keys($builder->findTaggedServiceIds($options['tag'])) : $builder->getServiceIds();
$maxTags = array();
foreach ($serviceIds as $key => $serviceId) {
foreach ($serviceIds as $key => $serviceId) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
if ($definition instanceof Definition) {
// filter out private services unless shown explicitly
@ -261,10 +261,13 @@ class TextDescriptor extends Descriptor
$description[] = '<comment>Tags</comment> -';
}
$description[] = sprintf('<comment>Scope</comment> %s', $definition->getScope());
$description[] = sprintf('<comment>Scope</comment> %s', $definition->getScope(false));
$description[] = sprintf('<comment>Public</comment> %s', $definition->isPublic() ? 'yes' : 'no');
$description[] = sprintf('<comment>Synthetic</comment> %s', $definition->isSynthetic() ? 'yes' : 'no');
$description[] = sprintf('<comment>Lazy</comment> %s', $definition->isLazy() ? 'yes' : 'no');
if (method_exists($definition, 'isShared')) {
$description[] = sprintf('<comment>Shared</comment> %s', $definition->isShared() ? 'yes' : 'no');
}
if (method_exists($definition, 'isSynchronized')) {
$description[] = sprintf('<comment>Synchronized</comment> %s', $definition->isSynchronized(false) ? 'yes' : 'no');
}

View File

@ -362,10 +362,13 @@ class XmlDescriptor extends Descriptor
}
}
$serviceXML->setAttribute('scope', $definition->getScope());
$serviceXML->setAttribute('scope', $definition->getScope(false));
$serviceXML->setAttribute('public', $definition->isPublic() ? 'true' : 'false');
$serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false');
$serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
if (method_exists($definition, 'isShared')) {
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
}
if (method_exists($definition, 'isSynchronized')) {
$serviceXML->setAttribute('synchronized', $definition->isSynchronized(false) ? 'true' : 'false');
}

View File

@ -13,16 +13,16 @@
</parameters>
<services>
<service id="test.client" class="%test.client.class%" scope="prototype">
<service id="test.client" class="%test.client.class%" shared="false">
<argument type="service" id="kernel" />
<argument>%test.client.parameters%</argument>
<argument type="service" id="test.client.history" />
<argument type="service" id="test.client.cookiejar" />
</service>
<service id="test.client.history" class="%test.client.history.class%" scope="prototype" />
<service id="test.client.history" class="%test.client.history.class%" shared="false" />
<service id="test.client.cookiejar" class="%test.client.cookiejar.class%" scope="prototype" />
<service id="test.client.cookiejar" class="%test.client.cookiejar.class%" shared="false" />
<service id="test.session.listener" class="%test.session.listener.class%">
<argument type="service" id="service_container" />

View File

@ -6,6 +6,7 @@
"public": true,
"synthetic": false,
"lazy": true,
"shared": true,
"synchronized": false,
"abstract": true,
"file": null,

View File

@ -12,6 +12,7 @@ definition_1
- Public: yes
- Synthetic: no
- Lazy: yes
- Shared: yes
- Synchronized: no
- Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass`

View File

@ -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" scope="container" public="true" synthetic="false" lazy="true" synchronized="false" abstract="true" file="">
<definition id="definition_1" class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" shared="true" synchronized="false" abstract="true" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/>
</definition>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerBuilder"/>

View File

@ -6,6 +6,7 @@
"public": true,
"synthetic": false,
"lazy": true,
"shared": true,
"synchronized": false,
"abstract": true,
"file": null,
@ -21,6 +22,7 @@
"public": false,
"synthetic": true,
"lazy": false,
"shared": true,
"synchronized": false,
"abstract": false,
"file": "\/path\/to\/file",

View File

@ -12,6 +12,7 @@ definition_1
- Public: yes
- Synthetic: no
- Lazy: yes
- Shared: yes
- Synchronized: no
- Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass`
@ -25,6 +26,7 @@ definition_2
- Public: no
- Synthetic: yes
- Lazy: no
- Shared: yes
- Synchronized: no
- Abstract: no
- File: `/path/to/file`

View File

@ -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" scope="container" public="true" synthetic="false" lazy="true" synchronized="false" abstract="true" file="">
<definition id="definition_1" class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" shared="true" synchronized="false" abstract="true" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/>
</definition>
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" synchronized="false" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" synchronized="false" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
<tags>
<tag name="tag1">

View File

@ -6,6 +6,7 @@
"public": false,
"synthetic": true,
"lazy": false,
"shared": true,
"synchronized": false,
"abstract": false,
"file": "\/path\/to\/file",

View File

@ -12,6 +12,7 @@ definition_2
- Public: no
- Synthetic: yes
- Lazy: no
- Shared: yes
- Synchronized: no
- Abstract: no
- File: `/path/to/file`

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<container>
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" synchronized="false" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" synchronized="false" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
<tags>
<tag name="tag1">

View File

@ -6,6 +6,7 @@
"public": false,
"synthetic": true,
"lazy": false,
"shared": true,
"synchronized": false,
"abstract": false,
"file": "\/path\/to\/file",
@ -20,6 +21,7 @@
"public": false,
"synthetic": true,
"lazy": false,
"shared": true,
"synchronized": false,
"abstract": false,
"file": "\/path\/to\/file",

View File

@ -12,6 +12,7 @@ definition_2
- Public: no
- Synthetic: yes
- Lazy: no
- Shared: yes
- Synchronized: no
- Abstract: no
- File: `/path/to/file`
@ -30,6 +31,7 @@ definition_2
- Public: no
- Synthetic: yes
- Lazy: no
- Shared: yes
- Synchronized: no
- Abstract: no
- File: `/path/to/file`

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<container>
<tag name="tag1">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" synchronized="false" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" synchronized="false" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
</definition>
</tag>
<tag name="tag2">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" synchronized="false" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" synchronized="false" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
</definition>
</tag>

View File

@ -4,6 +4,7 @@
"public": true,
"synthetic": false,
"lazy": true,
"shared": true,
"synchronized": false,
"abstract": true,
"file": null,

View File

@ -3,6 +3,7 @@
- Public: yes
- Synthetic: no
- Lazy: yes
- Shared: yes
- Synchronized: no
- Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass`

View File

@ -5,6 +5,7 @@
<comment>Public</comment> yes
<comment>Synthetic</comment> no
<comment>Lazy</comment> yes
<comment>Shared</comment> yes
<comment>Synchronized</comment> no
<comment>Abstract</comment> yes
<comment>Factory Class</comment> Full\Qualified\FactoryClass

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" synchronized="false" abstract="true" file="">
<definition class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" shared="true" synchronized="false" abstract="true" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/>
</definition>

View File

@ -4,6 +4,7 @@
"public": false,
"synthetic": true,
"lazy": false,
"shared": true,
"synchronized": false,
"abstract": false,
"file": "\/path\/to\/file",

View File

@ -3,6 +3,7 @@
- Public: no
- Synthetic: yes
- Lazy: no
- Shared: yes
- Synchronized: no
- Abstract: no
- File: `/path/to/file`

View File

@ -8,6 +8,7 @@
<comment>Public</comment> no
<comment>Synthetic</comment> yes
<comment>Lazy</comment> no
<comment>Shared</comment> yes
<comment>Synchronized</comment> no
<comment>Abstract</comment> no
<comment>Required File</comment> /path/to/file

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" synchronized="false" abstract="false" file="/path/to/file">
<definition class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" synchronized="false" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
<tags>
<tag name="tag1">

View File

@ -4,6 +4,7 @@
"public": true,
"synthetic": false,
"lazy": true,
"shared": true,
"synchronized": true,
"abstract": true,
"file": null,

View File

@ -3,6 +3,7 @@
- Public: yes
- Synthetic: no
- Lazy: yes
- Shared: yes
- Synchronized: yes
- Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass`

View File

@ -5,6 +5,7 @@
<comment>Public</comment> yes
<comment>Synthetic</comment> no
<comment>Lazy</comment> yes
<comment>Shared</comment> yes
<comment>Synchronized</comment> yes
<comment>Abstract</comment> yes
<comment>Factory Class</comment> Full\Qualified\FactoryClass

View File

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class1" factory-class="Full\Qualified\FactoryClass" factory-method="get" scope="container" public="true" synthetic="false" lazy="true" synchronized="true" abstract="true" file=""/>
<definition class="Full\Qualified\Class1" factory-class="Full\Qualified\FactoryClass" factory-method="get" scope="container" public="true" synthetic="false" lazy="true" shared="true" synchronized="true" abstract="true" file=""/>

View File

@ -4,6 +4,7 @@
"public": false,
"synthetic": true,
"lazy": false,
"shared": true,
"synchronized": false,
"abstract": false,
"file": "\/path\/to\/file",

View File

@ -3,6 +3,7 @@
- Public: no
- Synthetic: yes
- Lazy: no
- Shared: yes
- Synchronized: no
- Abstract: no
- File: `/path/to/file`

View File

@ -8,6 +8,7 @@
<comment>Public</comment> no
<comment>Synthetic</comment> yes
<comment>Lazy</comment> no
<comment>Shared</comment> yes
<comment>Synchronized</comment> no
<comment>Abstract</comment> no
<comment>Required File</comment> /path/to/file

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class2" factory-service="factory.service" factory-method="get" scope="container" public="false" synthetic="true" lazy="false" synchronized="false" abstract="false" file="/path/to/file">
<definition class="Full\Qualified\Class2" factory-service="factory.service" factory-method="get" scope="container" public="false" synthetic="true" lazy="false" shared="true" synchronized="false" abstract="false" file="/path/to/file">
<tags>
<tag name="tag1">
<parameter name="attr1">val1</parameter>

View File

@ -16,7 +16,7 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;
@ -29,14 +29,14 @@ use Symfony\Component\Security\Core\Security;
*/
class UserLoginFormType extends AbstractType
{
private $request;
private $requestStack;
/**
* @param Request $request A request instance
* @param RequestStack $requestStack A RequestStack instance
*/
public function __construct(Request $request)
public function __construct(RequestStack $requestStack)
{
$this->request = $request;
$this->requestStack = $requestStack;
}
/**
@ -50,7 +50,7 @@ class UserLoginFormType extends AbstractType
->add('_target_path', 'hidden')
;
$request = $this->request;
$request = $this->requestStack->getCurrentRequest();
/* Note: since the Security component's form login listener intercepts
* the POST request, this form will never really be bound to the

View File

@ -4,9 +4,8 @@ imports:
services:
csrf_form_login.form.type:
class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form\UserLoginFormType
scope: request
arguments:
- @request
- @request_stack
tags:
- { name: form.type, alias: user_login }

View File

@ -29,7 +29,7 @@
"symfony/dom-crawler": "~2.0,>=2.0.5|~3.0.0",
"symfony/form": "~2.7|~3.0.0",
"symfony/framework-bundle": "~2.7|~3.0.0",
"symfony/http-foundation": "~2.3|~3.0.0",
"symfony/http-foundation": "~2.4|~3.0.0",
"symfony/twig-bundle": "~2.7|~3.0.0",
"symfony/twig-bridge": "~2.7|~3.0.0",
"symfony/process": "~2.0,>=2.0.5|~3.0.0",

View File

@ -18,7 +18,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Scope;
class WebProfilerExtensionTest extends TestCase
{
@ -49,8 +48,6 @@ class WebProfilerExtensionTest extends TestCase
$this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface');
$this->container = new ContainerBuilder();
$this->container->addScope(new Scope('request'));
$this->container->register('request', 'Symfony\\Component\\HttpFoundation\\Request')->setScope('request');
$this->container->register('router', $this->getMockClass('Symfony\\Component\\Routing\\RouterInterface'));
$this->container->register('twig', 'Twig_Environment');
$this->container->setParameter('kernel.bundles', array());
@ -125,7 +122,6 @@ class WebProfilerExtensionTest extends TestCase
eval('?>'.$dumper->dump(array('class' => $class)));
$container = new $class();
$container->enterScope('request');
$container->set('kernel', $this->kernel);
return $container;

View File

@ -5,6 +5,8 @@ CHANGELOG
-----
* allowed specifying a directory to recursively load all configuration files it contains
* deprecated the concept of scopes
* added `Definition::setShared()` and `Definition::isShared()`
2.7.0
-----

View File

@ -25,6 +25,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
* - non synthetic, non abstract services always have a class set
* - synthetic services are always public
* - synthetic services are always of non-prototype scope
* - shared services are always of non-prototype scope
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
@ -46,10 +47,15 @@ class CheckDefinitionValidityPass implements CompilerPassInterface
}
// synthetic service has non-prototype scope
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A synthetic service ("%s") cannot be of scope "prototype".', $id));
}
// shared service has non-prototype scope
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A shared service ("%s") cannot be of scope "prototype".', $id));
}
if ($definition->getFactory() && ($definition->getFactoryClass(false) || $definition->getFactoryService(false) || $definition->getFactoryMethod(false))) {
throw new RuntimeException(sprintf('A service ("%s") can use either the old or the new factory syntax, not both.', $id));
}

View File

@ -46,10 +46,10 @@ class CheckReferenceValidityPass implements CompilerPassInterface
{
$this->container = $container;
$children = $this->container->getScopeChildren();
$children = $this->container->getScopeChildren(false);
$ancestors = array();
$scopes = $this->container->getScopes();
$scopes = $this->container->getScopes(false);
foreach ($scopes as $name => $parent) {
$ancestors[$name] = array($parent);
@ -65,7 +65,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
$this->currentId = $id;
$this->currentDefinition = $definition;
$this->currentScope = $scope = $definition->getScope();
$this->currentScope = $scope = $definition->getScope(false);
if (ContainerInterface::SCOPE_CONTAINER === $scope) {
$this->currentScopeChildren = array_keys($scopes);
@ -125,7 +125,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
return;
}
if (!$reference->isStrict()) {
if (!$reference->isStrict(false)) {
return;
}
@ -133,7 +133,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
return;
}
if ($this->currentScope === $scope = $definition->getScope()) {
if ($this->currentScope === $scope = $definition->getScope(false)) {
return;
}

View File

@ -92,7 +92,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
$this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false)) {
$arguments[$k] = $definition;
} else {
$arguments[$k] = clone $definition;
@ -119,7 +119,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
*/
private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
{
if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
if (!$definition->isShared() || ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
return true;
}
@ -152,6 +152,6 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
return false;
}
return $container->getDefinition(reset($ids))->getScope() === $definition->getScope();
return $container->getDefinition(reset($ids))->getScope(false) === $definition->getScope(false);
}
}

View File

@ -153,7 +153,7 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
// these attributes are always taken from the child
$def->setAbstract($definition->isAbstract());
$def->setScope($definition->getScope());
$def->setScope($definition->getScope(false), false);
$def->setTags($definition->getTags());
// set new definition on container

View File

@ -68,7 +68,7 @@ class ResolveReferencesToAliasesPass implements CompilerPassInterface
$defId = $this->getDefinitionId($id = (string) $argument);
if ($defId !== $id) {
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict());
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict(false));
}
}
}

View File

@ -180,6 +180,8 @@ class Container implements IntrospectableContainerInterface
* Setting a service to null resets the service: has() returns false and get()
* behaves in the same way as if the service was never created.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
@ -191,6 +193,10 @@ class Container implements IntrospectableContainerInterface
*/
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{
if (!in_array($scope, array('container', 'request')) || ('request' === $scope && 'request' !== $id)) {
@trigger_error('The concept of container scopes is deprecated since version 2.8 and will be removed in 3.0. Omit the third parameter.', E_USER_DEPRECATED);
}
if (self::SCOPE_PROTOTYPE === $scope) {
throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id));
}
@ -397,9 +403,15 @@ class Container implements IntrospectableContainerInterface
* @throws InvalidArgumentException When the scope does not exist
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function enterScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (!isset($this->scopes[$name])) {
throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
}
@ -445,9 +457,15 @@ class Container implements IntrospectableContainerInterface
* @throws InvalidArgumentException if the scope is not active
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function leaveScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (!isset($this->scopedServices[$name])) {
throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
}
@ -492,12 +510,17 @@ class Container implements IntrospectableContainerInterface
* @throws InvalidArgumentException
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function addScope(ScopeInterface $scope)
{
$name = $scope->getName();
$parentScope = $scope->getParentName();
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
}
@ -526,9 +549,15 @@ class Container implements IntrospectableContainerInterface
* @return bool
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function hasScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return isset($this->scopes[$name]);
}
@ -542,9 +571,13 @@ class Container implements IntrospectableContainerInterface
* @return bool
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isScopeActive($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
return isset($this->scopedServices[$name]);
}

View File

@ -358,9 +358,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @return array An array of scopes
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScopes()
public function getScopes($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopes;
}
@ -370,15 +376,23 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @return array An array of scope children.
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScopeChildren()
public function getScopeChildren($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopeChildren;
}
/**
* Sets a service.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope
@ -1176,7 +1190,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private function shareService(Definition $definition, $service, $id)
{
if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
if ($definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
throw new InactiveScopeException($id, $scope);
}

View File

@ -34,6 +34,8 @@ interface ContainerInterface
/**
* Sets a service.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
@ -110,6 +112,8 @@ interface ContainerInterface
* @param string $name
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function enterScope($name);
@ -119,6 +123,8 @@ interface ContainerInterface
* @param string $name
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function leaveScope($name);
@ -128,6 +134,8 @@ interface ContainerInterface
* @param ScopeInterface $scope
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function addScope(ScopeInterface $scope);
@ -139,6 +147,8 @@ interface ContainerInterface
* @return bool
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function hasScope($name);
@ -152,6 +162,8 @@ interface ContainerInterface
* @return bool
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isScopeActive($name);
}

View File

@ -29,6 +29,7 @@ class Definition
private $factoryClass;
private $factoryMethod;
private $factoryService;
private $shared = true;
private $scope = ContainerInterface::SCOPE_CONTAINER;
private $properties = array();
private $calls = array();
@ -94,6 +95,7 @@ class Definition
* @return Definition The current instance
*
* @api
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryClass($factoryClass)
@ -111,6 +113,7 @@ class Definition
* @return string|null The factory class name
*
* @api
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function getFactoryClass($triggerDeprecationError = true)
@ -130,6 +133,7 @@ class Definition
* @return Definition The current instance
*
* @api
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryMethod($factoryMethod)
@ -182,6 +186,7 @@ class Definition
* @return string|null The factory method name
*
* @api
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function getFactoryMethod($triggerDeprecationError = true)
@ -201,6 +206,7 @@ class Definition
* @return Definition The current instance
*
* @api
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryService($factoryService)
@ -218,6 +224,7 @@ class Definition
* @return string|null The factory service id
*
* @api
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function getFactoryService($triggerDeprecationError = true)
@ -597,6 +604,34 @@ class Definition
return $this->file;
}
/**
* Sets if the service must be shared or not.
*
* @param bool $shared Whether the service must be shared or not
*
* @return Definition The current instance
*
* @api
*/
public function setShared($shared)
{
$this->shared = (bool) $shared;
return $this;
}
/**
* Whether this service is shared.
*
* @return bool
*
* @api
*/
public function isShared()
{
return $this->shared;
}
/**
* Sets the scope of the service.
*
@ -605,9 +640,15 @@ class Definition
* @return Definition The current instance
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function setScope($scope)
public function setScope($scope, $triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
$this->scope = $scope;
return $this;
@ -619,9 +660,15 @@ class Definition
* @return string
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScope()
public function getScope($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scope;
}

View File

@ -173,7 +173,7 @@ class GraphvizDumper extends Dumper
} catch (ParameterNotFoundException $e) {
}
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $className), 'attributes' => array_merge($this->options['node.definition'], array('style' => ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope() ? 'filled' : 'dotted')));
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $className), 'attributes' => array_merge($this->options['node.definition'], array('style' => $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false) ? 'filled' : 'dotted')));
$container->setDefinition($id, new Definition('stdClass'));
}
@ -201,7 +201,7 @@ class GraphvizDumper extends Dumper
$container->setDefinitions($this->container->getDefinitions());
$container->setAliases($this->container->getAliases());
$container->setResources($this->container->getResources());
foreach ($this->container->getScopes() as $scope => $parentScope) {
foreach ($this->container->getScopes(false) as $scope => $parentScope) {
$container->addScope(new Scope($scope, $parentScope));
}
foreach ($this->container->getExtensions() as $extension) {

View File

@ -382,9 +382,9 @@ class PhpDumper extends Dumper
$isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
$instantiation = '';
if (!$isProxyCandidate && ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
if (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
$instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
} elseif (!$isProxyCandidate && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
} elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
$instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
} elseif (!$simple) {
$instantiation = '$instance';
@ -578,7 +578,7 @@ class PhpDumper extends Dumper
$return[] = sprintf('@return object An instance returned by %s::%s().', $definition->getFactoryService(false), $definition->getFactoryMethod(false));
}
$scope = $definition->getScope();
$scope = $definition->getScope(false);
if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
$return[] = '';
@ -589,7 +589,7 @@ class PhpDumper extends Dumper
$return = implode("\n * ", $return);
$doc = '';
if (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
$doc .= <<<EOF
*
@ -860,10 +860,10 @@ EOF;
EOF;
if (count($scopes = $this->container->getScopes()) > 0) {
if (count($scopes = $this->container->getScopes(false)) > 0) {
$code .= "\n";
$code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren(false)).";\n";
}
$code .= $this->addMethodMap();
@ -907,9 +907,9 @@ EOF;
EOF;
$code .= "\n";
if (count($scopes = $this->container->getScopes()) > 0) {
if (count($scopes = $this->container->getScopes(false)) > 0) {
$code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren(false)).";\n";
} else {
$code .= " \$this->scopes = array();\n";
$code .= " \$this->scopeChildren = array();\n";

View File

@ -126,7 +126,10 @@ class XmlDumper extends Dumper
if ($definition->getFactoryService(false)) {
$service->setAttribute('factory-service', $definition->getFactoryService(false));
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
if (!$definition->isShared()) {
$service->setAttribute('shared', 'false');
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$service->setAttribute('scope', $scope);
}
if (!$definition->isPublic()) {
@ -283,7 +286,7 @@ class XmlDumper extends Dumper
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
$element->setAttribute('on-invalid', 'ignore');
}
if (!$value->isStrict()) {
if (!$value->isStrict(false)) {
$element->setAttribute('strict', 'false');
}
} elseif ($value instanceof Definition) {

View File

@ -128,7 +128,11 @@ class YamlDumper extends Dumper
$code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
if (!$definition->isShared()) {
$code .= " shared: false\n";
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$code .= sprintf(" scope: %s\n", $scope);
}
@ -212,7 +216,7 @@ class YamlDumper extends Dumper
}
/**
* Dumps callable to YAML format
* Dumps callable to YAML format.
*
* @param callable $callable
*

View File

@ -148,7 +148,7 @@ class XmlFileLoader extends FileLoader
$definition = new Definition();
}
foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
if ($value = $service->getAttribute($key)) {
if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
@trigger_error(sprintf('The "%s" attribute in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, $file), E_USER_DEPRECATED);
@ -158,6 +158,16 @@ class XmlFileLoader extends FileLoader
}
}
if ($value = $service->getAttribute('scope')) {
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
if ($triggerDeprecation) {
@trigger_error(sprintf('The "scope" attribute in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', $file), E_USER_DEPRECATED);
}
$definition->setScope(XmlUtils::phpize($value), false);
}
if ($value = $service->getAttribute('synchronized')) {
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');

View File

@ -163,8 +163,15 @@ class YamlFileLoader extends FileLoader
$definition->setClass($service['class']);
}
if (isset($service['shared'])) {
$definition->setShared($service['shared']);
}
if (isset($service['scope'])) {
$definition->setScope($service['scope']);
if ('request' !== $id) {
@trigger_error(sprintf('The "scope" key in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', $file), E_USER_DEPRECATED);
}
$definition->setScope($service['scope'], false);
}
if (isset($service['synthetic'])) {

View File

@ -87,6 +87,7 @@
</xsd:choice>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" />
<xsd:attribute name="shared" type="boolean" />
<xsd:attribute name="scope" type="xsd:string" />
<xsd:attribute name="public" type="boolean" />
<xsd:attribute name="synthetic" type="boolean" />

View File

@ -27,6 +27,8 @@ class Reference
/**
* Constructor.
*
* Note: The $strict parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param int $invalidBehavior The behavior when the service does not exist
* @param bool $strict Sets how this reference is validated
@ -64,9 +66,15 @@ class Reference
* Returns true when this Reference is strict.
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isStrict()
public function isStrict($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->strict;
}
}

View File

@ -17,6 +17,8 @@ namespace Symfony\Component\DependencyInjection;
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
class Scope implements ScopeInterface
{

View File

@ -17,6 +17,8 @@ namespace Symfony\Component\DependencyInjection;
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
interface ScopeInterface
{

View File

@ -30,6 +30,7 @@ class CheckDefinitionValidityPassTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @group legacy
*/
public function testProcessDetectsSyntheticPrototypeDefinitions()
{
@ -39,6 +40,18 @@ class CheckDefinitionValidityPassTest extends \PHPUnit_Framework_TestCase
$this->process($container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @group legacy
*/
public function testProcessDetectsSharedPrototypeDefinitions()
{
$container = new ContainerBuilder();
$container->register('a')->setShared(true)->setScope(ContainerInterface::SCOPE_PROTOTYPE);
$this->process($container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
*/

View File

@ -19,6 +19,9 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
{
/**
* @group legacy
*/
public function testProcessIgnoresScopeWideningIfNonStrictReference()
{
$container = new ContainerBuilder();
@ -30,6 +33,7 @@ class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \RuntimeException
* @group legacy
*/
public function testProcessDetectsScopeWidening()
{
@ -40,6 +44,9 @@ class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
$this->process($container);
}
/**
* @group legacy
*/
public function testProcessIgnoresCrossScopeHierarchyReferenceIfNotStrict()
{
$container = new ContainerBuilder();
@ -54,6 +61,7 @@ class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \RuntimeException
* @group legacy
*/
public function testProcessDetectsCrossScopeHierarchyReference()
{

View File

@ -41,6 +41,29 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($container->getDefinition('inlinable.service'), $arguments[0]);
}
public function testProcessDoesNotInlinesWhenAliasedServiceIsShared()
{
$container = new ContainerBuilder();
$container
->register('foo')
->setPublic(false)
;
$container->setAlias('moo', 'foo');
$container
->register('service')
->setArguments(array($ref = new Reference('foo')))
;
$this->process($container);
$arguments = $container->getDefinition('service')->getArguments();
$this->assertSame($ref, $arguments[0]);
}
/**
* @group legacy
*/
public function testProcessDoesNotInlineWhenAliasedServiceIsNotOfPrototypeScope()
{
$container = new ContainerBuilder();
@ -61,6 +84,38 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($ref, $arguments[0]);
}
public function testProcessDoesInlineNonSharedService()
{
$container = new ContainerBuilder();
$container
->register('foo')
->setShared(false)
;
$container
->register('bar')
->setPublic(false)
->setShared(false)
;
$container->setAlias('moo', 'bar');
$container
->register('service')
->setArguments(array(new Reference('foo'), $ref = new Reference('moo'), new Reference('bar')))
;
$this->process($container);
$arguments = $container->getDefinition('service')->getArguments();
$this->assertEquals($container->getDefinition('foo'), $arguments[0]);
$this->assertNotSame($container->getDefinition('foo'), $arguments[0]);
$this->assertSame($ref, $arguments[1]);
$this->assertEquals($container->getDefinition('bar'), $arguments[2]);
$this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
}
/**
* @group legacy
*/
public function testProcessDoesInlineServiceOfPrototypeScope()
{
$container = new ContainerBuilder();
@ -188,6 +243,9 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($ref, $args[0]);
}
/**
* @group legacy
*/
public function testProcessInlinesOnlyIfSameScope()
{
$container = new ContainerBuilder();

View File

@ -79,6 +79,9 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($def->isAbstract());
}
/**
* @group legacy
*/
public function testProcessDoesNotCopyScope()
{
$container = new ContainerBuilder();

View File

@ -61,6 +61,9 @@ class ResolveInvalidReferencesPassTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(), $def->getProperties());
}
/**
* @group legacy
*/
public function testStrictFlagIsPreserved()
{
$container = new ContainerBuilder();

View File

@ -117,10 +117,21 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('Circular reference detected for service "baz", path: "baz".', $e->getMessage(), '->get() throws a LogicException if the service has a circular reference to itself');
}
$builder->register('foobar', 'stdClass')->setScope('container');
$this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
}
/**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::setShared
*/
public function testNonSharedServicesReturnsDifferentInstances()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass')->setShared(false);
$this->assertNotSame($builder->get('bar'), $builder->get('bar'));
}
/**
* @covers \Symfony\Component\DependencyInjection\ContainerBuilder::get
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
@ -143,6 +154,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
/**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
* @group legacy
*/
public function testGetReturnsNullOnInactiveScope()
{
@ -154,6 +166,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
/**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
* @group legacy
*/
public function testGetReturnsNullOnInactiveScopeWhenServiceIsCreatedByAMethod()
{

View File

@ -171,6 +171,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \InvalidArgumentException
* @group legacy
*/
public function testSetDoesNotAllowPrototypeScope()
{
@ -180,6 +181,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \RuntimeException
* @group legacy
*/
public function testSetDoesNotAllowInactiveScope()
{
@ -188,6 +190,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$c->set('foo', new \stdClass(), 'foo');
}
/**
* @group legacy
*/
public function testSetAlsoSetsScopedService()
{
$c = new Container();
@ -200,6 +205,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertSame($foo, $scoped['foo']['foo'], '->set() sets a scoped service');
}
/**
* @group legacy
*/
public function testSetAlsoCallsSynchronizeService()
{
$c = new ProjectServiceContainer();
@ -273,6 +281,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @covers Symfony\Component\DependencyInjection\Container::get
* @group legacy
*/
public function testGetReturnsNullOnInactiveScope()
{
@ -311,6 +320,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized');
}
/**
* @group legacy
*/
public function testEnterLeaveCurrentScope()
{
$container = new ProjectServiceContainer();
@ -336,6 +348,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertSame($scopedFoo1, $scopedFoo3);
}
/**
* @group legacy
*/
public function testEnterLeaveScopeWithChildScopes()
{
$container = new Container();
@ -366,6 +381,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($container->has('a'));
}
/**
* @group legacy
*/
public function testEnterScopeRecursivelyWithInactiveChildScopes()
{
$container = new Container();
@ -407,6 +425,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($container->has('a'));
}
/**
* @group legacy
*/
public function testEnterChildScopeRecursively()
{
$container = new Container();
@ -444,6 +465,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \InvalidArgumentException
* @group legacy
*/
public function testEnterScopeNotAdded()
{
@ -453,6 +475,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \RuntimeException
* @group legacy
*/
public function testEnterScopeDoesNotAllowInactiveParentScope()
{
@ -462,6 +485,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$container->enterScope('bar');
}
/**
* @group legacy
*/
public function testLeaveScopeNotActive()
{
$container = new Container();
@ -486,7 +512,8 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \InvalidArgumentException
* @dataProvider getBuiltInScopes
* @dataProvider getLegacyBuiltInScopes
* @group legacy
*/
public function testAddScopeDoesNotAllowBuiltInScopes($scope)
{
@ -496,6 +523,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \InvalidArgumentException
* @group legacy
*/
public function testAddScopeDoesNotAllowExistingScope()
{
@ -506,7 +534,8 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \InvalidArgumentException
* @dataProvider getInvalidParentScopes
* @dataProvider getLegacyInvalidParentScopes
* @group legacy
*/
public function testAddScopeDoesNotAllowInvalidParentScope($scope)
{
@ -514,6 +543,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$c->addScope(new Scope('foo', $scope));
}
/**
* @group legacy
*/
public function testAddScope()
{
$c = new Container();
@ -529,6 +561,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('foo' => array('bar', 'baz'), 'bar' => array('baz'), 'baz' => array()), $this->getField($c, 'scopeChildren'));
}
/**
* @group legacy
*/
public function testHasScope()
{
$c = new Container();
@ -577,6 +612,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
}
/**
* @group legacy
*/
public function testIsScopeActive()
{
$c = new Container();
@ -593,7 +631,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($c->isScopeActive('foo'));
}
public function getInvalidParentScopes()
public function getLegacyInvalidParentScopes()
{
return array(
array(ContainerInterface::SCOPE_PROTOTYPE),
@ -601,7 +639,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
);
}
public function getBuiltInScopes()
public function getLegacyBuiltInScopes()
{
return array(
array(ContainerInterface::SCOPE_CONTAINER),

View File

@ -127,9 +127,22 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', $def->getFile(), '->getFile() returns the file to include');
}
/**
* @covers Symfony\Component\DependencyInjection\Definition::setShared
* @covers Symfony\Component\DependencyInjection\Definition::isShared
*/
public function testSetIsShared()
{
$def = new Definition('stdClass');
$this->assertTrue($def->isShared(), '->isShared() returns true by default');
$this->assertSame($def, $def->setShared(false), '->setShared() implements a fluent interface');
$this->assertFalse($def->isShared(), '->isShared() returns false if the instance must not be shared');
}
/**
* @covers Symfony\Component\DependencyInjection\Definition::setScope
* @covers Symfony\Component\DependencyInjection\Definition::getScope
* @group legacy
*/
public function testSetGetScope()
{

View File

@ -81,9 +81,12 @@ class GraphvizDumperTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(str_replace('%path%', __DIR__, file_get_contents(self::$fixturesPath.'/graphviz/services17.dot')), $dumper->dump(), '->dump() dumps services');
}
/**
* @group legacy
*/
public function testDumpWithScopes()
{
$container = include self::$fixturesPath.'/containers/container18.php';
$container = include self::$fixturesPath.'/containers/legacy-container18.php';
$dumper = new GraphvizDumper($container);
$this->assertEquals(str_replace('%path%', __DIR__, file_get_contents(self::$fixturesPath.'/graphviz/services18.dot')), $dumper->dump(), '->dump() dumps services');
}

View File

@ -28,12 +28,11 @@ $container
$container
->register('bar', 'Bar\FooClass')
->setArguments(array('foo', new Reference('foo.baz'), new Parameter('foo_bar')))
->setScope('container')
->setConfigurator(array(new Reference('foo.baz'), 'configure'))
;
$container
->register('foo_bar', '%foo_class%')
->setScope('prototype')
->setShared(false)
;
$container->getParameterBag()->clear();
$container->getParameterBag()->add(array(
@ -93,7 +92,6 @@ $container
$container
->register('new_factory', 'FactoryClass')
->setProperty('foo', 'bar')
->setScope('container')
->setPublic(false)
;
$container

View File

@ -30,8 +30,13 @@ $container->
setFactoryService('foo.baz')->
setFactoryMethod('getInstance')
;
$container
->register('foo_bar', '%foo_class%')
->setScope('prototype')
;
$container->getParameterBag()->clear();
$container->getParameterBag()->add(array(
'foo_class' => 'Bar\FooClass',
'baz_class' => 'BazClass',
'foo' => 'bar',
));

View File

@ -6,6 +6,7 @@ digraph sc {
node_foo [label="foo\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo_baz [label="foo.baz\nBazClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_factory_service [label="factory_service\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo_bar [label="foo_bar\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="dotted"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_bar [label="bar\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foo -> node_foo_baz [label="" style="filled"];

View File

@ -6,6 +6,9 @@
<services>
<service id="constructor" class="FooClass" factory-method="getInstance" />
<service id="factory_service" factory-method="getInstance" factory-service="baz_factory" />
<service id="scope.container" class="FooClass" scope="container" />
<service id="scope.custom" class="FooClass" scope="custom" />
<service id="scope.prototype" class="FooClass" scope="prototype" />
<service id="request" class="Request" synthetic="true" synchronized="true" lazy="true"/>
</services>
</container>

View File

@ -1,6 +1,7 @@
<?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">
<parameters>
<parameter key="foo_class">Bar\FooClass</parameter>
<parameter key="baz_class">BazClass</parameter>
<parameter key="foo">bar</parameter>
</parameters>
@ -32,5 +33,6 @@
<configurator class="%baz_class%" method="configureStatic1"/>
</service>
<service id="factory_service" class="Bar" factory-method="getInstance" factory-service="foo.baz"/>
<service id="foo_bar" class="%foo_class%" scope="prototype"/>
</services>
</container>

View File

@ -6,9 +6,7 @@
<services>
<service id="foo" class="FooClass" />
<service id="baz" class="BazClass" />
<service id="scope.container" class="FooClass" scope="container" />
<service id="scope.custom" class="FooClass" scope="custom" />
<service id="scope.prototype" class="FooClass" scope="prototype" />
<service id="not_shared" class="FooClass" shared="false" />
<service id="file" class="FooClass">
<file>%path%/foo.php</file>
</service>

View File

@ -40,7 +40,7 @@
<argument>%foo_bar%</argument>
<configurator service="foo.baz" method="configure"/>
</service>
<service id="foo_bar" class="%foo_class%" scope="prototype"/>
<service id="foo_bar" class="%foo_class%" shared="false"/>
<service id="method_call1" class="Bar\FooClass">
<file>%path%foo.php</file>
<call method="setBar">

View File

@ -1,6 +1,9 @@
services:
constructor: { class: FooClass, factory_method: getInstance }
factory_service: { class: BazClass, factory_method: getInstance, factory_service: baz_factory }
scope.container: { class: FooClass, scope: container }
scope.custom: { class: FooClass, scope: custom }
scope.prototype: { class: FooClass, scope: prototype }
request:
class: Request
synthetic: true

View File

@ -1,4 +1,5 @@
parameters:
foo_class: Bar\FooClass
baz_class: BazClass
foo: bar
@ -26,3 +27,6 @@ services:
class: Bar
factory_method: getInstance
factory_service: foo.baz
foo_bar:
class: %foo_class%
scope: prototype

View File

@ -1,9 +1,7 @@
services:
foo: { class: FooClass }
baz: { class: BazClass }
scope.container: { class: FooClass, scope: container }
scope.custom: { class: FooClass, scope: custom }
scope.prototype: { class: FooClass, scope: prototype }
not_shared: { class: FooClass, shared: false }
file: { class: FooClass, file: %path%/foo.php }
arguments: { class: FooClass, arguments: [foo, @foo, [true, false]] }
configurator1: { class: FooClass, configurator: sc_configure }

View File

@ -27,7 +27,7 @@ services:
configurator: ['@foo.baz', configure]
foo_bar:
class: %foo_class%
scope: prototype
shared: false
method_call1:
class: Bar\FooClass
file: %path%foo.php

View File

@ -204,6 +204,9 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertNull($services['factory_service']->getClass());
$this->assertEquals('baz_factory', $services['factory_service']->getFactoryService());
$this->assertEquals('getInstance', $services['factory_service']->getFactoryMethod());
$this->assertEquals('container', $services['scope.container']->getScope());
$this->assertEquals('custom', $services['scope.custom']->getScope());
$this->assertEquals('prototype', $services['scope.prototype']->getScope());
$this->assertTrue($services['request']->isSynthetic(), '->load() parses the synthetic flag');
$this->assertTrue($services['request']->isSynchronized(), '->load() parses the synchronized flag');
$this->assertTrue($services['request']->isLazy(), '->load() parses the lazy flag');
@ -217,11 +220,9 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
$loader->load('services6.xml');
$services = $container->getDefinitions();
$this->assertTrue(isset($services['foo']), '->load() parses <service> elements');
$this->assertFalse($services['not_shared']->isShared(), '->load() parses shared flag');
$this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Definition', $services['foo'], '->load() converts <service> element to Definition instances');
$this->assertEquals('FooClass', $services['foo']->getClass(), '->load() parses the class attribute');
$this->assertEquals('container', $services['scope.container']->getScope());
$this->assertEquals('custom', $services['scope.custom']->getScope());
$this->assertEquals('prototype', $services['scope.prototype']->getScope());
$this->assertEquals('%path%/foo.php', $services['file']->getFile(), '->load() parses the file tag');
$this->assertEquals(array('foo', new Reference('foo'), array(true, false)), $services['arguments']->getArguments(), '->load() parses the argument tags');
$this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag');

View File

@ -133,6 +133,9 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('BazClass', $services['factory_service']->getClass());
$this->assertEquals('baz_factory', $services['factory_service']->getFactoryService());
$this->assertEquals('getInstance', $services['factory_service']->getFactoryMethod());
$this->assertEquals('container', $services['scope.container']->getScope());
$this->assertEquals('custom', $services['scope.custom']->getScope());
$this->assertEquals('prototype', $services['scope.prototype']->getScope());
$this->assertTrue($services['request']->isSynthetic(), '->load() parses the synthetic flag');
$this->assertTrue($services['request']->isSynchronized(), '->load() parses the synchronized flag');
$this->assertTrue($services['request']->isLazy(), '->load() parses the lazy flag');
@ -146,11 +149,9 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
$loader->load('services6.yml');
$services = $container->getDefinitions();
$this->assertTrue(isset($services['foo']), '->load() parses service elements');
$this->assertFalse($services['not_shared']->isShared(), '->load() parses the shared flag');
$this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Definition', $services['foo'], '->load() converts service element to Definition instances');
$this->assertEquals('FooClass', $services['foo']->getClass(), '->load() parses the class attribute');
$this->assertEquals('container', $services['scope.container']->getScope());
$this->assertEquals('custom', $services['scope.custom']->getScope());
$this->assertEquals('prototype', $services['scope.prototype']->getScope());
$this->assertEquals('%path%/foo.php', $services['file']->getFile(), '->load() parses the file tag');
$this->assertEquals(array('foo', new Reference('foo'), array(true, false)), $services['arguments']->getArguments(), '->load() parses the argument tags');
$this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag');

View File

@ -92,6 +92,7 @@ class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
/**
* @expectedException \InvalidArgumentException
* @group legacy
*/
public function testTriggerAListenerServiceOutOfScope()
{
@ -111,6 +112,9 @@ class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
$dispatcher->dispatch('onEvent');
}
/**
* @group legacy
*/
public function testReEnteringAScope()
{
$event = new Event();