ProxyDumper::isProxyCandidate()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 2
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
/*
4
 * This file is part of the olvlvl/symfony-dependency-injection-proxy package.
5
 *
6
 * (c) Olivier Laviale <[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 olvlvl\SymfonyDependencyInjectionProxy;
13
14
use Exception;
15
use InvalidArgumentException;
16
use olvlvl\SymfonyDependencyInjectionProxy\InterfaceResolver\BasicInterfaceResolver;
17
use ReflectionException;
18
use Symfony\Component\DependencyInjection\Definition;
19
use Symfony\Component\DependencyInjection\Exception\LogicException;
20
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;
21
22
use function class_exists;
23
use function ltrim;
24
use function sprintf;
25
26
final class ProxyDumper implements DumperInterface
27
{
28
    /**
29
     * @var InterfaceResolver
30
     */
31
    private $interfaceResolver;
32
33
    /**
34
     * @var FactoryRenderer
35
     */
36
    private $factoryRenderer;
37
38
    public function __construct(InterfaceResolver $interfaceResolver = null, FactoryRenderer $factoryRenderer = null)
39
    {
40
        $this->interfaceResolver = $interfaceResolver ?? new BasicInterfaceResolver();
41
        $this->factoryRenderer = $factoryRenderer ?? new FactoryRenderer(new MethodRenderer());
42
    }
43
44
    /**
45
     * @inheritdoc
46
     */
47
    public function isProxyCandidate(Definition $definition): bool
48
    {
49
        $class = $definition->getClass();
50
51
        return $definition->isLazy() && ($definition->getFactory() || ($class && class_exists($class)));
52
    }
53
54
    /**
55
     * @inheritdoc
56
     * @throws Exception
57
     */
58
    public function getProxyFactoryCode(Definition $definition, string $id, string $factoryCode): string
59
    {
60
        if (!$factoryCode) {
61
            throw new InvalidArgumentException("Missing factory code to construct the service `$id`.");
62
        }
63
64
        $store = '';
65
66
        if ($definition->isShared()) {
67
            $store = sprintf(
68
                '$this->%s[\'%s\'] = ',
69
                $definition->isPublic() && !$definition->isPrivate() ? 'services' : 'privates',
70
                $id
71
            );
72
        }
73
74
        $interface = $this->findInterface($definition);
75
        $proxy = ltrim($this->renderFactory($interface, $factoryCode));
76
77
        return <<<PHPTPL
78
        if (\$lazyLoad) {
79
            return {$store}$proxy
80
        }
81
82
83
PHPTPL;
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89
    public function getProxyCode(Definition $definition): string
90
    {
91
        return '';
92
    }
93
94
    /**
95
     * @phpstan-return class-string
96
     * @throws Exception
97
     */
98
    private function findInterface(Definition $definition): string
99
    {
100
        $interface = $this->resolveInterfaceFromTags($definition);
101
102
        if ($interface) {
103
            return $interface;
104
        }
105
106
        $class = $definition->getClass();
107
108
        if (!$class) {
109
            throw new LogicException("Unable to resolve interface, class is missing.");
110
        }
111
112
        /** @phpstan-var class-string $class */
113
114
        return $this->interfaceResolver->resolveInterface($class);
115
    }
116
117
    /**
118
     * @phpstan-return class-string|null
119
     */
120
    private function resolveInterfaceFromTags(Definition $definition): ?string
121
    {
122
        $proxy = $definition->getTag('proxy');
123
124
        return $proxy[0]['interface'] ?? null;
125
    }
126
127
    /**
128
     * @phpstan-param class-string $interface
129
     *
130
     * @throws ReflectionException
131
     */
132
    private function renderFactory(string $interface, string $factoryCode): string
133
    {
134
        return ($this->factoryRenderer)($interface, $factoryCode);
135
    }
136
}
137