Passed
Push — main ( a04a11...ed3749 )
by Dimitri
05:24
created

Services::translator()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 9
nc 8
nop 2
dl 0
loc 19
rs 9.2222
c 0
b 0
f 0
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\Cache\ResponseCache;
18
use BlitzPHP\Config\Config;
19
use BlitzPHP\Contracts\Database\ConnectionResolverInterface;
20
use BlitzPHP\Debug\Logger;
21
use BlitzPHP\Debug\Timer;
22
use BlitzPHP\Debug\Toolbar;
23
use BlitzPHP\Event\EventManager;
24
use BlitzPHP\Filesystem\Filesystem;
25
use BlitzPHP\Filesystem\FilesystemManager;
26
use BlitzPHP\Http\Negotiator;
27
use BlitzPHP\Http\Redirection;
28
use BlitzPHP\Http\Request;
29
use BlitzPHP\Http\Response;
30
use BlitzPHP\Http\ResponseEmitter;
31
use BlitzPHP\Http\ServerRequest;
32
use BlitzPHP\Http\Uri;
33
use BlitzPHP\Http\UrlGenerator;
34
use BlitzPHP\Mail\Mail;
35
use BlitzPHP\Router\RouteCollection;
36
use BlitzPHP\Router\Router;
37
use BlitzPHP\Session\Cookie\Cookie;
38
use BlitzPHP\Session\Handlers\Database as DatabaseSessionHandler;
39
use BlitzPHP\Session\Handlers\Database\MySQL as MySQLSessionHandler;
40
use BlitzPHP\Session\Handlers\Database\Postgre as PostgreSessionHandler;
41
use BlitzPHP\Session\Store;
42
use BlitzPHP\Translator\Translate;
43
use BlitzPHP\Utilities\Helpers;
44
use BlitzPHP\Utilities\String\Text;
45
use BlitzPHP\View\View;
46
use Psr\Log\LoggerInterface;
47
use stdClass;
48
49
/**
50
 * Service
51
 *
52
 * Les services sont simplement d'autres classes/bibliothèques que le système utilise
53
 * pour faire son travail. Ceci est utilisé par BlitzPHP pour permettre au coeur du
54
 * framework à échanger facilement sans affecter l'utilisation à l'intérieur
55
 * le reste de votre application.
56
 *
57
 * Ceci est utilisé à la place d'un conteneur d'injection de dépendance principalement
58
 * en raison de sa simplicité, qui permet un meilleur entretien à long terme
59
 * des applications construites sur BlitzPHP. Un effet secondaire bonus
60
 * est que les IDE sont capables de déterminer quelle classe vous appelez
61
 * alors qu'avec les conteneurs DI, il n'y a généralement aucun moyen pour eux de le faire.
62
 */
63
class Services
64
{
65
    /**
66
     * Cache des instances des services demander comme instance "partagee".
67
     * La cle est le FQCN du service.
68
     */
69
    protected static array $instances = [];
70
71
    /**
72
     * Cache d'autres classe de que nous avons trouver via la methode cacheService.
73
     */
74
    protected static array $services = [];
75
76
    /**
77
     * Avons-nous déjà découvert d'autres Services ?
78
     */
79
    protected static bool $discovered = false;
80
81
    /**
82
     * Un cache des noms de classes de services trouvés.
83
     *
84
     * @var array<string>
85
     */
86
    private static array $serviceNames = [];
87
88
    /**
89
     * La classe Autoloader permet de charger les fichiers simplement.
90
     */
91
    public static function autoloader(bool $shared = true): Autoloader
92
    {
93
        if (true === $shared && isset(static::$instances[Autoloader::class])) {
94
            return static::$instances[Autoloader::class];
95
        }
96
97
        $config  = static::config()->get('autoload');
98
        $helpers = array_merge(['url'], ($config['helpers'] ?? []));
99
100
        return static::$instances[Autoloader::class] = new Autoloader($config, $helpers);
0 ignored issues
show
Bug introduced by
It seems like $config can also be of type null; however, parameter $config of BlitzPHP\Autoloader\Autoloader::__construct() does only seem to accept array, 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

100
        return static::$instances[Autoloader::class] = new Autoloader(/** @scrutinizer ignore-type */ $config, $helpers);
Loading history...
101
    }
102
103
    /**
104
     * La classe de cache fournit un moyen simple de stocker et de récupérer
105
     * données complexes pour plus tard
106
     */
107
    public static function cache(?array $config = null, bool $shared = true): Cache
108
    {
109
        if (empty($config)) {
110
            $config = static::config()->get('cache');
111
        }
112
113
        if (true === $shared && isset(static::$instances[Cache::class])) {
114
            $instance = static::$instances[Cache::class];
115
            if (empty(func_get_args()[0])) {
116
                return $instance;
117
            }
118
119
            return $instance->setConfig($config);
120
        }
121
122
        return static::$instances[Cache::class] = new Cache($config);
123
    }
124
125
    /**
126
     * La clase Config offre une api fluide por gerer les configurations de l'application
127
     */
128
    public static function config(bool $shared = true): Config
129
    {
130
        if (true === $shared && isset(static::$instances[Config::class])) {
131
            return static::$instances[Config::class];
132
        }
133
134
        return static::$instances[Config::class] = new Config();
135
    }
136
137
    /**
138
     * Conteneur d'injection de dependances
139
     */
140
    public static function container(bool $shared = true): Container
141
    {
142
        if (true === $shared && isset(static::$instances[Container::class])) {
143
            return static::$instances[Container::class];
144
        }
145
146
        return static::$instances[Container::class] = new Container();
147
    }
148
149
    /**
150
     * Émetteur de réponse au client
151
     */
152
    public static function emitter(bool $shared = true): ResponseEmitter
153
    {
154
        if (true === $shared && isset(static::$instances[ResponseEmitter::class])) {
155
            return static::$instances[ResponseEmitter::class];
156
        }
157
158
        return static::$instances[ResponseEmitter::class] = new ResponseEmitter();
159
    }
160
161
    /**
162
     * Gestionnaire d'evenement
163
     */
164
    public static function event(bool $shared = true): EventManager
165
    {
166
        if (true === $shared && isset(static::$instances[EventManager::class])) {
167
            return static::$instances[EventManager::class];
168
        }
169
170
        return static::$instances[EventManager::class] = new EventManager();
171
    }
172
173
    /**
174
     * System de gestion de fichier
175
     */
176
    public static function fs(bool $shared = true): Filesystem
177
    {
178
        if (true === $shared && isset(static::$instances[Filesystem::class])) {
179
            return static::$instances[Filesystem::class];
180
        }
181
182
        return static::$instances[Filesystem::class] = new Filesystem();
183
    }
184
185
    /**
186
     * Responsable du chargement des traductions des chaînes de langue.
187
     *
188
     * @deprecated 0.9 use translators instead
189
     */
190
    public static function language(?string $locale = null, bool $shared = true): Translate
191
    {
192
        return static::translator($locale, $shared);
193
    }
194
195
    /**
196
     * Le file locator fournit des methodes utilitaire pour chercher les fichiers non-classes
197
     * dans les dossiers de namespace. C'est une excelente methode pour charger les 'vues', 'helpers', et 'libraries'.
198
     */
199
    public static function locator(bool $shared = true): Locator
200
    {
201
        if ($shared && isset(static::$instances[Locator::class])) {
202
            return static::$instances[Locator::class];
203
        }
204
205
        return static::$instances[Locator::class] = new Locator(static::autoloader());
206
    }
207
208
    /**
209
     * La classe Logger est une classe Logging compatible PSR-3 qui prend en charge
210
     * plusieurs gestionnaires qui traitent la journalisation réelle.
211
     *
212
     * @return Logger
213
     */
214
    public static function logger(bool $shared = true): LoggerInterface
215
    {
216
        if ($shared && isset(static::$instances[Logger::class])) {
217
            return static::$instances[Logger::class];
218
        }
219
220
        return static::$instances[Logger::class] = new Logger();
221
    }
222
223
    /**
224
     * La classe de mail vous permet d'envoyer par courrier électronique via mail, sendmail, SMTP.
225
     */
226
    public static function mail(?array $config = null, bool $shared = true): Mail
227
    {
228
        if (empty($config)) {
229
            $config = static::config()->get('mail');
230
        }
231
232
        if (true === $shared && isset(static::$instances[Mail::class])) {
233
            /** @var Mail $instance */
234
            $instance = static::$instances[Mail::class];
235
            if (empty(func_get_args()[0])) {
236
                return $instance;
237
            }
238
239
            return $instance->merge($config);
240
        }
241
242
        return static::$instances[Mail::class] = new Mail($config);
243
    }
244
245
    /**
246
     * La classe Input générale modélise une requête HTTP.
247
     */
248
    public static function negotiator(?ServerRequest $request = null, bool $shared = true): Negotiator
249
    {
250
        if (empty($request)) {
251
            $request = static::request(true);
252
        }
253
254
        if (true === $shared && isset(static::$instances[Negotiator::class])) {
255
            $instance = static::$instances[Negotiator::class];
256
            if (empty(func_get_args()[0])) {
257
                return $instance;
258
            }
259
260
            return $instance->setRequest($request);
261
        }
262
263
        return static::$instances[Negotiator::class] = new Negotiator($request);
264
    }
265
266
    /**
267
     * La classe des redirections HTTP
268
     */
269
    public static function redirection(bool $shared = true): Redirection
270
    {
271
        if (true === $shared && isset(static::$instances[Redirection::class])) {
272
            return static::$instances[Redirection::class];
273
        }
274
275
        return static::$instances[Redirection::class] = new Redirection(static::factory(UrlGenerator::class));
276
    }
277
278
    /**
279
     * La classe Resquest modélise une reqûete HTTP.
280
     */
281
    public static function request(bool $shared = true): Request
282
    {
283
        if (true === $shared && isset(static::$instances[Request::class])) {
284
            return static::$instances[Request::class];
285
        }
286
287
        return static::$instances[Request::class] = new Request();
288
    }
289
290
    /**
291
     * La classe Response modélise une réponse HTTP.
292
     */
293
    public static function response(bool $shared = true): Response
294
    {
295
        if (true === $shared && isset(static::$instances[Response::class])) {
296
            return static::$instances[Response::class];
297
        }
298
299
        return static::$instances[Response::class] = new Response();
300
    }
301
302
    /**
303
     * CacheResponse
304
     */
305
    public static function responsecache(bool $shared = true): ResponseCache
306
    {
307
        if (true === $shared && isset(static::$instances[ResponseCache::class])) {
308
            return static::$instances[ResponseCache::class];
309
        }
310
311
        return static::$instances[ResponseCache::class] = new ResponseCache(static::cache(), static::config()->get('cache.cache_query_string'));
0 ignored issues
show
Bug introduced by
It seems like static::config()->get('cache.cache_query_string') can also be of type null; however, parameter $cacheQueryString of BlitzPHP\Cache\ResponseCache::__construct() does only seem to accept array|boolean, 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

311
        return static::$instances[ResponseCache::class] = new ResponseCache(static::cache(), /** @scrutinizer ignore-type */ static::config()->get('cache.cache_query_string'));
Loading history...
312
    }
313
314
    /**
315
     * Le service Routes est une classe qui permet de construire facilement
316
     * une collection d'itinéraires.
317
     */
318
    public static function routes(bool $shared = true): RouteCollection
319
    {
320
        if (true === $shared && isset(static::$instances[RouteCollection::class])) {
321
            return static::$instances[RouteCollection::class];
322
        }
323
324
        return static::$instances[RouteCollection::class] = new RouteCollection(static::locator(), (object) static::config()->get('routing'));
325
    }
326
327
    /**
328
     * La classe Router utilise le tableau de routes d'une RouteCollection et détermine
329
     * le contrôleur et la méthode corrects à exécuter.
330
     */
331
    public static function router(?RouteCollection $routes = null, ?ServerRequest $request = null, bool $shared = true): Router
332
    {
333
        if (true === $shared && isset(static::$instances[Router::class])) {
334
            return static::$instances[Router::class];
335
        }
336
337
        if (empty($routes)) {
338
            $routes = static::routes(true);
339
        }
340
        if (empty($request)) {
341
            $request = static::request(true);
342
        }
343
344
        return static::$instances[Router::class] = new Router($routes, $request);
345
    }
346
347
    /**
348
     * Retourne le gestionnaire de session.
349
     */
350
    public static function session(bool $shared = true): Store
351
    {
352
        if (true === $shared && isset(static::$instances[Store::class])) {
353
            return static::$instances[Store::class];
354
        }
355
356
        $config = static::config()->get('session');
357
        $db     = null;
358
359
        if (Text::contains($config['handler'], [DatabaseSessionHandler::class, 'database'])) {
360
            $group = $config['group'] ?? static::config()->get('database.connection');
361
            $db    = static::singleton(ConnectionResolverInterface::class)->connection($group);
362
363
            $driver = $db->getPlatform();
364
365
            if (Text::contains($driver, ['mysql', MySQLSessionHandler::class])) {
366
                $config['handler'] = MySQLSessionHandler::class;
367
            } elseif (Text::contains($driver, ['postgre', PostgreSessionHandler::class])) {
368
                $config['handler'] = PostgreSessionHandler::class;
369
            }
370
        }
371
372
        Cookie::setDefaults($cookies = static::config()->get('cookie'));
0 ignored issues
show
Bug introduced by
It seems like $cookies = static::config()->get('cookie') can also be of type null; however, parameter $options of BlitzPHP\Session\Cookie\Cookie::setDefaults() does only seem to accept array, 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

372
        Cookie::setDefaults(/** @scrutinizer ignore-type */ $cookies = static::config()->get('cookie'));
Loading history...
373
        $session = new Store($config, $cookies, Helpers::ipAddress());
0 ignored issues
show
Bug introduced by
It seems like $config can also be of type null; however, parameter $config of BlitzPHP\Session\Store::__construct() does only seem to accept array, 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

373
        $session = new Store(/** @scrutinizer ignore-type */ $config, $cookies, Helpers::ipAddress());
Loading history...
Bug introduced by
It seems like $cookies can also be of type null; however, parameter $cookie of BlitzPHP\Session\Store::__construct() does only seem to accept array, 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

373
        $session = new Store($config, /** @scrutinizer ignore-type */ $cookies, Helpers::ipAddress());
Loading history...
374
        $session->setLogger(static::logger());
375
        $session->setDatabase($db);
376
377
        if (session_status() === PHP_SESSION_NONE) {
378
            $session->start();
379
        }
380
381
        return static::$instances[Store::class] = $session;
382
    }
383
384
    /**
385
     * System de gestion de fichier par disque
386
     */
387
    public static function storage(bool $shared = true): FilesystemManager
388
    {
389
        if ($shared && isset(static::$instances[FilesystemManager::class])) {
390
            return static::$instances[FilesystemManager::class];
391
        }
392
393
        return static::$instances[FilesystemManager::class] = new FilesystemManager(static::config()->get('filesystems'));
0 ignored issues
show
Bug introduced by
It seems like static::config()->get('filesystems') can also be of type null; however, parameter $config of BlitzPHP\Filesystem\File...mManager::__construct() does only seem to accept array, 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

393
        return static::$instances[FilesystemManager::class] = new FilesystemManager(/** @scrutinizer ignore-type */ static::config()->get('filesystems'));
Loading history...
394
    }
395
396
    /**
397
     * La classe Timer fournit un moyen simple d'évaluer des parties de votre application.
398
     */
399
    public static function timer(bool $shared = true): Timer
400
    {
401
        if (true === $shared && isset(static::$instances[Timer::class])) {
402
            return static::$instances[Timer::class];
403
        }
404
405
        return static::$instances[Timer::class] = new Timer();
406
    }
407
408
    /**
409
     * Renvoie la barre d'outils de débogage.
410
     */
411
    public static function toolbar(?stdClass $config = null, bool $shared = true): Toolbar
412
    {
413
        if ($shared && isset(static::$instances[Toolbar::class])) {
414
            return static::$instances[Toolbar::class];
415
        }
416
417
        $config ??= (object) config('toolbar');
418
419
        return static::$instances[Toolbar::class] = new Toolbar($config);
0 ignored issues
show
Bug introduced by
It seems like $config can also be of type BlitzPHP\Config\Config; however, parameter $config of BlitzPHP\Debug\Toolbar::__construct() does only seem to accept null|stdClass, 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

419
        return static::$instances[Toolbar::class] = new Toolbar(/** @scrutinizer ignore-type */ $config);
Loading history...
420
    }
421
422
    /**
423
     * Responsable du chargement des traductions des chaînes de langue.
424
     */
425
    public static function translator(?string $locale = null, bool $shared = true): Translate
426
    {
427
        if (empty($locale)) {
428
            if (empty($locale = static::$instances[Translate::class . 'locale'] ?? null)) {
429
                $config = static::config()->get('app');
430
431
                if (empty($locale = static::negotiator()->language($config['supported_locales']))) {
432
                    $locale = $config['language'];
433
                }
434
435
                static::$instances[Translate::class . 'locale'] = $locale;
436
            }
437
        }
438
439
        if (true === $shared && isset(static::$instances[Translate::class])) {
440
            return static::$instances[Translate::class]->setLocale($locale);
441
        }
442
443
        return static::$instances[Translate::class] = new Translate($locale, static::locator());
444
    }
445
446
    /**
447
     * La classe URI fournit un moyen de modéliser et de manipuler les URI.
448
     */
449
    public static function uri(?string $uri = null, bool $shared = true): Uri
450
    {
451
        if (true === $shared && isset(static::$instances[Uri::class])) {
452
            return static::$instances[Uri::class]->setURI($uri);
453
        }
454
455
        return static::$instances[Uri::class] = new Uri($uri);
456
    }
457
458
    /**
459
     * La classe Renderer est la classe qui affiche réellement un fichier à l'utilisateur.
460
     * La classe View par défaut dans BlitzPHP est intentionnellement simple, mais
461
     * le service peut facilement être remplacé par un moteur de modèle si l'utilisateur en a besoin.
462
     */
463
    public static function viewer(bool $shared = true): View
464
    {
465
        if (true === $shared && isset(static::$instances[View::class])) {
466
            return static::$instances[View::class];
467
        }
468
469
        return static::$instances[View::class] = new View();
470
    }
471
472
    /**
473
     * Offre la possibilité d'effectuer des appels insensibles à la casse des noms de service.
474
     *
475
     * @return mixed
476
     */
477
    public static function __callStatic(string $name, array $arguments)
478
    {
479
        if (null === $service = static::serviceExists($name)) {
480
            return static::discoverServices($name, $arguments);
481
        }
482
483
        return $service::$name(...$arguments);
484
    }
485
486
    /**
487
     * Vérifiez si le service demandé est défini et renvoyez la classe déclarante.
488
     * Renvoie null s'il n'est pas trouvé.
489
     */
490
    public static function serviceExists(string $name): ?string
491
    {
492
        static::cacheServices();
493
        $services = array_merge(self::$serviceNames, [self::class]);
494
        $name     = strtolower($name);
495
496
        foreach ($services as $service) {
497
            if (method_exists($service, $name)) {
498
                return $service;
499
            }
500
        }
501
502
        return null;
503
    }
504
505
    /**
506
     * Essaie d'obtenir un service à partir du conteneur
507
     *
508
     * @return mixed
509
     */
510
    protected static function discoverServices(string $name, array $arguments)
511
    {
512
        if (true !== array_pop($arguments)) {
513
            return static::factory($name, $arguments);
514
        }
515
516
        return static::singleton($name, ...$arguments);
517
    }
518
519
    protected static function cacheServices(): void
520
    {
521
        if (! static::$discovered) {
522
            $locator = static::locator();
523
            $files   = $locator->search('Config/Services');
524
525
            // Obtenez des instances de toutes les classes de service et mettez-les en cache localement.
526
            foreach ($files as $file) {
527
                if (self::class !== $classname = $locator->getClassname($file)) {
528
                    self::$serviceNames[] = $classname;
529
                    static::$services[]   = new $classname();
530
                }
531
            }
532
533
            static::$discovered = true;
534
        }
535
    }
536
537
    /**
538
     * Injecter une seule instance de la classe donnée
539
     *
540
     * @return mixed
541
     */
542
    public static function singleton(string $name)
543
    {
544
        $arguments = func_get_args();
545
        $name      = array_shift($arguments);
546
547
        if (empty(static::$instances[$name])) {
548
            if (! empty($arguments)) {
549
                static::$instances[$name] = static::factory($name, $arguments);
550
            } else {
551
                static::$instances[$name] = static::container()->get($name);
552
            }
553
        }
554
555
        return static::$instances[$name];
556
    }
557
558
    /**
559
     * Injecter une nouvelle instance de la classe donnée
560
     *
561
     * @return mixed
562
     */
563
    public static function factory(string $name, array $arguments = [])
564
    {
565
        return static::container()->make($name, $arguments);
566
    }
567
568
    /**
569
     * Définissez un objet ou une valeur dans le conteneur.
570
     *
571
     * @param string $name  Nom de l'entrée
572
     * @param mixed  $value utilisez les aides à la définition pour définir les objets
573
     */
574
    public static function set(string $name, $value)
575
    {
576
        static::$instances[$name] = $value;
577
        static::container()->set($name, $value);
578
    }
579
}
580