Passed
Push — main ( 6ad81f...1b5a5a )
by Dimitri
12:10 queued 08:06
created

Services::emitter()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

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
ccs 2
cts 2
cp 1
crap 3
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\Autoloader\LocatorCached;
17
use BlitzPHP\Cache\Cache;
18
use BlitzPHP\Cache\Handlers\FileVarExportHandler;
19
use BlitzPHP\Cache\ResponseCache;
20
use BlitzPHP\Config\Config;
21
use BlitzPHP\Contracts\Autoloader\LocatorInterface;
22
use BlitzPHP\Contracts\Cache\CacheInterface;
23
use BlitzPHP\Contracts\Container\ContainerInterface;
24
use BlitzPHP\Contracts\Database\ConnectionResolverInterface;
25
use BlitzPHP\Contracts\Event\EventManagerInterface;
26
use BlitzPHP\Contracts\Mail\MailerInterface;
27
use BlitzPHP\Contracts\Router\RouteCollectionInterface;
28
use BlitzPHP\Contracts\Router\RouterInterface;
29
use BlitzPHP\Contracts\Security\EncrypterInterface;
30
use BlitzPHP\Contracts\Session\CookieManagerInterface;
31
use BlitzPHP\Contracts\Session\SessionInterface;
32
use BlitzPHP\Debug\Logger;
33
use BlitzPHP\Debug\Timer;
34
use BlitzPHP\Debug\Toolbar;
35
use BlitzPHP\Event\EventManager;
36
use BlitzPHP\Filesystem\Filesystem;
37
use BlitzPHP\Filesystem\FilesystemManager;
38
use BlitzPHP\Http\Negotiator;
39
use BlitzPHP\Http\Redirection;
40
use BlitzPHP\Http\Request;
41
use BlitzPHP\Http\Response;
42
use BlitzPHP\Http\ResponseEmitter;
43
use BlitzPHP\Http\ServerRequest;
44
use BlitzPHP\Http\ServerRequestFactory;
45
use BlitzPHP\Http\Uri;
46
use BlitzPHP\Http\UrlGenerator;
47
use BlitzPHP\Mail\Mail;
48
use BlitzPHP\Router\RouteCollection;
49
use BlitzPHP\Router\Router;
50
use BlitzPHP\Security\Encryption\Encryption;
51
use BlitzPHP\Session\Cookie\Cookie;
52
use BlitzPHP\Session\Cookie\CookieManager;
53
use BlitzPHP\Session\Handlers\Database as DatabaseSessionHandler;
54
use BlitzPHP\Session\Handlers\Database\MySQL as MySQLSessionHandler;
55
use BlitzPHP\Session\Handlers\Database\Postgre as PostgreSessionHandler;
56
use BlitzPHP\Session\Store;
57
use BlitzPHP\Translator\Translate;
58
use BlitzPHP\Utilities\Helpers;
59
use BlitzPHP\Utilities\String\Text;
60
use BlitzPHP\View\Components\ComponentLoader;
61
use BlitzPHP\View\View;
62
use Psr\Http\Message\UriInterface;
63
use Psr\Log\LoggerInterface;
64
use stdClass;
65
66
/**
67
 * Service
68
 *
69
 * Les services sont simplement d'autres classes/bibliothèques que le système utilise
70
 * pour faire son travail. Ceci est utilisé par BlitzPHP pour permettre au coeur du
71
 * framework à échanger facilement sans affecter l'utilisation à l'intérieur
72
 * le reste de votre application.
73
 *
74
 * Ceci est utilisé à la place d'un conteneur d'injection de dépendance principalement
75
 * en raison de sa simplicité, qui permet un meilleur entretien à long terme
76
 * des applications construites sur BlitzPHP. Un effet secondaire bonus
77
 * est que les IDE sont capables de déterminer quelle classe vous appelez
78
 * alors qu'avec les conteneurs DI, il n'y a généralement aucun moyen pour eux de le faire.
79
 */
80
class Services
81
{
82
    /**
83
     * Cache des instances des services demander comme instance "partagee".
84
     * La cle est le FQCN du service.
85
     */
86
    protected static array $instances = [];
87
88
    /**
89
     * Objets simulés à tester qui sont renvoyés s'ils existent.
90
     */
91
    protected static array $mocks = [];
92
93
    /**
94
     * Cache d'autres classe de que nous avons trouver via la methode cacheService.
95
     */
96
    protected static array $services = [];
97
98
    /**
99
     * Avons-nous déjà découvert d'autres Services ?
100
     */
101
    protected static bool $discovered = false;
102
103
    /**
104
     * Un cache des noms de classes de services trouvés.
105
     *
106
     * @var list<string>
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Container\list 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...
107
     */
108
    private static array $serviceNames = [];
109
110
    /**
111
     * La classe Autoloader permet de charger les fichiers simplement.
112
     */
113
    public static function autoloader(bool $shared = true): Autoloader
114
    {
115
        if (true === $shared && isset(static::$instances[Autoloader::class])) {
116 68
            return static::$instances[Autoloader::class];
117
        }
118
119 2
        $config  = static::config()->get('autoload');
120 2
        $helpers = array_merge(['url'], ($config['helpers'] ?? []));
121
122 2
        return static::$instances[Autoloader::class] = new Autoloader(/** @scrutinizer ignore-type */ $config, $helpers);
123
    }
124
125
    /**
126
     * La classe de cache fournit un moyen simple de stocker et de récupérer
127
     * données complexes pour plus tard
128
     *
129
     * @return Cache
130
     */
131
    public static function cache(?array $config = null, bool $shared = true): CacheInterface
132
    {
133
        if ($config === null || $config === []) {
134 10
            $config = static::config()->get('cache');
135
        }
136
137
        if (true === $shared && isset(static::$instances[Cache::class])) {
138 10
            $instance = static::$instances[Cache::class];
139
            if (empty(func_get_args()[0])) {
140 10
                return $instance;
141
            }
142
143 2
            return $instance->setConfig($config);
144
        }
145
146 2
        return static::$instances[Cache::class] = new Cache($config);
147
    }
148
149
    /**
150
     * Les composants sont destinées à vous permettre d'insérer du HTML dans la vue
151
     * qui a été généré par n'importe quel appel dans le système.
152
     */
153
    public static function componentLoader(bool $shared = true): ComponentLoader
154
    {
155
        if (true === $shared && isset(static::$instances[ComponentLoader::class])) {
156 2
            return static::$instances[ComponentLoader::class];
157
        }
158
159 2
        return static::$instances[ComponentLoader::class] = new ComponentLoader(static::cache());
160
    }
161
162
    /**
163
     * La clase Config offre une api fluide por gerer les configurations de l'application
164
     */
165
    public static function config(bool $shared = true): Config
166
    {
167
        if (true === $shared && isset(static::$instances[Config::class])) {
168 223
            return static::$instances[Config::class];
169
        }
170
171
        return static::$instances[Config::class] = new Config();
172
    }
173
174
    /**
175
     * Conteneur d'injection de dependances
176
     *
177
     * @return Container
178
     */
179
    public static function container(bool $shared = true): ContainerInterface
180
    {
181
        if (true === $shared && isset(static::$instances[Container::class])) {
182 103
            return static::$instances[Container::class];
183
        }
184
185
        return static::$instances[Container::class] = new Container();
186
    }
187
188
    /**
189
     * Gestionnaire de cookies
190
     *
191
     * @return CookieManager
192
     */
193
    public static function cookie(bool $shared = true): CookieManagerInterface
194
    {
195
        if (true === $shared && isset(static::$instances[CookieManager::class])) {
196 2
            return static::$instances[CookieManager::class];
197
        }
198
199 2
        $config = (object) static::config()->get('cookie');
200
201
        return static::$instances[CookieManager::class] = (new CookieManager())->setDefaultPathAndDomain(
202
            $config->path ?: '/',
203
            $config->domain ?: '',
204
            $config->secure ?: false,
205
            $config->httponly ?: true,
206
            $config->samesite ?: 'Lax'
207 2
        );
208
    }
209
210
    /**
211
     * Émetteur de réponse au client
212
     */
213
    public static function emitter(bool $shared = true): ResponseEmitter
214
    {
215
        if (true === $shared && isset(static::$instances[ResponseEmitter::class])) {
216 2
            return static::$instances[ResponseEmitter::class];
217
        }
218
219 2
        return static::$instances[ResponseEmitter::class] = new ResponseEmitter();
220
    }
221
222
    /**
223
     * La classe Encryption fournit un cryptage bidirectionnel.
224
     *
225
     * @return Encryption
226
     */
227
    public static function encrypter(?array $config = null, bool $shared = false): EncrypterInterface
228
    {
229
        if (true === $shared && isset(static::$instances[Encryption::class])) {
230
            return static::$instances[Encryption::class];
231
        }
232
233
        $config ??= config('encryption');
234
        $config     = (object) $config;
235
        $encryption = new Encryption($config);
236
        $encryption->initialize($config);
237
238
        return static::$instances[Encryption::class] = $encryption;
239
    }
240
241
    /**
242
     * Gestionnaire d'evenement
243
     *
244
     * @return EventManager
245
     */
246
    public static function event(bool $shared = true): EventManagerInterface
247
    {
248
        if (true === $shared && isset(static::$instances[EventManager::class])) {
249 3
            return static::$instances[EventManager::class];
250
        }
251
252
        return static::$instances[EventManager::class] = new EventManager();
253
    }
254
255
    /**
256
     * System de gestion de fichier
257
     */
258
    public static function fs(bool $shared = true): Filesystem
259
    {
260
        if (true === $shared && isset(static::$instances[Filesystem::class])) {
261 22
            return static::$instances[Filesystem::class];
262
        }
263
264 2
        return static::$instances[Filesystem::class] = new Filesystem();
265
    }
266
267
    /**
268
     * Responsable du chargement des traductions des chaînes de langue.
269
     *
270
     * @deprecated 0.9 use translators instead
271
     */
272
    public static function language(?string $locale = null, bool $shared = true): Translate
273
    {
274
        return static::translator($locale, $shared);
275
    }
276
277
    /**
278
     * Le file locator fournit des methodes utilitaire pour chercher les fichiers non-classes dans les dossiers de namespace.
279
     * C'est une excelente methode pour charger les 'vues', 'helpers', et 'libraries'.
280
     */
281
    public static function locator(bool $shared = true): LocatorInterface
282
    {
283
        if ($shared) {
284
            if (! isset(static::$instances[Locator::class])) {
285 159
                $locator = new Locator(static::autoloader());
286
                if (true === config('optimize.locator_cache_enabled', false)) {
0 ignored issues
show
introduced by
The condition true === config('optimiz..._cache_enabled', false) is always false.
Loading history...
287
                    static::$instances[Locator::class] = new LocatorCached($locator, new FileVarExportHandler());
288
                } else {
289
                    static::$instances[Locator::class] = $locator;
290
                }
291
            }
292
293 159
            return static::$instances[Locator::class];
294
        }
295
296
        return static::$instances[Locator::class] = new Locator(static::autoloader());
297
    }
298
299
    /**
300
     * La classe Logger est une classe Logging compatible PSR-3 qui prend en charge
301
     * plusieurs gestionnaires qui traitent la journalisation réelle.
302
     *
303
     * @return Logger
304
     */
305
    public static function logger(bool $shared = true): LoggerInterface
306
    {
307
        if ($shared && isset(static::$instances[Logger::class])) {
308 43
            return static::$instances[Logger::class];
309
        }
310
311
        return static::$instances[Logger::class] = new Logger();
312
    }
313
314
    /**
315
     * La classe de mail vous permet d'envoyer par courrier électronique via mail, sendmail, SMTP.
316
     *
317
     * @return Mail
318
     */
319
    public static function mail(?array $config = null, bool $shared = true): MailerInterface
320
    {
321
        if ($config === null || $config === []) {
322
            $config = static::config()->get('mail');
323
        }
324
325
        if (true === $shared && isset(static::$instances[Mail::class])) {
326
            /** @var Mail $instance */
327
            $instance = static::$instances[Mail::class];
328
            if (empty(func_get_args()[0])) {
329
                return $instance;
330
            }
331
332
            return $instance->merge($config);
333
        }
334
335
        return static::$instances[Mail::class] = new Mail($config);
336
    }
337
338
    /**
339
     * La classe Input générale modélise une requête HTTP.
340
     */
341
    public static function negotiator(?ServerRequest $request = null, bool $shared = true): Negotiator
342
    {
343
        if ($request === null) {
344
            $request = static::request(true);
345
        }
346
347
        if (true === $shared && isset(static::$instances[Negotiator::class])) {
348
            $instance = static::$instances[Negotiator::class];
349
            if (empty(func_get_args()[0])) {
350
                return $instance;
351
            }
352
353
            return $instance->setRequest($request);
354
        }
355
356
        return static::$instances[Negotiator::class] = new Negotiator($request);
357
    }
358
359
    /**
360
     * La classe des redirections HTTP
361
     */
362
    public static function redirection(bool $shared = true): Redirection
363
    {
364
        if (true === $shared && isset(static::$instances[Redirection::class])) {
365
            return static::$instances[Redirection::class];
366
        }
367
368
        return static::$instances[Redirection::class] = new Redirection(static::factory(UrlGenerator::class));
369
    }
370
371
    /**
372
     * La classe Resquest modélise une reqûete HTTP.
373
     */
374
    public static function request(bool $shared = true): Request
375
    {
376
        if (true === $shared && isset(static::$instances[Request::class])) {
377 47
            return static::$instances[Request::class];
378
        }
379
380 2
        return static::$instances[Request::class] = ServerRequestFactory::fromGlobals();
381
    }
382
383
    /**
384
     * La classe Response modélise une réponse HTTP.
385
     */
386
    public static function response(bool $shared = true): Response
387
    {
388
        if (true === $shared && isset(static::$instances[Response::class])) {
389 8
            return static::$instances[Response::class];
390
        }
391
392 1
        return static::$instances[Response::class] = new Response();
393
    }
394
395
    /**
396
     * CacheResponse
397
     */
398
    public static function responsecache(bool $shared = true): ResponseCache
399
    {
400
        if (true === $shared && isset(static::$instances[ResponseCache::class])) {
401
            return static::$instances[ResponseCache::class];
402
        }
403
404
        return static::$instances[ResponseCache::class] = new ResponseCache(static::cache(), /** @scrutinizer ignore-type */ static::config()->get('cache.cache_query_string'));
405
    }
406
407
    /**
408
     * Le service Routes est une classe qui permet de construire facilement une collection de routes.
409
     *
410
     * @return RouteCollection
411
     */
412
    public static function routes(bool $shared = true): RouteCollectionInterface
413
    {
414
        if (true === $shared && isset(static::$instances[RouteCollection::class])) {
415 4
            return static::$instances[RouteCollection::class];
416
        }
417
418 10
        return static::$instances[RouteCollection::class] = new RouteCollection(static::locator(), (object) static::config()->get('routing'));
419
    }
420
421
    /**
422
     * La classe Router utilise le tableau de routes d'une RouteCollection et détermine
423
     * le contrôleur et la méthode corrects à exécuter.
424
     *
425
     * @return Router
426
     */
427
    public static function router(?RouteCollection $routes = null, ?ServerRequest $request = null, bool $shared = true): RouterInterface
428
    {
429
        if (true === $shared && isset(static::$instances[Router::class])) {
430 12
            return static::$instances[Router::class];
431
        }
432
433
        if ($routes === null) {
434 12
            $routes = static::routes(true);
435
        }
436
        if ($request === null) {
437 2
            $request = static::request(true);
438
        }
439
440 12
        return static::$instances[Router::class] = new Router($routes, $request);
441
    }
442
443
    /**
444
     * Retourne le gestionnaire de session.
445
     *
446
     * @return Store
447
     */
448
    public static function session(bool $shared = true): SessionInterface
449
    {
450
        if (true === $shared && isset(static::$instances[Store::class])) {
451 10
            return static::$instances[Store::class];
452
        }
453
454 19
        $config = static::config()->get('session');
455 19
        $db     = null;
456
457
        if (Text::contains($config['handler'], [DatabaseSessionHandler::class, 'database'])) {
458 19
            $group = $config['group'] ?? static::config()->get('database.connection');
459
            $db    = static::singleton(ConnectionResolverInterface::class)->connection($group);
460
461
            $driver = $db->getPlatform();
462
463
            if (Text::contains($driver, ['mysql', MySQLSessionHandler::class])) {
464
                $config['handler'] = MySQLSessionHandler::class;
465
            } elseif (Text::contains($driver, ['postgre', PostgreSessionHandler::class])) {
466
                $config['handler'] = PostgreSessionHandler::class;
467
            }
468
        }
469
470 19
        Cookie::setDefaults($cookies = /** @scrutinizer ignore-type */ 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

470
        Cookie::setDefaults(/** @scrutinizer ignore-type */ $cookies = /** @scrutinizer ignore-type */ static::config()->get('cookie'));
Loading history...
471 19
        $session = new Store((array) $config, (array) $cookies, Helpers::ipAddress());
472 19
        $session->setLogger(static::logger());
473 19
        $session->setDatabase($db);
474
475
        if (session_status() === PHP_SESSION_NONE) {
476 19
            $session->start();
477
        }
478
479 19
        return static::$instances[Store::class] = $session;
480
    }
481
482
    /**
483
     * System de gestion de fichier par disque
484
     */
485
    public static function storage(bool $shared = true): FilesystemManager
486
    {
487
        if ($shared && isset(static::$instances[FilesystemManager::class])) {
488 2
            return static::$instances[FilesystemManager::class];
489
        }
490
491 2
        return static::$instances[FilesystemManager::class] = new FilesystemManager(/** @scrutinizer ignore-type */ static::config()->get('filesystems'));
492
    }
493
494
    /**
495
     * La classe Timer fournit un moyen simple d'évaluer des parties de votre application.
496
     */
497
    public static function timer(bool $shared = true): Timer
498
    {
499
        if (true === $shared && isset(static::$instances[Timer::class])) {
500
            return static::$instances[Timer::class];
501
        }
502
503
        return static::$instances[Timer::class] = new Timer();
504
    }
505
506
    /**
507
     * Renvoie la barre d'outils de débogage.
508
     */
509
    public static function toolbar(?stdClass $config = null, bool $shared = true): Toolbar
510
    {
511
        if ($shared && isset(static::$instances[Toolbar::class])) {
512
            return static::$instances[Toolbar::class];
513
        }
514
515
        $config ??= (object) static::config()->get('toolbar');
516
517
        return static::$instances[Toolbar::class] = new Toolbar($config);
518
    }
519
520
    /**
521
     * Responsable du chargement des traductions des chaînes de langue.
522
     */
523
    public static function translator(?string $locale = null, bool $shared = true): Translate
524
    {
525
        if (null === $locale || $locale === '' || $locale === '0') {
526 68
            $locale = is_cli() ? static::config()->get('app.language') : static::request()->getLocale();
527
        }
528
529
        if (true === $shared && isset(static::$instances[Translate::class])) {
530 68
            return static::$instances[Translate::class]->setLocale($locale);
531
        }
532
533 2
        return static::$instances[Translate::class] = new Translate($locale, static::locator());
534
    }
535
536
    /**
537
     * La classe URI fournit un moyen de modéliser et de manipuler les URI.
538
     *
539
     * @return Uri
540
     */
541
    public static function uri(?string $uri = null, bool $shared = true): UriInterface
542
    {
543
        if (true === $shared && isset(static::$instances[Uri::class])) {
544
            return static::$instances[Uri::class]->setURI($uri);
545
        }
546
547
        return static::$instances[Uri::class] = new Uri($uri);
548
    }
549
550
    /**
551
     * La classe Renderer est la classe qui affiche réellement un fichier à l'utilisateur.
552
     * La classe View par défaut dans BlitzPHP est intentionnellement simple, mais
553
     * le service peut facilement être remplacé par un moteur de modèle si l'utilisateur en a besoin.
554
     */
555
    public static function viewer(bool $shared = true): View
556
    {
557
        if (true === $shared && isset(static::$instances[View::class])) {
558 2
            return static::$instances[View::class];
559
        }
560
561 2
        return static::$instances[View::class] = new View();
562
    }
563
564
    /**
565
     * Offre la possibilité d'effectuer des appels insensibles à la casse des noms de service.
566
     *
567
     * @return mixed
568
     */
569
    public static function __callStatic(string $name, array $arguments)
570
    {
571
        if (null === $service = static::serviceExists($name)) {
572 22
            return static::discoverServices($name, $arguments);
573
        }
574
575 2
        return $service::$name(...$arguments);
576
    }
577
578
    /**
579
     * Vérifiez si le service demandé est défini et renvoyez la classe déclarante.
580
     * Renvoie null s'il n'est pas trouvé.
581
     */
582
    public static function serviceExists(string $name): ?string
583
    {
584 24
        static::cacheServices();
585 24
        $services = array_merge(self::$serviceNames, [self::class]);
586 24
        $name     = strtolower($name);
587
588
        foreach ($services as $service) {
589
            if (method_exists($service, $name)) {
590 2
                return $service;
591
            }
592
        }
593
594 22
        return null;
595
    }
596
597
    /**
598
     * Essaie d'obtenir un service à partir du conteneur
599
     *
600
     * @return mixed
601
     */
602
    protected static function discoverServices(string $name, array $arguments)
603
    {
604
        if (true !== array_pop($arguments)) {
605 22
            return static::factory($name, $arguments);
606
        }
607
608
        return static::singleton($name, ...$arguments);
609
    }
610
611
    protected static function cacheServices(): void
612
    {
613
        if (! static::$discovered) {
614 2
            $locator = static::locator();
615 2
            $files   = $locator->search('Config/Services');
616
617
            // Obtenez des instances de toutes les classes de service et mettez-les en cache localement.
618
            foreach ($files as $file) {
619
                if (false === $classname = $locator->findQualifiedNameFromPath($file)) {
620
                    continue;
621
                }
622
                if (self::class !== $classname) {
623 2
                    self::$serviceNames[] = $classname;
624 2
                    static::$services[]   = new $classname();
625
                }
626
            }
627
628 2
            static::$discovered = true;
629
        }
630
    }
631
632
    /**
633
     * Injecter une seule instance de la classe donnée
634
     *
635
     * @return mixed
636
     */
637
    public static function singleton(string $name)
638
    {
639
        $arguments = func_get_args();
640
        $name      = array_shift($arguments);
641
642
        if (empty(static::$instances[$name])) {
643
            static::$instances[$name] = $arguments !== [] ? static::factory($name, $arguments) : static::container()->get($name);
644
        }
645
646
        return static::$instances[$name];
647
    }
648
649
    /**
650
     * Injecter une nouvelle instance de la classe donnée
651
     *
652
     * @return mixed
653
     */
654
    public static function factory(string $name, array $arguments = [])
655
    {
656 26
        return static::container()->make($name, $arguments);
657
    }
658
659
    /**
660
     * Définissez un objet ou une valeur dans le conteneur.
661
     *
662
     * @param string $name  Nom de l'entrée
663
     * @param mixed  $value utilisez les aides à la définition pour définir les objets
664
     */
665
    public static function set(string $name, $value)
666
    {
667 48
        static::$instances[$name] = $value;
668 48
        static::container()->set($name, $value);
669
    }
670
671
    /**
672
     * Injectez un objet fictif pour les tests.
673
     *
674
     * @testTag disponible uniquement pour le code de test
675
     */
676
    public static function injectMock(string $name, object $mock): void
677
    {
678 3
        static::$mocks[strtolower($name)] = $mock;
679
    }
680
681
    /**
682
     * Réinitialisez les instances partagées et les simulations pour les tests.
683
     *
684
     * @testTag disponible uniquement pour le code de test
685
     */
686
    public static function reset(bool $initAutoloader = true): void
687
    {
688
        static::$mocks     = [];
689
        static::$instances = [];
690
691
        if ($initAutoloader) {
692
            static::autoloader()->initialize();
693
        }
694
    }
695
696
    /**
697
     * Réinitialise toutes les instances fictives et partagées pour un seul service.
698
     *
699
     * @testTag disponible uniquement pour le code de test
700
     */
701
    public static function resetSingle(string ...$name)
702
    {
703
        foreach ($name as $n) {
704
            unset(static::$mocks[$n], static::$instances[$n]);
705
            $n = strtolower($n);
706
            unset(static::$mocks[$n], static::$instances[$n]);
707
        }
708
    }
709
}
710