Passed
Push — master ( 0b4ab1...035e32 )
by Esteban De La Fuente
03:21
created

CompilerPass::processFoundationService()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 61
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 9.2708

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 44
nc 5
nop 3
dl 0
loc 61
ccs 35
cts 48
cp 0.7292
crap 9.2708
rs 7.9715
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Derafu: Biblioteca PHP (Núcleo).
7
 * Copyright (C) Derafu <https://www.derafu.org>
8
 *
9
 * Este programa es software libre: usted puede redistribuirlo y/o modificarlo
10
 * bajo los términos de la Licencia Pública General Affero de GNU publicada por
11
 * la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, o
12
 * (a su elección) cualquier versión posterior de la misma.
13
 *
14
 * Este programa se distribuye con la esperanza de que sea útil, pero SIN
15
 * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD
16
 * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la Licencia Pública
17
 * General Affero de GNU para obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace Derafu\Lib\Core\Foundation;
26
27
use Derafu\Lib\Core\Foundation\Contract\ServiceInterface;
28
use Derafu\Lib\Core\Helper\Str;
29
use LogicException;
30
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
31
use Symfony\Component\DependencyInjection\ContainerBuilder;
32
use Symfony\Component\DependencyInjection\Definition;
33
34
/**
35
 * Clase para modificar servicios durante la compilación.
36
 */
37
class CompilerPass implements CompilerPassInterface
38
{
39
    /**
40
     * Prefijo con el que deben ser nombrados todos los servicios asociados a la
41
     * aplicación.
42
     *
43
     * Esto se utiliza especialmente al nombrar paquetes, componentes y workers.
44
     *
45
     * @var string
46
     */
47
    protected string $servicesPrefix;
48
49
    /**
50
     * Patrones de búsqueda de clases de servicios de Foundation.
51
     *
52
     * Estas clases deben implementar además la interfaz ServiceInterface.
53
     *
54
     * @var array<string, string>
55
     */
56
    protected array $servicesPatterns = [
57
        // Strategies.
58
        'strategy' => "/\\\\Package\\\\([A-Za-z0-9_]+)\\\\Component\\\\([A-Za-z0-9_]+)\\\\Worker\\\\([A-Za-z0-9_]+)\\\\([A-Za-z0-9_]+)\\\\([A-Za-z0-9_]+)Strategy$/",
59
        // Workers.
60
        'worker' => "/\\\\Package\\\\([A-Za-z0-9_]+)\\\\Component\\\\([A-Za-z0-9_]+)\\\\Contract\\\\([A-Za-z0-9]+)WorkerInterface$/",
61
        // Components.
62
        'component' => "/\\\\Package\\\\([A-Za-z0-9_]+)\\\\Component\\\\([A-Za-z0-9_]+)\\\\Contract\\\\(?:[A-Z][a-zA-Z0-9]+)ComponentInterface$/",
63
        // Packages.
64
        'package' => "/\\\\Package\\\\([A-Za-z0-9_]+)\\\\Contract\\\\(?:[A-Z][a-zA-Z0-9]+)PackageInterface$/",
65
    ];
66
67
    /**
68
     * Constructor de la clase.
69
     *
70
     * @param string $servicesPrefix
71
     */
72 16
    public function __construct(string $servicesPrefix)
73
    {
74 16
        $this->servicesPrefix = $servicesPrefix;
75
    }
76
77
    /**
78
     * Procesar servicios en tiempo de compilación.
79
     *
80
     * @param ContainerBuilder $container
81
     * @return void
82
     */
83 16
    public function process(ContainerBuilder $container): void
84
    {
85 16
        foreach ($container->getDefinitions() as $id => $definition) {
86
            // Omitir servicios sintéticos y abstractos.
87
            //   - Sintéticos: si el contenedor no lo crea ni lo gestiona.
88
            //   - Abstractos: plantilla que otros servicios heredan.
89
            // Solo se procesarán servicios reales (ni sintéticos ni abstractos)
90
            // y que son gestionados directamente por el contenedor.
91 16
            if ($definition->isSynthetic() || $definition->isAbstract()) {
92 16
                continue;
93
            }
94
95
            // Procesar paquetes, componentes y workers.
96 16
            $this->processFoundationService($id, $definition, $container);
97
98
            // Asignar los servicios como lazy.
99
            // Se creará un proxy y se cargará solo al acceder al servicio. Esto
100
            // es cuando se acceda a un método o propiedas (aunque no deberían
101
            // existir propiedades públicas en servicios). No se cargará el
102
            // servicio si solo se inyecta y guarda en el atributo de una clase.
103 16
            $definition->setLazy(true);
104
        }
105
    }
106
107
    /**
108
     * Procesa un servicio registrado en el contenedor.
109
     *
110
     * Este método permite realizar de manera automática:
111
     *
112
     *   - Crear alias para paquetes, componentes, workers y estrategias.
113
     *   - Agregar un tag a paquetes, componentes, workers y estrategias.
114
     *   - Marcar como servicio público los paquetes.
115
     *
116
     * @param string $id
117
     * @param Definition $definition
118
     * @param ContainerBuilder $container
119
     * @return void
120
     */
121 16
    private function processFoundationService(
122
        string $id,
123
        Definition $definition,
124
        ContainerBuilder $container
125
    ): void {
126
        // Solo se procesan servicios que implementen `ServiceInterface`.
127
        if (
128 16
            str_contains($id, '.')
129 10
            || !str_contains($id, '\\')
130 16
            || !in_array(ServiceInterface::class, (array) class_implements($id))
131
        ) {
132 6
            return;
133
        }
134
135
        // Revisar si la clase hace match con alguno de los patrones de búsqueda
136
        // de clases de servicios de Foundation.
137 10
        foreach ($this->servicesPatterns as $type => $regex) {
138 10
            if (preg_match($regex, $id, $matches)) {
139 10
                $package = Str::snake($matches[1]);
140 10
                $component = Str::snake($matches[2] ?? '');
141 10
                $worker = Str::snake($matches[3] ?? '');
142 10
                $strategyGroup = Str::snake($matches[4] ?? '');
143 10
                $strategy = Str::snake($matches[5] ?? '');
144 10
                if ($strategyGroup && $strategy) {
145
                    $strategy = $strategyGroup . '.' . $strategy;
146
                }
147
148 10
                match($type) {
149 10
                    'package' => $this->processServicePackage(
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->processServicePac..., $package, $container) targeting Derafu\Lib\Core\Foundati...processServicePackage() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
150 10
                        $id,
151 10
                        $definition,
152 10
                        $package,
153 10
                        $container
154 10
                    ),
155 10
                    'component' => $this->processServiceComponent(
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->processServiceCom...$component, $container) targeting Derafu\Lib\Core\Foundati...ocessServiceComponent() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
156 10
                        $id,
157 10
                        $definition,
158 10
                        $package,
159 10
                        $component,
160 10
                        $container
161 10
                    ),
162 10
                    'worker' => $this->processServiceWorker(
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->processServiceWor...t, $worker, $container) targeting Derafu\Lib\Core\Foundati...:processServiceWorker() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
163 10
                        $id,
164 10
                        $definition,
165 10
                        $package,
166 10
                        $component,
167 10
                        $worker,
168 10
                        $container
169 10
                    ),
170
                    'strategy' => $this->processServiceStrategy(
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->processServiceStr... $strategy, $container) targeting Derafu\Lib\Core\Foundati...rocessServiceStrategy() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
171
                        $id,
172
                        $definition,
173
                        $package,
174
                        $component,
175
                        $worker,
176
                        $strategy,
177
                        $container
178
                    ),
179
                    default => throw new LogicException(sprintf(
180
                        'Tipo de servicio %s no es manejado por CompilerPass::processFoundationService().',
181
                        $type
182
                    )),
183 10
                };
184
            }
185
        }
186
    }
187
188
    /**
189
     * Procesa un servicio que representa un paquete.
190
     *
191
     * @param string $serviceId
192
     * @param Definition $definition
193
     * @param string $package
194
     * @param ContainerBuilder $container
195
     * @return void
196
     */
197 10
    private function processServicePackage(
198
        string $serviceId,
199
        Definition $definition,
200
        string $package,
201
        ContainerBuilder $container
202
    ): void {
203 10
        $aliasId = $this->servicesPrefix . $package;
204 10
        $alias = $container->setAlias($aliasId, $serviceId);
205 10
        $alias->setPublic(true);
206
207 10
        $definition->addTag('package', [
208 10
            'name' => $package,
209 10
        ]);
210
    }
211
212
    /**
213
     * Procesa un servicio que representa un componente.
214
     *
215
     * @param string $serviceId
216
     * @param Definition $definition
217
     * @param string $package
218
     * @param string $component
219
     * @param ContainerBuilder $container
220
     * @return void
221
     */
222 10
    private function processServiceComponent(
223
        string $serviceId,
224
        Definition $definition,
225
        string $package,
226
        string $component,
227
        ContainerBuilder $container
228
    ): void {
229 10
        $aliasId = $this->servicesPrefix . $package . '.' . $component;
230 10
        $alias = $container->setAlias($aliasId, $serviceId);
0 ignored issues
show
Unused Code introduced by
The assignment to $alias is dead and can be removed.
Loading history...
231
232 10
        $definition->addTag($package . '.component', [
233 10
            'name' => $component,
234 10
        ]);
235
    }
236
237
    /**
238
     * Procesa un servicio que representa un worker.
239
     *
240
     * @param string $serviceId
241
     * @param Definition $definition
242
     * @param string $package
243
     * @param string $component
244
     * @param string $worker
245
     * @param ContainerBuilder $container
246
     * @return void
247
     */
248 10
    private function processServiceWorker(
249
        string $serviceId,
250
        Definition $definition,
251
        string $package,
252
        string $component,
253
        string $worker,
254
        ContainerBuilder $container
255
    ): void {
256 10
        $aliasId = $this->servicesPrefix . $package . '.' . $component . '.' . $worker;
257 10
        $alias = $container->setAlias($aliasId, $serviceId);
0 ignored issues
show
Unused Code introduced by
The assignment to $alias is dead and can be removed.
Loading history...
258
259 10
        $definition->addTag($package . '.' . $component . '.worker', [
260 10
            'name' => $worker,
261 10
        ]);
262
    }
263
264
    /**
265
     * Procesa un servicio que representa un worker.
266
     *
267
     * @param string $serviceId
268
     * @param Definition $definition
269
     * @param string $package
270
     * @param string $component
271
     * @param string $worker
272
     * @param string $strategy
273
     * @param ContainerBuilder $container
274
     * @return void
275
     */
276
    private function processServiceStrategy(
277
        string $serviceId,
278
        Definition $definition,
279
        string $package,
280
        string $component,
281
        string $worker,
282
        string $strategy,
283
        ContainerBuilder $container
284
    ): void {
285
        $aliasId = $this->servicesPrefix . $package . '.' . $component . '.' . $worker . '.' . $strategy;
286
        $alias = $container->setAlias($aliasId, $serviceId);
0 ignored issues
show
Unused Code introduced by
The assignment to $alias is dead and can be removed.
Loading history...
287
288
        $definition->addTag($package . '.' . $component . '.' . $worker . '.strategy', [
289
            'name' => $strategy,
290
        ]);
291
    }
292
}
293