Skip to content

Commit f4c17e8

Browse files
authored
Merge pull request #7696 from kenjis/feat-Factories-config-cache
feat: [Factories] Config caching
2 parents aeaebf6 + ef045ce commit f4c17e8

File tree

17 files changed

+506
-10
lines changed

17 files changed

+506
-10
lines changed

psalm-baseline.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<files psalm-version="5.13.1@086b94371304750d1c673315321a55d15fc59015">
3+
<file src="system/Cache/FactoriesCache/FileVarExportHandler.php">
4+
<UndefinedVariable>
5+
<code>$val</code>
6+
</UndefinedVariable>
7+
</file>
38
<file src="system/Cache/Handlers/MemcachedHandler.php">
49
<UndefinedClass>
510
<code>Memcache</code>

public/index.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@
4343
require_once SYSTEMPATH . 'Config/DotEnv.php';
4444
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
4545

46+
// Define ENVIRONMENT
47+
if (! defined('ENVIRONMENT')) {
48+
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production'));
49+
}
50+
51+
// Load Config Cache
52+
// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
53+
// $factoriesCache->load('config');
54+
// ^^^ Uncomment these lines if you want to use Config Caching.
55+
4656
/*
4757
* ---------------------------------------------------------------
4858
* GRAB OUR CODEIGNITER INSTANCE
@@ -68,6 +78,10 @@
6878

6979
$app->run();
7080

81+
// Save Config Cache
82+
// $factoriesCache->save('config');
83+
// ^^^ Uncomment this line if you want to use Config Caching.
84+
7185
// Exits the application, setting the exit code for CLI-based applications
7286
// that might be watching.
7387
exit(EXIT_SUCCESS);

spark

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstra
7878
require_once SYSTEMPATH . 'Config/DotEnv.php';
7979
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
8080

81+
// Define ENVIRONMENT
82+
if (! defined('ENVIRONMENT')) {
83+
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production'));
84+
}
85+
8186
// Grab our CodeIgniter
8287
$app = Config\Services::codeigniter();
8388
$app->initialize();

system/Cache/FactoriesCache.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[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 CodeIgniter\Cache;
13+
14+
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
15+
use CodeIgniter\Config\Factories;
16+
17+
final class FactoriesCache
18+
{
19+
/**
20+
* @var CacheInterface|FileVarExportHandler
21+
*/
22+
private $cache;
23+
24+
/**
25+
* @param CacheInterface|FileVarExportHandler|null $cache
26+
*/
27+
public function __construct($cache = null)
28+
{
29+
$this->cache = $cache ?? new FileVarExportHandler();
30+
}
31+
32+
public function save(string $component): void
33+
{
34+
if (! Factories::isUpdated($component)) {
35+
return;
36+
}
37+
38+
$data = Factories::getComponentInstances($component);
39+
40+
$this->cache->save($this->getCacheKey($component), $data, 3600 * 24);
41+
}
42+
43+
private function getCacheKey(string $component): string
44+
{
45+
return 'FactoriesCache_' . $component;
46+
}
47+
48+
public function load(string $component): bool
49+
{
50+
$key = $this->getCacheKey($component);
51+
52+
if (! $data = $this->cache->get($key)) {
53+
return false;
54+
}
55+
56+
Factories::setComponentInstances($component, $data);
57+
58+
return true;
59+
}
60+
61+
public function delete(string $component): void
62+
{
63+
$this->cache->delete($this->getCacheKey($component));
64+
}
65+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[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 CodeIgniter\Cache\FactoriesCache;
13+
14+
final class FileVarExportHandler
15+
{
16+
private string $path = WRITEPATH . 'cache';
17+
18+
/**
19+
* @param array|bool|float|int|object|string|null $val
20+
*/
21+
public function save(string $key, $val): void
22+
{
23+
$val = var_export($val, true);
24+
25+
// Write to temp file first to ensure atomicity
26+
$tmp = $this->path . "/{$key}." . uniqid('', true) . '.tmp';
27+
file_put_contents($tmp, '<?php return ' . $val . ';', LOCK_EX);
28+
29+
rename($tmp, $this->path . "/{$key}");
30+
}
31+
32+
public function delete(string $key): void
33+
{
34+
@unlink($this->path . "/{$key}");
35+
}
36+
37+
/**
38+
* @return array|bool|float|int|object|string|null
39+
*/
40+
public function get(string $key)
41+
{
42+
return @include $this->path . "/{$key}";
43+
}
44+
}

system/CodeIgniter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ public function __construct(App $config)
200200
public function initialize()
201201
{
202202
// Define environment variables
203-
$this->detectEnvironment();
204203
$this->bootstrapEnvironment();
205204

206205
// Setup Exception Handling
@@ -560,6 +559,8 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache
560559
* production
561560
*
562561
* @codeCoverageIgnore
562+
*
563+
* @deprecated 4.4.0 No longer used. Moved to index.php and spark.
563564
*/
564565
protected function detectEnvironment()
565566
{

system/Config/BaseConfig.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
* from the environment.
2727
*
2828
* These can be set within the .env file.
29+
*
30+
* @phpstan-consistent-constructor
2931
*/
3032
class BaseConfig
3133
{
@@ -37,6 +39,11 @@ class BaseConfig
3739
*/
3840
public static $registrars = [];
3941

42+
/**
43+
* Whether to override properties by Env vars and Registrars.
44+
*/
45+
public static bool $override = true;
46+
4047
/**
4148
* Has module discovery happened yet?
4249
*
@@ -51,6 +58,21 @@ class BaseConfig
5158
*/
5259
protected static $moduleConfig;
5360

61+
public static function __set_state(array $array)
62+
{
63+
static::$override = false;
64+
$obj = new static();
65+
static::$override = true;
66+
67+
$properties = array_keys(get_object_vars($obj));
68+
69+
foreach ($properties as $property) {
70+
$obj->{$property} = $array[$property];
71+
}
72+
73+
return $obj;
74+
}
75+
5476
/**
5577
* Will attempt to get environment variables with names
5678
* that match the properties of the child class.
@@ -61,6 +83,10 @@ public function __construct()
6183
{
6284
static::$moduleConfig = config(Modules::class);
6385

86+
if (! static::$override) {
87+
return;
88+
}
89+
6490
$this->registerProperties();
6591

6692
$properties = array_keys(get_object_vars($this));

system/Config/Factories.php

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ class Factories
8080
*/
8181
protected static $instances = [];
8282

83+
/**
84+
* Whether the component instances are updated?
85+
*
86+
* @var array<string, true> [component => true]
87+
*
88+
* @internal For caching only
89+
*/
90+
protected static $updated = [];
91+
8392
/**
8493
* Define the class to load. You can *override* the concrete class.
8594
*
@@ -153,6 +162,7 @@ public static function __callStatic(string $component, array $arguments)
153162

154163
self::$instances[$options['component']][$class] = new $class(...$arguments);
155164
self::$aliases[$options['component']][$alias] = $class;
165+
self::$updated[$options['component']] = true;
156166

157167
// If a short classname is specified, also register FQCN to share the instance.
158168
if (! isset(self::$aliases[$options['component']][$class])) {
@@ -383,7 +393,8 @@ public static function reset(?string $component = null)
383393
unset(
384394
static::$options[$component],
385395
static::$aliases[$component],
386-
static::$instances[$component]
396+
static::$instances[$component],
397+
static::$updated[$component]
387398
);
388399

389400
return;
@@ -392,6 +403,7 @@ public static function reset(?string $component = null)
392403
static::$options = [];
393404
static::$aliases = [];
394405
static::$instances = [];
406+
static::$updated = [];
395407
}
396408

397409
/**
@@ -440,4 +452,46 @@ public static function getBasename(string $alias): string
440452

441453
return $alias;
442454
}
455+
456+
/**
457+
* Gets component data for caching.
458+
*
459+
* @internal For caching only
460+
*/
461+
public static function getComponentInstances(string $component): array
462+
{
463+
if (! isset(static::$aliases[$component])) {
464+
return [
465+
'aliases' => [],
466+
'instances' => [],
467+
];
468+
}
469+
470+
return [
471+
'aliases' => static::$aliases[$component],
472+
'instances' => self::$instances[$component],
473+
];
474+
}
475+
476+
/**
477+
* Sets component data
478+
*
479+
* @internal For caching only
480+
*/
481+
public static function setComponentInstances(string $component, array $data): void
482+
{
483+
static::$aliases[$component] = $data['aliases'];
484+
self::$instances[$component] = $data['instances'];
485+
unset(self::$updated[$component]);
486+
}
487+
488+
/**
489+
* Whether the component instances are updated?
490+
*
491+
* @internal For caching only
492+
*/
493+
public static function isUpdated(string $component): bool
494+
{
495+
return isset(self::$updated[$component]);
496+
}
443497
}

system/Config/Services.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public static function cache(?Cache $config = null, bool $getShared = true)
119119
return static::getSharedInstance('cache', $config);
120120
}
121121

122-
$config ??= new Cache();
122+
$config ??= config(Cache::class);
123123

124124
return CacheFactory::getHandler($config);
125125
}

system/HTTP/UserAgent.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class UserAgent
102102
*/
103103
public function __construct(?UserAgents $config = null)
104104
{
105-
$this->config = $config ?? new UserAgents();
105+
$this->config = $config ?? config(UserAgents::class);
106106

107107
if (isset($_SERVER['HTTP_USER_AGENT'])) {
108108
$this->agent = trim($_SERVER['HTTP_USER_AGENT']);

0 commit comments

Comments
 (0)