• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 25021729516

27 Apr 2026 09:57PM UTC coverage: 88.227% (-0.09%) from 88.318%
25021729516

Pull #10145

github

web-flow
Merge 486af643a into c9dcbd288
Pull Request #10145: feat: add atomic locks for cache-backed concurrency control

129 of 173 new or added lines in 12 files covered. (74.57%)

14 existing lines in 3 files now uncovered.

23397 of 26519 relevant lines covered (88.23%)

216.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.26
/system/Config/Services.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\Config;
15

16
use CodeIgniter\Cache\CacheFactory;
17
use CodeIgniter\Cache\CacheInterface;
18
use CodeIgniter\Cache\ResponseCache;
19
use CodeIgniter\CLI\Commands;
20
use CodeIgniter\CodeIgniter;
21
use CodeIgniter\Context\Context;
22
use CodeIgniter\Database\ConnectionInterface;
23
use CodeIgniter\Database\MigrationRunner;
24
use CodeIgniter\Debug\Exceptions;
25
use CodeIgniter\Debug\Iterator;
26
use CodeIgniter\Debug\Timer;
27
use CodeIgniter\Debug\Toolbar;
28
use CodeIgniter\Email\Email;
29
use CodeIgniter\Encryption\EncrypterInterface;
30
use CodeIgniter\Encryption\Encryption;
31
use CodeIgniter\EnvironmentDetector;
32
use CodeIgniter\Filters\Filters;
33
use CodeIgniter\Format\Format;
34
use CodeIgniter\Honeypot\Honeypot;
35
use CodeIgniter\HTTP\CLIRequest;
36
use CodeIgniter\HTTP\ContentSecurityPolicy;
37
use CodeIgniter\HTTP\CURLRequest;
38
use CodeIgniter\HTTP\IncomingRequest;
39
use CodeIgniter\HTTP\Negotiate;
40
use CodeIgniter\HTTP\RedirectResponse;
41
use CodeIgniter\HTTP\Request;
42
use CodeIgniter\HTTP\RequestInterface;
43
use CodeIgniter\HTTP\Response;
44
use CodeIgniter\HTTP\ResponseInterface;
45
use CodeIgniter\HTTP\SiteURIFactory;
46
use CodeIgniter\HTTP\URI;
47
use CodeIgniter\HTTP\UserAgent;
48
use CodeIgniter\Images\Handlers\BaseHandler;
49
use CodeIgniter\Language\Language;
50
use CodeIgniter\Lock\LockManager;
51
use CodeIgniter\Log\Logger;
52
use CodeIgniter\Pager\Pager;
53
use CodeIgniter\Router\RouteCollection;
54
use CodeIgniter\Router\RouteCollectionInterface;
55
use CodeIgniter\Router\Router;
56
use CodeIgniter\Security\Security;
57
use CodeIgniter\Session\Handlers\BaseHandler as SessionBaseHandler;
58
use CodeIgniter\Session\Handlers\Database\MySQLiHandler;
59
use CodeIgniter\Session\Handlers\Database\PostgreHandler;
60
use CodeIgniter\Session\Handlers\DatabaseHandler;
61
use CodeIgniter\Session\Session;
62
use CodeIgniter\Superglobals;
63
use CodeIgniter\Throttle\Throttler;
64
use CodeIgniter\Typography\Typography;
65
use CodeIgniter\Validation\Validation;
66
use CodeIgniter\Validation\ValidationInterface;
67
use CodeIgniter\View\Cell;
68
use CodeIgniter\View\Parser;
69
use CodeIgniter\View\RendererInterface;
70
use CodeIgniter\View\View;
71
use Config\App;
72
use Config\Cache;
73
use Config\ContentSecurityPolicy as ContentSecurityPolicyConfig;
74
use Config\ContentSecurityPolicy as CSPConfig;
75
use Config\Database;
76
use Config\Email as EmailConfig;
77
use Config\Encryption as EncryptionConfig;
78
use Config\Exceptions as ExceptionsConfig;
79
use Config\Filters as FiltersConfig;
80
use Config\Format as FormatConfig;
81
use Config\Honeypot as HoneypotConfig;
82
use Config\Images;
83
use Config\Logger as LoggerConfig;
84
use Config\Migrations;
85
use Config\Modules;
86
use Config\Pager as PagerConfig;
87
use Config\Paths;
88
use Config\Routing;
89
use Config\Security as SecurityConfig;
90
use Config\Services as AppServices;
91
use Config\Session as SessionConfig;
92
use Config\Toolbar as ToolbarConfig;
93
use Config\Validation as ValidationConfig;
94
use Config\View as ViewConfig;
95
use InvalidArgumentException;
96
use Locale;
97

98
/**
99
 * Services Configuration file.
100
 *
101
 * Services are simply other classes/libraries that the system uses
102
 * to do its job. This is used by CodeIgniter to allow the core of the
103
 * framework to be swapped out easily without affecting the usage within
104
 * the rest of your application.
105
 *
106
 * This is used in place of a Dependency Injection container primarily
107
 * due to its simplicity, which allows a better long-term maintenance
108
 * of the applications built on top of CodeIgniter. A bonus side-effect
109
 * is that IDEs are able to determine what class you are calling
110
 * whereas with DI Containers there usually isn't a way for them to do this.
111
 *
112
 * @see http://blog.ircmaxell.com/2015/11/simple-easy-risk-and-change.html
113
 * @see http://www.infoq.com/presentations/Simple-Made-Easy
114
 * @see \CodeIgniter\Config\ServicesTest
115
 */
116
class Services extends BaseService
117
{
118
    /**
119
     * The cache class provides a simple way to store and retrieve
120
     * complex data for later.
121
     *
122
     * @return CacheInterface
123
     */
124
    public static function cache(?Cache $config = null, bool $getShared = true)
125
    {
126
        if ($getShared) {
2,110✔
127
            return static::getSharedInstance('cache', $config);
2,107✔
128
        }
129

130
        $config ??= config(Cache::class);
2,110✔
131

132
        return CacheFactory::getHandler($config);
2,110✔
133
    }
134

135
    /**
136
     * The locks service provides atomic locks backed by supported cache handlers.
137
     *
138
     * @return LockManager
139
     */
140
    public static function locks(?CacheInterface $cache = null, bool $getShared = true)
141
    {
142
        if ($getShared) {
4✔
143
            return static::getSharedInstance('locks', $cache);
1✔
144
        }
145

146
        $cache ??= AppServices::get('cache');
4✔
147

148
        return new LockManager($cache);
4✔
149
    }
150

151
    /**
152
     * The CLI Request class provides for ways to interact with
153
     * a command line request.
154
     *
155
     * @return CLIRequest
156
     *
157
     * @internal
158
     */
159
    public static function clirequest(?App $config = null, bool $getShared = true)
160
    {
161
        if ($getShared) {
10✔
162
            return static::getSharedInstance('clirequest', $config);
5✔
163
        }
164

165
        $config ??= config(App::class);
10✔
166

167
        return new CLIRequest($config);
10✔
168
    }
169

170
    /**
171
     * CodeIgniter, the core of the framework.
172
     *
173
     * @return CodeIgniter
174
     */
175
    public static function codeigniter(?App $config = null, bool $getShared = true)
176
    {
177
        if ($getShared) {
2✔
UNCOV
178
            return static::getSharedInstance('codeigniter', $config);
×
179
        }
180

181
        $config ??= config(App::class);
2✔
182

183
        return new CodeIgniter($config);
2✔
184
    }
185

186
    /**
187
     * The commands utility for running and working with CLI commands.
188
     *
189
     * @return Commands
190
     */
191
    public static function commands(bool $getShared = true)
192
    {
193
        if ($getShared) {
57✔
194
            return static::getSharedInstance('commands');
55✔
195
        }
196

197
        return new Commands();
57✔
198
    }
199

200
    /**
201
     * Content Security Policy
202
     *
203
     * @return ContentSecurityPolicy
204
     */
205
    public static function csp(?CSPConfig $config = null, bool $getShared = true)
206
    {
207
        if ($getShared) {
107✔
208
            return static::getSharedInstance('csp', $config);
105✔
209
        }
210

211
        $config ??= config(ContentSecurityPolicyConfig::class);
107✔
212

213
        return new ContentSecurityPolicy($config);
107✔
214
    }
215

216
    /**
217
     * The CURL Request class acts as a simple HTTP client for interacting
218
     * with other servers, typically through APIs.
219
     *
220
     * @todo v4.8.0 Remove $config parameter since unused
221
     *
222
     * @return CURLRequest
223
     */
224
    public static function curlrequest(array $options = [], ?ResponseInterface $response = null, ?App $config = null, bool $getShared = true)
225
    {
226
        if ($getShared) {
5✔
227
            return static::getSharedInstance('curlrequest', $options, $response, $config);
3✔
228
        }
229

230
        $config ??= config(App::class);
5✔
231
        $response ??= new Response();
5✔
232

233
        return new CURLRequest(
5✔
234
            $config,
5✔
235
            new URI($options['baseURI'] ?? null),
5✔
236
            $response,
5✔
237
            $options,
5✔
238
        );
5✔
239
    }
240

241
    /**
242
     * The Email class allows you to send email via mail, sendmail, SMTP.
243
     *
244
     * @param array|EmailConfig|null $config
245
     *
246
     * @return Email
247
     */
248
    public static function email($config = null, bool $getShared = true)
249
    {
250
        if ($getShared) {
5✔
251
            return static::getSharedInstance('email', $config);
1✔
252
        }
253

254
        if (empty($config) || (! is_array($config) && ! $config instanceof EmailConfig)) {
4✔
255
            $config = config(EmailConfig::class);
3✔
256
        }
257

258
        return new Email($config);
4✔
259
    }
260

261
    /**
262
     * The Encryption class provides two-way encryption.
263
     *
264
     * @param bool $getShared
265
     *
266
     * @return EncrypterInterface Encryption handler
267
     */
268
    public static function encrypter(?EncryptionConfig $config = null, $getShared = false)
269
    {
270
        if ($getShared === true) {
7✔
271
            return static::getSharedInstance('encrypter', $config);
1✔
272
        }
273

274
        $config ??= config(EncryptionConfig::class);
7✔
275
        $encryption = new Encryption($config);
7✔
276

277
        return $encryption->initialize($config);
6✔
278
    }
279

280
    /**
281
     * Provides a simple way to determine the current environment
282
     * of the application.
283
     *
284
     * Primarily intended for testing environment-specific branches by
285
     * mocking this service. Mocking it does not modify the `ENVIRONMENT`
286
     * constant. It only affects code paths that resolve and use this service.
287
     */
288
    public static function environment(?string $environment = null, bool $getShared = true): EnvironmentDetector
289
    {
290
        if ($getShared) {
584✔
291
            return static::getSharedInstance('environment', $environment);
582✔
292
        }
293

294
        return new EnvironmentDetector($environment);
584✔
295
    }
296

297
    /**
298
     * The Exceptions class holds the methods that handle:
299
     *
300
     *  - set_exception_handler
301
     *  - set_error_handler
302
     *  - register_shutdown_function
303
     *
304
     * @return Exceptions
305
     */
306
    public static function exceptions(
307
        ?ExceptionsConfig $config = null,
308
        bool $getShared = true,
309
    ) {
310
        if ($getShared) {
4✔
311
            return static::getSharedInstance('exceptions', $config);
1✔
312
        }
313

314
        $config ??= config(ExceptionsConfig::class);
4✔
315

316
        return new Exceptions($config);
4✔
317
    }
318

319
    /**
320
     * Filters allow you to run tasks before and/or after a controller
321
     * is executed. During before filters, the request can be modified,
322
     * and actions taken based on the request, while after filters can
323
     * act on or modify the response itself before it is sent to the client.
324
     *
325
     * @return Filters
326
     */
327
    public static function filters(?FiltersConfig $config = null, bool $getShared = true)
328
    {
329
        if ($getShared) {
147✔
330
            return static::getSharedInstance('filters', $config);
145✔
331
        }
332

333
        $config ??= config(FiltersConfig::class);
147✔
334

335
        return new Filters($config, AppServices::get('request'), AppServices::get('response'));
147✔
336
    }
337

338
    /**
339
     * The Format class is a convenient place to create Formatters.
340
     *
341
     * @return Format
342
     */
343
    public static function format(?FormatConfig $config = null, bool $getShared = true)
344
    {
345
        if ($getShared) {
39✔
346
            return static::getSharedInstance('format', $config);
36✔
347
        }
348

349
        $config ??= config(FormatConfig::class);
39✔
350

351
        return new Format($config);
39✔
352
    }
353

354
    /**
355
     * The Honeypot provides a secret input on forms that bots should NOT
356
     * fill in, providing an additional safeguard when accepting user input.
357
     *
358
     * @return Honeypot
359
     */
360
    public static function honeypot(?HoneypotConfig $config = null, bool $getShared = true)
361
    {
362
        if ($getShared) {
7✔
363
            return static::getSharedInstance('honeypot', $config);
5✔
364
        }
365

366
        $config ??= config(HoneypotConfig::class);
7✔
367

368
        return new Honeypot($config);
7✔
369
    }
370

371
    /**
372
     * Acts as a factory for ImageHandler classes and returns an instance
373
     * of the handler. Used like service('image')->withFile($path)->rotate(90)->save();
374
     *
375
     * @return BaseHandler
376
     */
377
    public static function image(?string $handler = null, ?Images $config = null, bool $getShared = true)
378
    {
379
        if ($getShared) {
90✔
380
            return static::getSharedInstance('image', $handler, $config);
1✔
381
        }
382

383
        $config ??= config(Images::class);
90✔
384
        assert($config instanceof Images);
385

386
        $handler = in_array($handler, [null, '', '0'], true) ? $config->defaultHandler : $handler;
90✔
387
        $class   = $config->handlers[$handler];
90✔
388

389
        return new $class($config);
90✔
390
    }
391

392
    /**
393
     * The Iterator class provides a simple way of looping over a function
394
     * and timing the results and memory usage. Used when debugging and
395
     * optimizing applications.
396
     *
397
     * @return Iterator
398
     */
399
    public static function iterator(bool $getShared = true)
400
    {
401
        if ($getShared) {
3✔
402
            return static::getSharedInstance('iterator');
1✔
403
        }
404

405
        return new Iterator();
3✔
406
    }
407

408
    /**
409
     * Responsible for loading the language string translations.
410
     *
411
     * @return Language
412
     */
413
    public static function language(?string $locale = null, bool $getShared = true)
414
    {
415
        if ($getShared) {
522✔
416
            return static::getSharedInstance('language', $locale)->setLocale($locale);
511✔
417
        }
418

419
        if (AppServices::get('request') instanceof IncomingRequest) {
521✔
420
            $requestLocale = AppServices::get('request')->getLocale();
520✔
421
        } else {
422
            $requestLocale = Locale::getDefault();
1✔
423
        }
424

425
        // Use '?:' for empty string check
426
        $locale = in_array($locale, [null, '', '0'], true) ? $requestLocale : $locale;
521✔
427

428
        return new Language($locale);
521✔
429
    }
430

431
    /**
432
     * The Logger class is a PSR-3 compatible Logging class that supports
433
     * multiple handlers that process the actual logging.
434
     *
435
     * @return Logger
436
     */
437
    public static function logger(bool $getShared = true)
438
    {
439
        if ($getShared) {
352✔
440
            return static::getSharedInstance('logger');
350✔
441
        }
442

443
        return new Logger(config(LoggerConfig::class));
350✔
444
    }
445

446
    /**
447
     * Return the appropriate Migration runner.
448
     *
449
     * @return MigrationRunner
450
     */
451
    public static function migrations(?Migrations $config = null, ?ConnectionInterface $db = null, bool $getShared = true)
452
    {
453
        if ($getShared) {
837✔
454
            return static::getSharedInstance('migrations', $config, $db);
2✔
455
        }
456

457
        $config ??= config(Migrations::class);
837✔
458

459
        return new MigrationRunner($config, $db);
837✔
460
    }
461

462
    /**
463
     * The Negotiate class provides the content negotiation features for
464
     * working the request to determine correct language, encoding, charset,
465
     * and more.
466
     *
467
     * @return Negotiate
468
     */
469
    public static function negotiator(?RequestInterface $request = null, bool $getShared = true)
470
    {
471
        if ($getShared) {
11✔
472
            return static::getSharedInstance('negotiator', $request);
9✔
473
        }
474

475
        $request ??= AppServices::get('request');
5✔
476

477
        return new Negotiate($request);
5✔
478
    }
479

480
    /**
481
     * Return the ResponseCache.
482
     *
483
     * @return ResponseCache
484
     */
485
    public static function responsecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true)
486
    {
487
        if ($getShared) {
7,524✔
488
            return static::getSharedInstance('responsecache', $config, $cache);
7,524✔
489
        }
490

491
        $config ??= config(Cache::class);
2,109✔
492
        $cache ??= AppServices::get('cache');
2,109✔
493

494
        return new ResponseCache($config, $cache);
2,109✔
495
    }
496

497
    /**
498
     * Return the appropriate pagination handler.
499
     *
500
     * @return Pager
501
     */
502
    public static function pager(?PagerConfig $config = null, ?RendererInterface $view = null, bool $getShared = true)
503
    {
504
        if ($getShared) {
12✔
505
            return static::getSharedInstance('pager', $config, $view);
10✔
506
        }
507

508
        $config ??= config(PagerConfig::class);
12✔
509
        $view ??= AppServices::renderer(null, null, false);
12✔
510

511
        return new Pager($config, $view);
12✔
512
    }
513

514
    /**
515
     * The Parser is a simple template parser.
516
     *
517
     * @return Parser
518
     */
519
    public static function parser(?string $viewPath = null, ?ViewConfig $config = null, bool $getShared = true)
520
    {
521
        if ($getShared) {
14✔
522
            return static::getSharedInstance('parser', $viewPath, $config);
12✔
523
        }
524

525
        $viewPath = in_array($viewPath, [null, '', '0'], true) ? (new Paths())->viewDirectory : $viewPath;
14✔
526
        $config ??= config(ViewConfig::class);
14✔
527

528
        return new Parser($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger'));
14✔
529
    }
530

531
    /**
532
     * The Renderer class is the class that actually displays a file to the user.
533
     * The default View class within CodeIgniter is intentionally simple, but this
534
     * service could easily be replaced by a template engine if the user needed to.
535
     *
536
     * @return View
537
     */
538
    public static function renderer(?string $viewPath = null, ?ViewConfig $config = null, bool $getShared = true)
539
    {
540
        if ($getShared) {
232✔
541
            return static::getSharedInstance('renderer', $viewPath, $config);
218✔
542
        }
543

544
        $viewPath = in_array($viewPath, [null, '', '0'], true) ? (new Paths())->viewDirectory : $viewPath;
232✔
545
        $config ??= config(ViewConfig::class);
232✔
546

547
        return new View($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger'));
232✔
548
    }
549

550
    /**
551
     * Returns the current Request object.
552
     *
553
     * createRequest() injects IncomingRequest or CLIRequest.
554
     *
555
     * @return CLIRequest|IncomingRequest
556
     */
557
    public static function request()
558
    {
559
        return static::$instances['request'] ?? static::incomingrequest(getShared: false);
2,943✔
560
    }
561

562
    /**
563
     * Create the current Request object, either IncomingRequest or CLIRequest.
564
     *
565
     * This method is called from CodeIgniter::getRequestObject().
566
     *
567
     * @internal
568
     */
569
    public static function createRequest(App $config, bool $isCli = false): void
570
    {
571
        if ($isCli) {
81✔
572
            $request = AppServices::clirequest($config);
4✔
573
        } else {
574
            $request = AppServices::incomingrequest($config);
77✔
575

576
            // guess at protocol if needed
577
            $request->setProtocolVersion(static::superglobals()->server('SERVER_PROTOCOL', 'HTTP/1.1'));
77✔
578
        }
579

580
        // Inject the request object into Services.
581
        static::$instances['request'] = $request;
81✔
582
    }
583

584
    /**
585
     * The IncomingRequest class models an HTTP request.
586
     *
587
     * @return IncomingRequest
588
     *
589
     * @internal
590
     */
591
    public static function incomingrequest(?App $config = null, bool $getShared = true)
592
    {
593
        if ($getShared) {
2,987✔
594
            return static::getSharedInstance('request', $config);
78✔
595
        }
596

597
        $config ??= config(App::class);
2,987✔
598

599
        return new IncomingRequest(
2,987✔
600
            $config,
2,987✔
601
            AppServices::get('uri'),
2,987✔
602
            'php://input',
2,987✔
603
            new UserAgent(),
2,987✔
604
        );
2,987✔
605
    }
606

607
    /**
608
     * The Response class models an HTTP response.
609
     *
610
     * @todo v4.8.0 Remove $config parameter since unused
611
     *
612
     * @return ResponseInterface
613
     */
614
    public static function response(?App $config = null, bool $getShared = true)
615
    {
616
        if ($getShared) {
385✔
617
            return static::getSharedInstance('response', $config);
341✔
618
        }
619

620
        return new Response();
377✔
621
    }
622

623
    /**
624
     * The Redirect class provides nice way of working with redirects.
625
     *
626
     * @todo v4.8.0 Remove $config parameter since unused
627
     *
628
     * @return RedirectResponse
629
     */
630
    public static function redirectresponse(?App $config = null, bool $getShared = true)
631
    {
632
        if ($getShared) {
18✔
633
            return static::getSharedInstance('redirectresponse', $config);
14✔
634
        }
635

636
        $response = new RedirectResponse();
18✔
637
        $response->setProtocolVersion(AppServices::get('request')->getProtocolVersion());
18✔
638

639
        return $response;
18✔
640
    }
641

642
    /**
643
     * The Routes service is a class that allows for easily building
644
     * a collection of routes.
645
     *
646
     * @return RouteCollection
647
     */
648
    public static function routes(bool $getShared = true)
649
    {
650
        if ($getShared) {
257✔
651
            return static::getSharedInstance('routes');
255✔
652
        }
653

654
        return new RouteCollection(AppServices::get('locator'), new Modules(), config(Routing::class));
257✔
655
    }
656

657
    /**
658
     * The Router class uses a RouteCollection's array of routes, and determines
659
     * the correct Controller and Method to execute.
660
     *
661
     * @return Router
662
     */
663
    public static function router(?RouteCollectionInterface $routes = null, ?Request $request = null, bool $getShared = true)
664
    {
665
        if ($getShared) {
115✔
666
            return static::getSharedInstance('router', $routes, $request);
113✔
667
        }
668

669
        $routes ??= AppServices::get('routes');
112✔
670
        $request ??= AppServices::get('request');
112✔
671

672
        return new Router($routes, $request);
112✔
673
    }
674

675
    /**
676
     * The Security class provides a few handy tools for keeping the site
677
     * secure, most notably the CSRF protection tools.
678
     *
679
     * @return Security
680
     */
681
    public static function security(?SecurityConfig $config = null, bool $getShared = true)
682
    {
683
        if ($getShared) {
13✔
684
            return static::getSharedInstance('security', $config);
11✔
685
        }
686

687
        $config ??= config(SecurityConfig::class);
12✔
688

689
        return new Security($config);
12✔
690
    }
691

692
    /**
693
     * Return the session manager.
694
     *
695
     * @return Session
696
     */
697
    public static function session(?SessionConfig $config = null, bool $getShared = true)
698
    {
699
        if ($getShared) {
63✔
700
            return static::getSharedInstance('session', $config);
56✔
701
        }
702

703
        $config ??= config(SessionConfig::class);
62✔
704

705
        $logger = AppServices::get('logger');
62✔
706

707
        $driverName = $config->driver;
62✔
708

709
        if ($driverName === DatabaseHandler::class) {
62✔
710
            $DBGroup = $config->DBGroup ?? config(Database::class)->defaultGroup;
1✔
711

712
            $driverPlatform = Database::connect($DBGroup)->getPlatform();
1✔
713

714
            if ($driverPlatform === 'MySQLi') {
1✔
715
                $driverName = MySQLiHandler::class;
×
716
            } elseif ($driverPlatform === 'Postgre') {
1✔
UNCOV
717
                $driverName = PostgreHandler::class;
×
718
            } else {
719
                throw new InvalidArgumentException(sprintf(
1✔
720
                    'Invalid session database handler "%s" provided. Only "MySQLi" and "Postgre" are supported.',
1✔
721
                    $driverPlatform,
1✔
722
                ));
1✔
723
            }
724
        }
725

726
        if (! class_exists($driverName) || ! is_a($driverName, SessionBaseHandler::class, true)) {
61✔
727
            throw new InvalidArgumentException(sprintf(
3✔
728
                'Invalid session handler "%s" provided.',
3✔
729
                $driverName,
3✔
730
            ));
3✔
731
        }
732

733
        $driver = new $driverName($config, AppServices::get('request')->getIPAddress());
58✔
734
        $driver->setLogger($logger);
58✔
735

736
        $session = new Session($driver, $config);
58✔
737
        $session->setLogger($logger);
58✔
738

739
        if (session_status() === PHP_SESSION_NONE) {
58✔
740
            // PHP Session emits the headers according to `session.cache_limiter`.
741
            // See https://www.php.net/manual/en/function.session-cache-limiter.php.
742
            // The headers are not managed by CI's Response class.
743
            // So, we remove CI's default Cache-Control header.
744
            AppServices::get('response')->removeHeader('Cache-Control');
58✔
745

746
            $session->start();
58✔
747
        }
748

749
        return $session;
58✔
750
    }
751

752
    /**
753
     * The Factory for SiteURI.
754
     *
755
     * @return SiteURIFactory
756
     */
757
    public static function siteurifactory(
758
        ?App $config = null,
759
        ?Superglobals $superglobals = null,
760
        bool $getShared = true,
761
    ) {
762
        if ($getShared) {
22✔
763
            return static::getSharedInstance('siteurifactory', $config, $superglobals);
17✔
764
        }
765

766
        $config ??= config('App');
22✔
767
        $superglobals ??= AppServices::get('superglobals');
22✔
768

769
        return new SiteURIFactory($config, $superglobals);
22✔
770
    }
771

772
    /**
773
     * Superglobals.
774
     *
775
     * @return Superglobals
776
     */
777
    public static function superglobals(
778
        ?array $server = null,
779
        ?array $get = null,
780
        ?array $post = null,
781
        ?array $cookie = null,
782
        ?array $files = null,
783
        ?array $request = null,
784
        bool $getShared = true,
785
    ) {
786
        if ($getShared) {
1,314✔
787
            return static::getSharedInstance('superglobals', $server, $get, $post, $cookie, $files, $request);
1,312✔
788
        }
789

790
        return new Superglobals($server, $get, $post, $cookie, $files, $request);
779✔
791
    }
792

793
    /**
794
     * The Throttler class provides a simple method for implementing
795
     * rate limiting in your applications.
796
     *
797
     * @return Throttler
798
     */
799
    public static function throttler(bool $getShared = true)
800
    {
801
        if ($getShared) {
4✔
802
            return static::getSharedInstance('throttler');
1✔
803
        }
804

805
        return new Throttler(AppServices::get('cache'));
4✔
806
    }
807

808
    /**
809
     * The Timer class provides a simple way to Benchmark portions of your
810
     * application.
811
     *
812
     * @return Timer
813
     */
814
    public static function timer(bool $getShared = true)
815
    {
816
        if ($getShared) {
119✔
817
            return static::getSharedInstance('timer');
117✔
818
        }
819

820
        return new Timer();
117✔
821
    }
822

823
    /**
824
     * Return the debug toolbar.
825
     *
826
     * @return Toolbar
827
     */
828
    public static function toolbar(?ToolbarConfig $config = null, bool $getShared = true)
829
    {
830
        if ($getShared) {
107✔
831
            return static::getSharedInstance('toolbar', $config);
105✔
832
        }
833

834
        $config ??= config(ToolbarConfig::class);
107✔
835

836
        return new Toolbar($config);
107✔
837
    }
838

839
    /**
840
     * The URI class provides a way to model and manipulate URIs.
841
     *
842
     * @param string|null $uri The URI string
843
     *
844
     * @return URI The current URI if $uri is null.
845
     */
846
    public static function uri(?string $uri = null, bool $getShared = true)
847
    {
UNCOV
848
        if ($getShared) {
×
UNCOV
849
            return static::getSharedInstance('uri', $uri);
×
850
        }
851

852
        if ($uri === null) {
×
UNCOV
853
            $appConfig = config(App::class);
×
854
            $factory   = AppServices::siteurifactory($appConfig, AppServices::get('superglobals'));
×
855

UNCOV
856
            return $factory->createFromGlobals();
×
857
        }
858

UNCOV
859
        return new URI($uri);
×
860
    }
861

862
    /**
863
     * The Validation class provides tools for validating input data.
864
     *
865
     * @return ValidationInterface
866
     */
867
    public static function validation(?ValidationConfig $config = null, bool $getShared = true)
868
    {
869
        if ($getShared) {
150✔
870
            return static::getSharedInstance('validation', $config);
47✔
871
        }
872

873
        $config ??= config(ValidationConfig::class);
150✔
874

875
        return new Validation($config, AppServices::get('renderer'));
150✔
876
    }
877

878
    /**
879
     * View cells are intended to let you insert HTML into view
880
     * that has been generated by any callable in the system.
881
     *
882
     * @return Cell
883
     */
884
    public static function viewcell(bool $getShared = true)
885
    {
886
        if ($getShared) {
6✔
887
            return static::getSharedInstance('viewcell');
3✔
888
        }
889

890
        return new Cell(AppServices::get('cache'));
6✔
891
    }
892

893
    /**
894
     * The Typography class provides a way to format text in semantically relevant ways.
895
     *
896
     * @return Typography
897
     */
898
    public static function typography(bool $getShared = true)
899
    {
900
        if ($getShared) {
5✔
901
            return static::getSharedInstance('typography');
3✔
902
        }
903

904
        return new Typography();
5✔
905
    }
906

907
    /**
908
     * The Context class provides a way to store and retrieve static data throughout requests.
909
     */
910
    public static function context(bool $getShared = true): Context
911
    {
912
        if ($getShared) {
65✔
913
            return static::getSharedInstance('context');
2✔
914
        }
915

916
        return new Context();
65✔
917
    }
918
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc