Test Failed
Push — develop ( 8fcf9d...8b5bdd )
by nguereza
02:43
created

Application::setVendorPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Platine Framework
5
 *
6
 * Platine Framework is a lightweight, high-performance, simple and elegant
7
 * PHP Web framework
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine Framework
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file Application.php
34
 *
35
 *  The Platine Application class
36
 *
37
 *  @package    Platine\Framework\App
38
 *  @author Platine Developers team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   http://www.iacademy.cf
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Framework\App;
49
50
use InvalidArgumentException;
51
use Platine\Config\Config;
52
use Platine\Config\FileLoader;
53
use Platine\Container\Container;
54
use Platine\Event\DispatcherInterface;
55
use Platine\Event\EventInterface;
56
use Platine\Event\ListenerInterface;
57
use Platine\Framework\Service\Provider\BaseServiceProvider;
58
use Platine\Framework\Service\Provider\EventServiceProvider;
59
use Platine\Framework\Service\ServiceProvider;
60
61
/**
62
 * @class Application
63
 * @package Platine\Framework\App
64
 * @template T
65
 */
66
class Application extends Container
67
{
68
69
    /**
70
     * The application version
71
     */
72
    public const VERSION = '1.0.0-dev';
73
74
    /**
75
     * The event dispatcher instance
76
     * @var DispatcherInterface
77
     */
78
    protected DispatcherInterface $dispatcher;
79
80
    /**
81
     * The base path for this application
82
     * @var string
83
     */
84
    protected string $basePath = '';
85
86
    /**
87
     * The vendor path
88
     * @var string
89
     */
90
    protected string $vendorPath = '';
91
92
    /**
93
     * The Application path
94
     * @var string
95
     */
96
    protected string $appPath = '';
97
98
    /**
99
     * The application configuration path
100
     * @var string
101
     */
102
    protected string $configPath = 'config';
103
104
    /**
105
     * The application storage path
106
     * @var string
107
     */
108
    protected string $storagePath = 'storage';
109
110
    /**
111
     * The list of service providers
112
     * @var array<string, ServiceProvider>
113
     */
114
    protected array $providers = [];
115
116
    /**
117
     * Whether the system already booted
118
     * @var bool
119
     */
120
    protected bool $booted = false;
121
122
    /**
123
     * The application environment
124
     * @var string
125
     */
126
    protected string $env = 'dev';
127
128
    /**
129
     * Create new instance
130
     * @param string $basePath
131
     */
132
    public function __construct(string $basePath = '')
133
    {
134
        parent::__construct();
135
        $this->basePath = $basePath;
136
        $this->loadCoreServiceProviders();
137
138
        $this->dispatcher = $this->get(DispatcherInterface::class);
139
    }
140
141
    /**
142
     * Return the application version
143
     * @return string
144
     */
145
    public function version(): string
146
    {
147
        return self::VERSION;
148
    }
149
150
    /**
151
     * Return the current environment
152
     * @return string
153
     */
154
    public function getEnv(): string
155
    {
156
        return $this->env;
157
    }
158
159
    /**
160
     * Set the environment
161
     * @param string $env
162
     * @return $this
163
     */
164
    public function setEnv(string $env)
165
    {
166
        $this->env = $env;
167
168
        return $this;
169
    }
170
171
    /**
172
     * Return the storage path
173
     * @return string
174
     */
175
    public function getStoragePath(): string
176
    {
177
        return $this->storagePath;
178
    }
179
180
    /**
181
     * Set the storage path
182
     * @param string $storagePath
183
     * @return $this
184
     */
185
    public function setStoragePath(string $storagePath): self
186
    {
187
        $this->storagePath = $storagePath;
188
189
        return $this;
190
    }
191
192
193
    /**
194
     * Return the vendor path
195
     * @return string
196
     */
197
    public function getVendorPath(): string
198
    {
199
        return $this->vendorPath;
200
    }
201
202
    /**
203
     * Return the application root path
204
     * @return string
205
     */
206
    public function getAppPath(): string
207
    {
208
        return $this->appPath;
209
    }
210
211
    /**
212
     * Set vendor path
213
     * @param string $vendorPath
214
     * @return $this
215
     */
216
    public function setVendorPath(string $vendorPath): self
217
    {
218
        $this->vendorPath = $vendorPath;
219
220
        return $this;
221
    }
222
223
    /**
224
     * Set Application path
225
     * @param string $appPath
226
     * @return $this
227
     */
228
    public function setAppPath(string $appPath): self
229
    {
230
        $this->appPath = $appPath;
231
232
        return $this;
233
    }
234
235
    /**
236
     * Return the application base path
237
     * @return string
238
     */
239
    public function getBasePath(): string
240
    {
241
        return $this->basePath;
242
    }
243
244
    /**
245
     * Set the application base path
246
     * @param string $basePath
247
     * @return $this
248
     */
249
    public function setBasePath(string $basePath): self
250
    {
251
        $this->basePath = $basePath;
252
253
        return $this;
254
    }
255
256
    /**
257
     * Return the application configuration path
258
     * @return string
259
     */
260
    public function getConfigPath(): string
261
    {
262
        return $this->configPath;
263
    }
264
265
    /**
266
     * Set the application configuration path
267
     * @param string $configPath
268
     * @return $this
269
     */
270
    public function setConfigPath(string $configPath): self
271
    {
272
        $this->configPath = $configPath;
273
274
        return $this;
275
    }
276
277
    /**
278
     * Dispatches an event to all registered listeners.
279
     * @param  string|EventInterface     $eventName the name of event of instance of EventInterface
280
     * @param  EventInterface|null $event  the instance of EventInterface or null
281
     * @return $this
282
     */
283
    public function dispatch($eventName, EventInterface $event = null): self
284
    {
285
        $this->dispatcher->dispatch($eventName, $event);
286
287
        return $this;
288
    }
289
290
    /**
291
     * Register a listener for the given event.
292
     *
293
     * @param string $eventName the name of event
294
     * @param ListenerInterface|callable|string $listener the Listener interface or any callable
295
     * @param int $priority the listener execution priority
296
     * @return $this
297
     */
298
    public function listen(
299
        string $eventName,
300
        $listener,
301
        int $priority = DispatcherInterface::PRIORITY_DEFAULT
302
    ): self {
303
        if (is_string($listener)) {
304
            $listener = $this->createListener($listener);
305
        }
306
        $this->dispatcher->addListener($eventName, $listener, $priority);
307
308
        return $this;
309
    }
310
311
    /**
312
     * Return the list of providers
313
     * @return array<string, ServiceProvider>
314
     */
315
    public function getProviders(): array
316
    {
317
        return $this->providers;
318
    }
319
320
    /**
321
     * Return the list of service providers commands
322
     * @return array<class-string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string>.
Loading history...
323
     */
324
    public function getProvidersCommands(): array
325
    {
326
        $commands = [];
327
        foreach ($this->providers as /** @var ServiceProvider $provider */ $provider) {
328
            $commands = array_merge($commands, $provider->getCommands());
329
        }
330
331
        return $commands;
332
    }
333
334
    /**
335
     * Boot the application
336
     * @return void
337
     */
338
    public function boot(): void
339
    {
340
        if ($this->booted) {
341
            return;
342
        }
343
344
        foreach ($this->providers as $provider) {
345
            $this->bootServiceProvider($provider);
346
        }
347
348
        $this->booted = true;
349
    }
350
351
    /**
352
     * Register the service provider
353
     * @param string|ServiceProvider $provider
354
     * @param bool $force whether to force registration of provider
355
     * if already loaded
356
     * @return ServiceProvider
357
     */
358
    public function registerServiceProvider(
359
        $provider,
360
        bool $force = false
361
    ): ServiceProvider {
362
        $registered = $this->getServiceProvider($provider);
363
        if ($registered && !$force) {
364
            return $registered;
365
        }
366
367
        if (is_string($provider)) {
368
            $provider = $this->createServiceProvider($provider);
369
        }
370
371
        $provider->register();
372
373
        $this->markProviderAsRegistered($provider);
374
375
        if ($this->booted) {
376
            $this->bootServiceProvider($provider);
377
        }
378
379
        return $provider;
380
    }
381
382
    /**
383
     * Return the registered service provider if exist
384
     * @param string|ServiceProvider $provider
385
     * @return ServiceProvider|null
386
     */
387
    public function getServiceProvider($provider): ?ServiceProvider
388
    {
389
        $name = is_string($provider)
390
                ? $provider
391
                : get_class($provider);
392
393
        return $this->providers[$name] ?? null;
394
    }
395
396
    /**
397
     * Load configured service providers
398
     * @return void
399
     */
400
    public function registerConfiguredServiceProviders(): void
401
    {
402
        /** @var Config<T> $config */
403
        $config = $this->get(Config::class);
404
405
        /** @var string[] $providers */
406
        $providers = $config->get('providers', []);
407
        foreach ($providers as $provider) {
408
            $this->registerServiceProvider($provider);
409
        }
410
    }
411
412
    /**
413
     * Load configured events and listeners
414
     * @return void
415
     */
416
    public function registerConfiguredEvents(): void
417
    {
418
        /** @var Config<T> $config */
419
        $config = $this->get(Config::class);
420
421
        /** @var array<string, string[]> $events */
422
        $events = $config->get('events', []);
423
        foreach ($events as $eventName => $listeners) {
424
            foreach ($listeners as $listener) {
425
                $this->listen($eventName, $listener);
426
            }
427
        }
428
    }
429
430
    /**
431
     * Load the application configuration
432
     * @return void
433
     */
434
    public function registerConfiguration(): void
435
    {
436
        $loader = new FileLoader($this->getConfigPath());
437
        $config = new Config($loader, $this->env);
438
        $this->instance($loader);
439
        $this->instance($config);
440
441
        date_default_timezone_set($config->get('app.timezone', 'UTC'));
442
    }
443
444
    /**
445
     * Create service provider
446
     * @param string $provider
447
     * @return ServiceProvider
448
     */
449
    protected function createServiceProvider(string $provider): ServiceProvider
450
    {
451
        return new $provider($this);
452
    }
453
454
    /**
455
     * Boot the given service provider
456
     * @param ServiceProvider $provider
457
     * @return void
458
     */
459
    protected function bootServiceProvider(ServiceProvider $provider): void
460
    {
461
        $provider->boot();
462
    }
463
464
    /**
465
     * Set the given service provider as registered
466
     * @param ServiceProvider $provider
467
     * @return void
468
     */
469
    protected function markProviderAsRegistered(ServiceProvider $provider): void
470
    {
471
        $this->providers[get_class($provider)] = $provider;
472
    }
473
474
    /**
475
     * Load framework core service providers
476
     * @return void
477
     */
478
    protected function loadCoreServiceProviders(): void
479
    {
480
        $this->registerServiceProvider(new BaseServiceProvider($this));
481
        $this->registerServiceProvider(new EventServiceProvider($this));
482
    }
483
484
    /**
485
     * Create listener using the container or direct class instance
486
     * @param string $listener
487
     * @return ListenerInterface
488
     */
489
    protected function createListener(string $listener): ListenerInterface
490
    {
491
        if ($this->has($listener)) {
492
            return $this->get($listener);
493
        }
494
495
        if (class_exists($listener)) {
496
            return new $listener();
497
        }
498
499
        throw new InvalidArgumentException(sprintf(
500
            'Can not resolve the listener class [%s], check if this is the'
501
                . ' identifier of container or class exists',
502
            $listener
503
        ));
504
    }
505
}
506