-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
/
FactoryReturnTypePass.php
110 lines (97 loc) · 4.14 KB
/
FactoryReturnTypePass.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Guilhem N. <egetick@gmail.com>
*
* @deprecated since version 3.3, to be removed in 4.0.
*/
class FactoryReturnTypePass implements CompilerPassInterface
{
private $resolveClassPass;
public function __construct(ResolveClassPass $resolveClassPass = null)
{
if (null === $resolveClassPass) {
@trigger_error('The '.__CLASS__.' class is deprecated since version 3.3 and will be removed in 4.0.', E_USER_DEPRECATED);
}
$this->resolveClassPass = $resolveClassPass;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
// works only since php 7.0 and hhvm 3.11
if (!method_exists(\ReflectionMethod::class, 'getReturnType')) {
return;
}
$resolveClassPassChanges = null !== $this->resolveClassPass ? $this->resolveClassPass->getChanges() : array();
foreach ($container->getDefinitions() as $id => $definition) {
$this->updateDefinition($container, $id, $definition, $resolveClassPassChanges);
}
}
private function updateDefinition(ContainerBuilder $container, $id, Definition $definition, array $resolveClassPassChanges, array $previous = array())
{
// circular reference
$lcId = strtolower($id);
if (isset($previous[$lcId])) {
return;
}
$factory = $definition->getFactory();
if (null === $factory || (!isset($resolveClassPassChanges[$lcId]) && null !== $definition->getClass())) {
return;
}
$class = null;
if (is_string($factory)) {
try {
$m = new \ReflectionFunction($factory);
if (false !== $m->getFileName() && file_exists($m->getFileName())) {
$container->addResource(new FileResource($m->getFileName()));
}
} catch (\ReflectionException $e) {
return;
}
} else {
if ($factory[0] instanceof Reference) {
$previous[$lcId] = true;
$factoryDefinition = $container->findDefinition((string) $factory[0]);
$this->updateDefinition($container, $factory[0], $factoryDefinition, $resolveClassPassChanges, $previous);
$class = $factoryDefinition->getClass();
} else {
$class = $factory[0];
}
try {
$m = new \ReflectionMethod($class, $factory[1]);
} catch (\ReflectionException $e) {
return;
}
}
$returnType = $m->getReturnType();
if (null !== $returnType && !$returnType->isBuiltin()) {
$returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString();
if (null !== $class) {
$declaringClass = $m->getDeclaringClass()->getName();
if ('self' === strtolower($returnType)) {
$returnType = $declaringClass;
} elseif ('parent' === strtolower($returnType)) {
$returnType = get_parent_class($declaringClass) ?: null;
}
}
if (null !== $returnType && (!isset($resolveClassPassChanges[$lcId]) || $returnType !== $resolveClassPassChanges[$lcId])) {
@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);
}
$definition->setClass($returnType);
}
}
}