Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aeec585

Browse files
[DI] Optional class for class named services
1 parent 0d2dfa7 commit aeec585

File tree

5 files changed

+112
-10
lines changed

5 files changed

+112
-10
lines changed

src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,22 @@
1717

1818
/**
1919
* @author Guilhem N. <[email protected]>
20+
*
21+
* @deprecated since version 3.3, to be removed in 4.0.
2022
*/
2123
class FactoryReturnTypePass implements CompilerPassInterface
2224
{
25+
private $resolveClassPass;
26+
private $resolveClassPassChanges = array();
27+
28+
public function __construct(ResolveClassPass $resolveClassPass = null)
29+
{
30+
if (null === $resolveClassPass) {
31+
@trigger_error('The '.__CLASS__.' class is deprecated since version 3.3 and will be removed in 4.0.', E_USER_DEPRECATED);
32+
}
33+
$this->resolveClassPass = $resolveClassPass;
34+
}
35+
2336
/**
2437
* {@inheritdoc}
2538
*/
@@ -29,6 +42,9 @@ public function process(ContainerBuilder $container)
2942
if (!method_exists(\ReflectionMethod::class, 'getReturnType')) {
3043
return;
3144
}
45+
if (null !== $this->resolveClassPass) {
46+
$this->resolveClassPassChanges = $this->resolveClassPass->getChanges();
47+
}
3248

3349
foreach ($container->getDefinitions() as $id => $definition) {
3450
$this->updateDefinition($container, $id, $definition);
@@ -43,7 +59,7 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $
4359
}
4460

4561
$factory = $definition->getFactory();
46-
if (null === $factory || null !== $definition->getClass()) {
62+
if (null === $factory || (!isset($this->resolveClassPassChanges[$id]) && null !== $definition->getClass())) {
4763
return;
4864
}
4965

@@ -83,6 +99,9 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $
8399
}
84100
}
85101

102+
if (null !== $returnType && (!isset($this->resolveClassPassChanges[$id]) || $returnType !== $this->resolveClassPassChanges[$id])) {
103+
@trigger_error(sprintf('Relying on its factory\'s return-type to define the class of service "%s" is deprecated since Symfony 3.3 and won\'t work in 4.0. Set the "class" attribute to "%s" on the service definition instead.', $id, $returnType), E_USER_DEPRECATED);
104+
}
86105
$definition->setClass($returnType);
87106
}
88107
}

src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ public function __construct()
4141

4242
$this->optimizationPasses = array(array(
4343
new ExtensionCompilerPass(),
44+
$resolveClassPass = new ResolveClassPass(),
4445
new ResolveDefinitionTemplatesPass(),
4546
new DecoratorServicePass(),
4647
new ResolveParameterPlaceHoldersPass(),
47-
new FactoryReturnTypePass(),
48+
new FactoryReturnTypePass($resolveClassPass),
4849
new CheckDefinitionValidityPass(),
4950
new ResolveReferencesToAliasesPass(),
5051
new ResolveInvalidReferencesPass(),
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\ChildDefinition;
16+
17+
/**
18+
* @author Nicolas Grekas <[email protected]>
19+
*/
20+
class ResolveClassPass implements CompilerPassInterface
21+
{
22+
private $changes = array();
23+
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function process(ContainerBuilder $container)
28+
{
29+
foreach ($container->getDefinitions() as $id => $definition) {
30+
if ($definition instanceof ChildDefinition || $definition->isSynthetic() || null !== $definition->getClass()) {
31+
continue;
32+
}
33+
$this->changes[$id] = $container->getCaseFullId($id);
34+
$definition->setClass($this->changes[$id]);
35+
}
36+
}
37+
38+
/**
39+
* @internal
40+
*
41+
* @deprecated since 3.3, to be removed in 4.0.
42+
*/
43+
public function getChanges()
44+
{
45+
$changes = $this->changes;
46+
$this->changes = array();
47+
48+
return $changes;
49+
}
50+
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
100100
*/
101101
private $envCounters = array();
102102

103+
/**
104+
* @var string[] A map of case less to case full ids
105+
*/
106+
private $caseFullIds = array();
107+
103108
/**
104109
* Sets the track resources flag.
105110
*
@@ -364,14 +369,18 @@ public function getCompiler()
364369
*/
365370
public function set($id, $service)
366371
{
367-
$id = strtolower($id);
372+
$caseFullId = (string) $id;
373+
$id = strtolower($caseFullId);
368374

369375
if ($this->isFrozen() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
370376
// setting a synthetic service on a frozen container is alright
371377
throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a frozen container is not allowed.', $id));
372378
}
373379

374380
unset($this->definitions[$id], $this->aliasDefinitions[$id]);
381+
if ($id !== $caseFullId) {
382+
$this->caseFullIds[$id] = $caseFullId;
383+
}
375384

376385
parent::set($id, $service);
377386
}
@@ -625,7 +634,8 @@ public function setAliases(array $aliases)
625634
*/
626635
public function setAlias($alias, $id)
627636
{
628-
$alias = strtolower($alias);
637+
$caseFullAlias = (string) $alias;
638+
$alias = strtolower($caseFullAlias);
629639

630640
if (is_string($id)) {
631641
$id = new Alias($id);
@@ -638,6 +648,9 @@ public function setAlias($alias, $id)
638648
}
639649

640650
unset($this->definitions[$alias]);
651+
if ($alias !== $caseFullAlias) {
652+
$this->caseFullIds[$alias] = $caseFullAlias;
653+
}
641654

642655
$this->aliasDefinitions[$alias] = $id;
643656
}
@@ -775,9 +788,13 @@ public function setDefinition($id, Definition $definition)
775788
throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
776789
}
777790

778-
$id = strtolower($id);
791+
$caseFullId = (string) $id;
792+
$id = strtolower($caseFullId);
779793

780794
unset($this->aliasDefinitions[$id]);
795+
if ($id !== $caseFullId) {
796+
$this->caseFullIds[$id] = $caseFullId;
797+
}
781798

782799
return $this->definitions[$id] = $definition;
783800
}
@@ -836,6 +853,20 @@ public function findDefinition($id)
836853
return $this->getDefinition($id);
837854
}
838855

856+
/**
857+
* Returns the case full id used at registration time if any.
858+
*
859+
* @param string $id
860+
*
861+
* @return string
862+
*/
863+
public function getCaseFullId($id)
864+
{
865+
$id = strtolower($id);
866+
867+
return isset($this->caseFullIds[$id]) ? $this->caseFullIds[$id] : $id;
868+
}
869+
839870
/**
840871
* Creates a service for a service definition.
841872
*

src/Symfony/Component/DependencyInjection/Tests/Compiler/FactoryReturnTypePassTest.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
/**
2222
* @author Guilhem N. <[email protected]>
23+
*
24+
* @group legacy
2325
*/
2426
class FactoryReturnTypePassTest extends \PHPUnit_Framework_TestCase
2527
{
@@ -103,17 +105,16 @@ public function testCircularReference()
103105
$this->assertNull($factory2->getClass());
104106
}
105107

108+
/**
109+
* @requires function ReflectionMethod::getReturnType
110+
* @expectedDeprecation Relying on its factory's return-type to define the class of service "factory" is deprecated since Symfony 3.3 and won't work in 4.0. Set the "class" attribute to "Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy" on the service definition instead.
111+
*/
106112
public function testCompile()
107113
{
108114
$container = new ContainerBuilder();
109115

110116
$factory = $container->register('factory');
111117
$factory->setFactory(array(FactoryDummy::class, 'createFactory'));
112-
113-
if (!method_exists(\ReflectionMethod::class, 'getReturnType')) {
114-
$this->setExpectedException(\RuntimeException::class, 'Please add the class to service "factory" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.');
115-
}
116-
117118
$container->compile();
118119

119120
$this->assertEquals(FactoryDummy::class, $container->getDefinition('factory')->getClass());

0 commit comments

Comments
 (0)