Passed
Push — master ( 6a582f...5c28cd )
by Esteban De La Fuente
05:08
created

AbstractApplication::run()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 12
c 0
b 0
f 0
nc 4
nop 0
dl 0
loc 26
ccs 0
cts 15
cp 0
crap 20
rs 9.8666
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\Adapter\ServiceAdapter;
28
use Derafu\Lib\Core\Foundation\Configuration;
29
use Derafu\Lib\Core\Foundation\Contract\ApplicationInterface;
30
use Derafu\Lib\Core\Foundation\Contract\ConfigurationInterface;
31
use Derafu\Lib\Core\Foundation\Contract\KernelInterface;
32
use Derafu\Lib\Core\Foundation\Contract\PackageInterface;
33
use Derafu\Lib\Core\Foundation\Contract\ServiceInterface;
34
use LogicException;
35
use RuntimeException;
36
use Symfony\Component\Console\Application as SymfonyConsoleApplication;
37
use Symfony\Component\Console\Command\Command;
38
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
39
40
/**
41
 * Clase base para la clase principal de la aplicación.
42
 */
43
abstract class AbstractApplication implements ApplicationInterface
44
{
45
    /**
46
     * Instancia del núcleo de la aplicación.
47
     *
48
     * @var KernelInterface
49
     */
50
    private KernelInterface $kernel;
51
52
    /**
53
     * Instancia de la clase para el patrón singleton.
54
     *
55
     * @var self
56
     */
57
    private static self $instance;
58
59
    /**
60
     * Constructor de la aplicación.
61
     *
62
     * Debe ser privado para respetar el patrón singleton.
63
     *
64
     * @param string|array|null $config Configuración de la aplicación.
65
     * Puede ser la clase que implementa la configuración, una ruta al archivo
66
     * de configuración o un arreglo con la configuración.
67
     */
68 16
    private function __construct(string|array|null $config)
69
    {
70 16
        $this->initialize($config);
71
    }
72
73
    /**
74
     * Inicializa la aplicación.
75
     *
76
     * @param string|array|null $config
77
     */
78 16
    protected function initialize(string|array|null $config)
79
    {
80
        // Cargar configuración.
81 16
        $configuration = $this->resolveConfiguration($config);
82
83
        // Iniciar el kernel.
84 16
        $kernelClass = $configuration->getKernelClass();
85 16
        $this->kernel = new $kernelClass();
86 16
        $this->kernel->initialize($configuration);
87
    }
88
89
    /**
90
     * Resuelve y carga la configuración de la aplicación.
91
     *
92
     * @param string|array|null $config
93
     * @return ConfigurationInterface
94
     */
95 16
    protected function resolveConfiguration(
96
        string|array|null $config
97
    ): ConfigurationInterface {
98 16
        if ($config === null) {
0 ignored issues
show
introduced by
The condition $config === null is always false.
Loading history...
99 10
            return new Configuration();
100
        }
101
102 6
        if (is_array($config)) {
0 ignored issues
show
introduced by
The condition is_array($config) is always true.
Loading history...
103
            return new Configuration($config);
104
        }
105
106 6
        if (class_exists($config)) {
107
            return new $config();
108
        }
109
110 6
        return new Configuration($config);
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function path(?string $path = null): string
117
    {
118
        return $this->kernel->getConfiguration()->resolvePath($path);
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function config(string $name, mixed $default = null): mixed
125
    {
126
        return $this->kernel->getConfiguration()->get($name, $default);
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function hasPackage(string $package): bool
133
    {
134
        $servicesPrefix = $this->kernel->getConfiguration()->getServicesPrefix();
135
        $service = $servicesPrefix . $package;
136
137
        return $this->kernel->getContainer()->has($service);
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143 6
    public function getPackage(string $package): PackageInterface
144
    {
145 6
        $servicesPrefix = $this->kernel->getConfiguration()->getServicesPrefix();
146 6
        $service = $servicesPrefix . $package;
147
148
        try {
149 6
            $instance = $this->kernel->getContainer()->get($service);
150
        } catch (ServiceNotFoundException $e) {
151
            $instance = null;
152
        }
153
154 6
        if (!$instance instanceof PackageInterface) {
155
            throw new LogicException(sprintf(
156
                'El paquete %s no existe en la aplicación.',
157
                $package
158
            ));
159
        }
160
161 6
        $config = $this->kernel->getConfiguration()->getPackageConfiguration(
162 6
            $package
163 6
        );
164 6
        $instance->setConfiguration($config);
165
166 6
        return $instance;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172 1
    public function getPackages(): array
173
    {
174 1
        $packages = [];
175 1
        $ids = $this->kernel->getContainer()->findTaggedServiceIds('package');
176 1
        $servicesPrefix = $this->kernel->getConfiguration()->getServicesPrefix();
177 1
        foreach ($ids as $id => $tags) {
178 1
            $packages[str_replace($servicesPrefix, '', $id)] =
179 1
                $this->kernel->getContainer()->get($id)
180 1
            ;
181
        }
182
183 1
        return $packages;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189
    public function hasService(string $service): bool
190
    {
191
        return $this->kernel->getContainer()->has($service);
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 8
    public function getService(string $service): ServiceInterface
198
    {
199 8
        $instance = $this->kernel->getContainer()->get($service);
200
201 4
        if ($instance instanceof ServiceInterface) {
202 2
            return $instance;
203
        }
204
205 2
        return new ServiceAdapter($instance);
0 ignored issues
show
Bug introduced by
It seems like $instance can also be of type null; however, parameter $adaptee of Derafu\Lib\Core\Foundati...eAdapter::__construct() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

205
        return new ServiceAdapter(/** @scrutinizer ignore-type */ $instance);
Loading history...
206
    }
207
208
    /**
209
     * {@inheritdoc}
210
     */
211 16
    public static function getInstance(string|array|null $config = null): static
212
    {
213 16
        if (!isset(self::$instance)) {
214 16
            $class = static::class;
215 16
            self::$instance = new $class($config);
216
        }
217
218 16
        assert(self::$instance instanceof static);
219
220 16
        return self::$instance;
221
    }
222
223
    /**
224
     * {@inheritdoc}
225
     */
226
    public function run(): int
227
    {
228
        // Validar que sea una ejecución de línea de comandos.
229
        if (php_sapi_name() !== 'cli') {
230
            throw new RuntimeException(
231
                'Esta aplicación solo puede ejecutarse en la línea de comandos.'
232
            );
233
        }
234
235
        // Crear instancia de Symfony Console Application.
236
        $consoleApp = new SymfonyConsoleApplication();
237
238
        // Registrar comandos del contenedor.
239
        $commands = $this->kernel
240
            ->getContainer()
241
            ->findTaggedServiceIds('service:command')
242
        ;
243
        foreach ($commands as $id => $tags) {
244
            $command = $this->kernel->getContainer()->get($id);
245
            if ($command instanceof Command) {
246
                $consoleApp->add($command);
247
            }
248
        }
249
250
        // Ejecutar la consola.
251
        return $consoleApp->run();
252
    }
253
}
254