Test Failed
Push — master ( 4516e7...6ee9d0 )
by Esteban De La Fuente
04:23
created

AbstractApplication::resolveConfiguration()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.8437

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 1
dl 0
loc 16
ccs 5
cts 8
cp 0.625
crap 4.8437
rs 10
c 0
b 0
f 0
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\Abstract;
26
27
use Derafu\Lib\Core\Foundation\Configuration;
28
use Derafu\Lib\Core\Foundation\Contract\ApplicationInterface;
29
use Derafu\Lib\Core\Foundation\Contract\ConfigurationInterface;
30
use Derafu\Lib\Core\Foundation\Contract\KernelInterface;
31
use Derafu\Lib\Core\Foundation\Contract\PackageInterface;
32
use LogicException;
33
use RuntimeException;
34
use Symfony\Component\Console\Application as SymfonyConsoleApplication;
35
use Symfony\Component\Console\Command\Command;
36
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
37
38
/**
39
 * Clase base para la clase principal de la aplicación.
40
 */
41
abstract class AbstractApplication implements ApplicationInterface
42
{
43
    /**
44
     * Instancia del núcleo de la aplicación.
45
     *
46
     * @var KernelInterface
47
     */
48
    private KernelInterface $kernel;
49
50
    /**
51
     * Instancia de la clase para el patrón singleton.
52
     *
53
     * @var self
54
     */
55
    private static self $instance;
56
57
    /**
58
     * Constructor de la aplicación.
59
     *
60
     * Debe ser privado para respetar el patrón singleton.
61
     *
62
     * @param string|array|null $config Configuración de la aplicación.
63
     * Puede ser la clase que implementa la configuración, una ruta al archivo
64
     * de configuración o un arreglo con la configuración.
65
     */
66 5
    private function __construct(string|array|null $config)
67
    {
68 5
        $this->initialize($config);
69
    }
70
71
    /**
72
     * Inicializa la aplicación.
73
     *
74
     * @param string|array|null $config
75
     */
76 5
    protected function initialize(string|array|null $config)
77
    {
78
        // Cargar configuración.
79 5
        $configuration = $this->resolveConfiguration($config);
80
81
        // Iniciar el kernel.
82 5
        $kernelClass = $configuration->getKernelClass();
83 5
        $this->kernel = new $kernelClass();
84 5
        $this->kernel->initialize($configuration);
85
    }
86
87
    /**
88
     * Resuelve y carga la configuración de la aplicación.
89
     *
90
     * @param string|array|null $config
91
     * @return ConfigurationInterface
92
     */
93 5
    protected function resolveConfiguration(
94
        string|array|null $config
95
    ): ConfigurationInterface {
96 5
        if ($config === null) {
0 ignored issues
show
introduced by
The condition $config === null is always false.
Loading history...
97
            return new Configuration();
98
        }
99
100 5
        if (is_array($config)) {
0 ignored issues
show
introduced by
The condition is_array($config) is always true.
Loading history...
101
            return new Configuration($config);
102
        }
103
104 5
        if (class_exists($config)) {
105
            return new $config();
106
        }
107
108 5
        return new Configuration($config);
109
    }
110
111
    /**
112
     * {@inheritDoc}
113
     */
114
    public function path(?string $path = null): string
115
    {
116
        return $this->kernel->getConfiguration()->resolvePath($path);
117
    }
118
119
    /**
120
     * {@inheritDoc}
121
     */
122
    public function config(string $name, mixed $default = null): mixed
123
    {
124
        return $this->kernel->getConfiguration()->get($name, $default);
125
    }
126
127
    /**
128
     * {@inheritDoc}
129
     */
130
    public function hasPackage(string $package): bool
131
    {
132
        $servicesPrefix = $this->kernel->getConfiguration()->getServicesPrefix();
133
        $service = $servicesPrefix . $package;
134
135
        return $this->kernel->getContainer()->has($service);
136
    }
137
138
    /**
139
     * {@inheritDoc}
140
     */
141
    public function getPackage(string $package): PackageInterface
142
    {
143
        $servicesPrefix = $this->kernel->getConfiguration()->getServicesPrefix();
144
        $service = $servicesPrefix . $package;
145
146
        try {
147
            $instance = $this->kernel->getContainer()->get($service);
148
        } catch (ServiceNotFoundException $e) {
149
            $instance = null;
150
        }
151
152
        if (!$instance instanceof PackageInterface) {
153
            throw new LogicException(sprintf(
154
                'El paquete %s no existe en la aplicación.',
155
                $package
156
            ));
157
        }
158
159
        $config = $this->kernel->getConfiguration()->getPackageConfiguration(
160
            $package
161
        );
162
        $instance->setConfiguration($config);
163
164
        return $instance;
165
    }
166
167
    /**
168
     * {@inheritDoc}
169
     */
170
    public function getPackages(): array
171
    {
172
        $packages = [];
173
        $ids = $this->kernel->getContainer()->findTaggedServiceIds('package');
174
        $servicesPrefix = $this->kernel->getConfiguration()->getServicesPrefix();
175
        foreach ($ids as $id => $tags) {
176
            $packages[str_replace($servicesPrefix, '', $id)] =
177
                $this->kernel->getContainer()->get($id)
178
            ;
179
        }
180
181
        return $packages;
182
    }
183
184
    /**
185
     * {@inheritDoc}
186
     */
187
    public function hasService(string $service): bool
188
    {
189
        return $this->kernel->getContainer()->has($service);
190
    }
191
192
    /**
193
     * {@inheritDoc}
194
     */
195 5
    public function getService(string $service): object
196
    {
197 5
        return $this->kernel->getContainer()->get($service);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->kernel->ge...tainer()->get($service) could return the type null which is incompatible with the type-hinted return object. Consider adding an additional type-check to rule them out.
Loading history...
198
    }
199
200
    /**
201
     * {@inheritDoc}
202
     */
203 5
    public static function getInstance(string|array|null $config = null): static
204
    {
205 5
        if (!isset(self::$instance)) {
206 5
            $class = static::class;
207 5
            self::$instance = new $class($config);
208
        }
209
210 5
        assert(self::$instance instanceof static);
211
212 5
        return self::$instance;
213
    }
214
215
    /**
216
     * {@inheritDoc}
217
     */
218
    public function run(): int
219
    {
220
        // Validar que sea una ejecución de línea de comandos.
221
        if (php_sapi_name() !== 'cli') {
222
            throw new RuntimeException(
223
                'Esta aplicación solo puede ejecutarse en la línea de comandos.'
224
            );
225
        }
226
227
        // Crear instancia de Symfony Console Application.
228
        $consoleApp = new SymfonyConsoleApplication();
229
230
        // Registrar comandos del contenedor.
231
        $commands = $this->kernel
232
            ->getContainer()
233
            ->findTaggedServiceIds('service:command')
234
        ;
235
        foreach ($commands as $id => $tags) {
236
            $command = $this->kernel->getContainer()->get($id);
237
            if ($command instanceof Command) {
238
                $consoleApp->add($command);
239
            }
240
        }
241
242
        // Ejecutar la consola.
243
        return $consoleApp->run();
244
    }
245
}
246