Passed
Push — main ( 3399b6...dd4eea )
by Dimitri
11:50
created

Services::locator()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Container;
13
14
use BlitzPHP\Autoloader\Autoloader;
15
use BlitzPHP\Autoloader\Locator;
16
use BlitzPHP\Cache\Cache;
17
use BlitzPHP\Config\Config;
18
use BlitzPHP\Config\Database as DatabaseConfig;
19
use BlitzPHP\Debug\Logger;
20
use BlitzPHP\Debug\Timer;
21
use BlitzPHP\Debug\Toolbar;
22
use BlitzPHP\Event\EventManager;
23
use BlitzPHP\Filesystem\Filesystem;
24
use BlitzPHP\Filesystem\FilesystemManager;
25
use BlitzPHP\Http\Negotiator;
26
use BlitzPHP\HTTP\Redirection;
27
use BlitzPHP\Http\Request;
28
use BlitzPHP\Http\Response;
29
use BlitzPHP\Http\ResponseEmitter;
30
use BlitzPHP\Http\ServerRequest;
31
use BlitzPHP\Http\Uri;
32
use BlitzPHP\HttpClient\Request as ClientRequest;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\HttpClient\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
use BlitzPHP\Mail\Mail;
34
use BlitzPHP\Router\RouteCollection;
35
use BlitzPHP\Router\Router;
36
use BlitzPHP\Session\Handlers\Database as DatabaseSessionHandler;
37
use BlitzPHP\Session\Handlers\Database\MySQL as MySQLSessionHandler;
38
use BlitzPHP\Session\Handlers\Database\Postgre as PostgreSessionHandler;
39
use BlitzPHP\Session\Session;
40
use BlitzPHP\Translator\Translate;
41
use BlitzPHP\Utilities\Helpers;
42
use BlitzPHP\Utilities\String\Text;
43
use BlitzPHP\View\View;
44
use DI\NotFoundException;
45
use stdClass;
46
47
/**
48
 * Service
49
 *
50
 * Les services sont simplement d'autres classes/bibliothèques que le système utilise
51
 * pour faire son travail. Ceci est utilisé par BlitzPHP pour permettre au coeur du
52
 * framework à échanger facilement sans affecter l'utilisation à l'intérieur
53
 * le reste de votre application.
54
 *
55
 * Ceci est utilisé à la place d'un conteneur d'injection de dépendance principalement
56
 * en raison de sa simplicité, qui permet un meilleur entretien à long terme
57
 * des applications construites sur BlitzPHP. Un effet secondaire bonus
58
 * est que les IDE sont capables de déterminer quelle classe vous appelez
59
 * alors qu'avec les conteneurs DI, il n'y a généralement aucun moyen pour eux de le faire.
60
 */
61
class Services
62
{
63
    /**
64
     * Cache des instances des services demander comme instance "partagee".
65
     * La cle est le FQCN du service.
66
     */
67
    protected static array $instances = [];
68
69
    /**
70
     * Cache d'autres classe de que nous avons trouver via la methode discoverService.
71
     */
72
    protected static array $services = [];
73
74
    /**
75
     * @return Injector
76
     */
77
    public static function injector()
78
    {
79
        return Injector::instance();
80
    }
81
82
    /**
83
     * @return \DI\Container
84
     */
85
    public static function container()
86
    {
87
        return Injector::container();
88
    }
89
90
    /**
91
     * La classe Autoloader permet de charger les fichiers simplement.
92
     */
93
    public static function autoloader(bool $shared = true): Autoloader
94
    {
95
        if (true === $shared && isset(static::$instances[Autoloader::class])) {
96
            return static::$instances[Autoloader::class];
97
        }
98
99
        $config  = Config::get('autoload');
100
        $helpers = array_merge(['url'], ($config['helpers'] ?? []));
101
102
        return static::$instances[Autoloader::class] = static::factory(Autoloader::class, compact('config', 'helpers'));
103
    }
104
105
    /**
106
     * La classe de cache fournit un moyen simple de stocker et de récupérer
107
     * données complexes pour plus tard
108
     */
109
    public static function cache(?array $config = null, bool $shared = true): Cache
110
    {
111
        if (empty($config)) {
112
            $config = Config::get('cache');
113
        }
114
115
        if (true === $shared && isset(static::$instances[Cache::class])) {
116
            $instance = static::$instances[Cache::class];
117
            if (empty(func_get_args()[0])) {
118
                return $instance;
119
            }
120
121
            return $instance->setConfig($config);
122
        }
123
124
        return static::$instances[Cache::class] = static::factory(Cache::class, compact('config'));
125
    }
126
127
    /**
128
     * Émetteur de réponse au client
129
     */
130
    public static function emitter(bool $shared = true): ResponseEmitter
131
    {
132
        if (true === $shared && isset(static::$instances[ResponseEmitter::class])) {
133
            return static::$instances[ResponseEmitter::class];
134
        }
135
136
        return static::$instances[ResponseEmitter::class] = static::factory(ResponseEmitter::class);
137
    }
138
139
    /**
140
     * Gestionnaire d'evenement
141
     */
142
    public static function event(bool $shared = true): EventManager
143
    {
144
        if (true === $shared && isset(static::$instances[EventManager::class])) {
145
            return static::$instances[EventManager::class];
146
        }
147
148
        return static::$instances[EventManager::class] = static::factory(EventManager::class);
149
    }
150
151
    /**
152
     * System de gestion de fichier
153
     */
154
    public static function fs(bool $shared = true): Filesystem
155
    {
156
        if (true === $shared && isset(static::$instances[Filesystem::class])) {
157
            return static::$instances[Filesystem::class];
158
        }
159
160
        return static::$instances[Filesystem::class] = static::factory(Filesystem::class);
161
    }
162
163
    /**
164
     * Le client HTTP fourni une interface simple pour interagir avec d'autres serveurs.
165
     * Typiquement a traver des APIs.
166
     */
167
    public static function httpclient(?string $baseUrl = null, bool $shared = true): ClientRequest
168
    {
169
        if (true === $shared && isset(static::$instances[ClientRequest::class])) {
170
            return static::$instances[ClientRequest::class]->baseUrl((string) $baseUrl);
171
        }
172
173
        return static::$instances[ClientRequest::class] = static::factory(ClientRequest::class, ['event' => static::event()])->baseUrl((string) $baseUrl);
174
    }
175
176
    /**
177
     * Responsable du chargement des traductions des chaînes de langue.
178
     */
179
    public static function language(?string $locale = null, bool $shared = true): Translate
180
    {
181
        if (empty($locale)) {
182
            if (empty($locale = static::$instances[Translate::class . 'locale'] ?? null)) {
183
                $config = Config::get('app');
184
185
                if (empty($locale = static::negotiator()->language($config['supported_locales']))) {
186
                    $locale = $config['language'];
187
                }
188
189
                static::$instances[Translate::class . 'locale'] = $locale;
190
            }
191
        }
192
193
        if (true === $shared && isset(static::$instances[Translate::class])) {
194
            return static::$instances[Translate::class]->setLocale($locale);
195
        }
196
197
        return static::$instances[Translate::class] = static::factory(Translate::class, compact('locale'));
198
    }
199
200
    /**
201
     * Le file locator fournit des methodes utilitaire pour chercher les fichiers non-classes
202
     * dans les dossiers de namespace. C'est une excelente methode pour charger les 'vues', 'helpers', et 'libraries'.
203
     */
204
    public static function locator(bool $shared = true): Locator
205
    {
206
        if ($shared && isset(static::$instances[Locator::class])) {
207
            return static::$instances[Locator::class];
208
        }
209
210
        return static::$instances[Locator::class] = static::factory(Locator::class, ['autoloader' => static::autoloader()]);
211
    }
212
213
    /**
214
     * La classe Logger est une classe Logging compatible PSR-3 qui prend en charge
215
     * plusieurs gestionnaires qui traitent la journalisation réelle.
216
     */
217
    public static function logger(bool $shared = true): Logger
218
    {
219
        if ($shared && isset(static::$instances[Logger::class])) {
220
            return static::$instances[Logger::class];
221
        }
222
223
        return static::$instances[Logger::class] = static::factory(Logger::class);
224
    }
225
226
    /**
227
     * La classe de mail vous permet d'envoyer par courrier électronique via mail, sendmail, SMTP.
228
     */
229
    public static function mail(?array $config = null, bool $shared = true): Mail
230
    {
231
        if (empty($config)) {
232
            $config = Config::get('mail');
233
        }
234
235
        if (true === $shared && isset(static::$instances[Mail::class])) {
236
            /** @var Mail $instance */
237
            $instance = static::$instances[Mail::class];
238
            if (empty(func_get_args()[0])) {
239
                return $instance;
240
            }
241
242
            return $instance->merge($config);
243
        }
244
245
        return static::$instances[Mail::class] = static::factory(Mail::class, compact('config'));
246
    }
247
248
    /**
249
     * La classe Input générale modélise une requête HTTP.
250
     */
251
    public static function negotiator(?ServerRequest $request = null, bool $shared = true): Negotiator
252
    {
253
        if (empty($request)) {
254
            $request = static::request(true);
255
        }
256
257
        if (true === $shared && isset(static::$instances[Negotiator::class])) {
258
            $instance = static::$instances[Negotiator::class];
259
            if (empty(func_get_args()[0])) {
260
                return $instance;
261
            }
262
263
            return $instance->setRequest($request);
264
        }
265
266
        return static::$instances[Negotiator::class] = static::factory(Negotiator::class, compact('request'));
267
    }
268
269
    /**
270
     * La classe des redirections HTTP
271
     */
272
    public static function redirection(bool $shared = true): Redirection
273
    {
274
        if (true === $shared && isset(static::$instances[Redirection::class])) {
275
            return static::$instances[Redirection::class];
276
        }
277
278
        return static::$instances[Redirection::class] = static::factory(Redirection::class);
279
    }
280
281
    /**
282
     * La classe Resquest modélise une reqûete HTTP.
283
     */
284
    public static function request(bool $shared = true): Request
285
    {
286
        if (true === $shared && isset(static::$instances[Request::class])) {
287
            return static::$instances[Request::class];
288
        }
289
290
        return static::$instances[Request::class] = static::factory(Request::class);
291
    }
292
293
    /**
294
     * La classe Response modélise une réponse HTTP.
295
     */
296
    public static function response(bool $shared = true): Response
297
    {
298
        if (true === $shared && isset(static::$instances[Response::class])) {
299
            return static::$instances[Response::class];
300
        }
301
302
        return static::$instances[Response::class] = static::factory(Response::class);
303
    }
304
305
    /**
306
     * Le service Routes est une classe qui permet de construire facilement
307
     * une collection d'itinéraires.
308
     */
309
    public static function routes(bool $shared = true): RouteCollection
310
    {
311
        if (true === $shared && isset(static::$instances[RouteCollection::class])) {
312
            return static::$instances[RouteCollection::class];
313
        }
314
315
        return static::$instances[RouteCollection::class] = static::factory(RouteCollection::class);
316
    }
317
318
    /**
319
     * La classe Router utilise le tableau de routes d'une RouteCollection et détermine
320
     * le contrôleur et la méthode corrects à exécuter.
321
     */
322
    public static function router(?RouteCollection $routes = null, ?ServerRequest $request = null, bool $shared = true): Router
323
    {
324
        if (true === $shared) {
325
            return static::singleton(Router::class);
326
        }
327
        if (empty($routes)) {
328
            $routes = static::routes(true);
329
        }
330
        if (empty($request)) {
331
            $request = static::request(true);
332
        }
333
334
        return static::factory(Router::class, compact('routes', 'request'));
335
    }
336
337
    /**
338
     * Retourne le gestionnaire de session.
339
     */
340
    public static function session(bool $shared = true): Session
341
    {
342
        if (true === $shared) {
343
            return static::singleton(Session::class);
344
        }
345
346
        $config = Config::get('session');
347
        $db     = null;
348
349
        if (Text::contains($config['handler'], [DatabaseSessionHandler::class, 'database'])) {
350
            $group = $config['group'] ?? Config::get('database.connection');
351
            $db    = DatabaseConfig::connect($group);
352
353
            $driver = $db->getPlatform();
354
355
            if (Text::contains($driver, ['mysql', MySQLSessionHandler::class])) {
356
                $config['handler'] = MySQLSessionHandler::class;
357
            } elseif (Text::contains($driver, ['postgre', PostgreSessionHandler::class])) {
358
                $config['handler'] = PostgreSessionHandler::class;
359
            }
360
        }
361
362
        $session = new Session($config, Config::get('cookie'), Helpers::ipAddress());
363
        $session->setLogger(static::logger());
364
        $session->setDatabase($db);
365
366
        if (session_status() === PHP_SESSION_NONE) {
367
            $session->start();
368
        }
369
370
        return static::$instances[Session::class] = $session;
371
    }
372
373
    /**
374
     * System de gestion de fichier par disque
375
     */
376
    public static function storage(bool $shared = true): FilesystemManager
377
    {
378
        if ($shared && isset(static::$instances[FilesystemManager::class])) {
379
            return static::$instances[FilesystemManager::class];
380
        }
381
382
        return static::$instances[FilesystemManager::class] = new FilesystemManager(Config::get('filesystems'));
383
    }
384
385
    /**
386
     * La classe Timer fournit un moyen simple d'évaluer des parties de votre application.
387
     */
388
    public static function timer(bool $shared = true): Timer
389
    {
390
        if (true === $shared && isset(static::$instances[Timer::class])) {
391
            return static::$instances[Timer::class];
392
        }
393
394
        return static::$instances[Timer::class] = static::factory(Timer::class);
395
    }
396
397
    /**
398
     * Renvoie la barre d'outils de débogage.
399
     */
400
    public static function toolbar(?stdClass $config = null, bool $shared = true): Toolbar
401
    {
402
        if ($shared && isset(static::$instances[Toolbar::class])) {
403
            return static::$instances[Toolbar::class];
404
        }
405
406
        $config ??= (object) config('toolbar');
407
408
        return static::$instances[Toolbar::class] = static::factory(Toolbar::class, compact('config'));
409
    }
410
411
    /**
412
     * La classe URI fournit un moyen de modéliser et de manipuler les URI.
413
     */
414
    public static function uri(?string $uri = null, bool $shared = true): Uri
415
    {
416
        if (true === $shared && isset(static::$instances[Uri::class])) {
417
            return static::$instances[Uri::class]->setURI($uri);
418
        }
419
420
        return static::$instances[Uri::class] = static::factory(Uri::class, compact('uri'));
421
    }
422
423
    /**
424
     * La classe Renderer est la classe qui affiche réellement un fichier à l'utilisateur.
425
     * La classe View par défaut dans BlitzPHP est intentionnellement simple, mais
426
     * le service peut facilement être remplacé par un moteur de modèle si l'utilisateur en a besoin.
427
     */
428
    public static function viewer(bool $shared = true): View
429
    {
430
        if (true === $shared && isset(static::$instances[View::class])) {
431
            return static::$instances[View::class];
432
        }
433
434
        return static::$instances[View::class] = static::factory(View::class);
435
    }
436
437
    /**
438
     * Offre la possibilité d'effectuer des appels insensibles à la casse des noms de service.
439
     *
440
     * @return mixed
441
     */
442
    public static function __callStatic(string $name, array $arguments)
443
    {
444
        if (method_exists(static::class, $name)) {
445
            return static::$name(...$arguments);
446
        }
447
448
        return static::discoverServices($name, $arguments);
449
    }
450
451
    /**
452
     * Essaie d'obtenir un service à partir du conteneur
453
     *
454
     * @return mixed
455
     */
456
    protected static function discoverServices(string $name, array $arguments)
457
    {
458
        $shared = array_pop($arguments);
459
        if ($shared !== true) {
460
            return static::discoverServiceFactory($name, $arguments);
461
        }
462
463
        return static::discoverServiceSingleton($name, ...$arguments);
464
    }
465
466
    /**
467
     * Essaie d'obtenir un service à partir du conteneur
468
     *
469
     * @return mixed
470
     */
471
    private static function discoverServiceFactory(string $name, array $arguments)
472
    {
473
        try {
474
            return static::factory($name, $arguments);
475
        } catch (NotFoundException $e) {
476
            try {
477
                return static::factory($name . 'Service', $arguments);
478
            } catch (NotFoundException $ex) {
479
                throw $e;
480
            }
481
        }
482
    }
483
484
    /**
485
     * Essaie de trouver un seul service
486
     *
487
     * @return mixed
488
     */
489
    private static function discoverServiceSingleton(string $name)
490
    {
491
        $arguments = func_get_args();
492
        $name      = array_shift($arguments);
493
494
        try {
495
            return static::singleton($name, ...$arguments);
496
        } catch (NotFoundException $e) {
497
            try {
498
                return static::singleton($name . 'Service', ...$arguments);
499
            } catch (NotFoundException $ex) {
500
                throw $e;
501
            }
502
        }
503
    }
504
505
    /**
506
     * Injecter une seule instance de la classe donnée
507
     *
508
     * @return mixed
509
     */
510
    public static function singleton(string $name)
511
    {
512
        $arguments = func_get_args();
513
        $name      = array_shift($arguments);
514
515
        if (empty(static::$instances[$name])) {
516
            if (! empty($arguments)) {
517
                static::$instances[$name] = static::factory($name, $arguments);
518
            } else {
519
                static::$instances[$name] = static::injector()->get($name);
520
            }
521
        }
522
523
        return static::$instances[$name];
524
    }
525
526
    /**
527
     * Injecter une nouvelle instance de la classe donnée
528
     *
529
     * @return mixed
530
     */
531
    public static function factory(string $name, array $arguments = [])
532
    {
533
        return static::injector()->make($name, $arguments);
534
    }
535
536
    /**
537
     * Définissez un objet ou une valeur dans le conteneur.
538
     *
539
     * @param string $name  Nom de l'entrée
540
     * @param mixed  $value utilisez les aides à la définition pour définir les objets
541
     */
542
    public static function set(string $name, $value)
543
    {
544
        static::$instances[$name] = $value;
545
        static::container()->set($name, $value);
546
    }
547
}
548