Passed
Push — main ( 7ca792...577f5e )
by Dimitri
03:34
created

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