Skip to content

Commit

Permalink
Merge pull request #7696 from kenjis/feat-Factories-config-cache
Browse files Browse the repository at this point in the history
feat: [Factories] Config caching
  • Loading branch information
kenjis authored Aug 21, 2023
2 parents aeaebf6 + ef045ce commit f4c17e8
Show file tree
Hide file tree
Showing 17 changed files with 506 additions and 10 deletions.
5 changes: 5 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.13.1@086b94371304750d1c673315321a55d15fc59015">
<file src="system/Cache/FactoriesCache/FileVarExportHandler.php">
<UndefinedVariable>
<code>$val</code>
</UndefinedVariable>
</file>
<file src="system/Cache/Handlers/MemcachedHandler.php">
<UndefinedClass>
<code>Memcache</code>
Expand Down
14 changes: 14 additions & 0 deletions public/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@
require_once SYSTEMPATH . 'Config/DotEnv.php';
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();

// Define ENVIRONMENT
if (! defined('ENVIRONMENT')) {
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production'));
}

// Load Config Cache
// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
// $factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.

/*
* ---------------------------------------------------------------
* GRAB OUR CODEIGNITER INSTANCE
Expand All @@ -68,6 +78,10 @@

$app->run();

// Save Config Cache
// $factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.

// Exits the application, setting the exit code for CLI-based applications
// that might be watching.
exit(EXIT_SUCCESS);
5 changes: 5 additions & 0 deletions spark
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstra
require_once SYSTEMPATH . 'Config/DotEnv.php';
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();

// Define ENVIRONMENT
if (! defined('ENVIRONMENT')) {
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production'));
}

// Grab our CodeIgniter
$app = Config\Services::codeigniter();
$app->initialize();
Expand Down
65 changes: 65 additions & 0 deletions system/Cache/FactoriesCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

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

namespace CodeIgniter\Cache;

use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
use CodeIgniter\Config\Factories;

final class FactoriesCache
{
/**
* @var CacheInterface|FileVarExportHandler
*/
private $cache;

/**
* @param CacheInterface|FileVarExportHandler|null $cache
*/
public function __construct($cache = null)
{
$this->cache = $cache ?? new FileVarExportHandler();
}

public function save(string $component): void
{
if (! Factories::isUpdated($component)) {
return;
}

$data = Factories::getComponentInstances($component);

$this->cache->save($this->getCacheKey($component), $data, 3600 * 24);
}

private function getCacheKey(string $component): string
{
return 'FactoriesCache_' . $component;
}

public function load(string $component): bool
{
$key = $this->getCacheKey($component);

if (! $data = $this->cache->get($key)) {
return false;
}

Factories::setComponentInstances($component, $data);

return true;
}

public function delete(string $component): void
{
$this->cache->delete($this->getCacheKey($component));
}
}
44 changes: 44 additions & 0 deletions system/Cache/FactoriesCache/FileVarExportHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

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

namespace CodeIgniter\Cache\FactoriesCache;

final class FileVarExportHandler
{
private string $path = WRITEPATH . 'cache';

/**
* @param array|bool|float|int|object|string|null $val
*/
public function save(string $key, $val): void
{
$val = var_export($val, true);

// Write to temp file first to ensure atomicity
$tmp = $this->path . "/{$key}." . uniqid('', true) . '.tmp';
file_put_contents($tmp, '<?php return ' . $val . ';', LOCK_EX);

rename($tmp, $this->path . "/{$key}");
}

public function delete(string $key): void
{
@unlink($this->path . "/{$key}");
}

/**
* @return array|bool|float|int|object|string|null
*/
public function get(string $key)
{
return @include $this->path . "/{$key}";
}
}
3 changes: 2 additions & 1 deletion system/CodeIgniter.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ public function __construct(App $config)
public function initialize()
{
// Define environment variables
$this->detectEnvironment();
$this->bootstrapEnvironment();

// Setup Exception Handling
Expand Down Expand Up @@ -560,6 +559,8 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache
* production
*
* @codeCoverageIgnore
*
* @deprecated 4.4.0 No longer used. Moved to index.php and spark.
*/
protected function detectEnvironment()
{
Expand Down
26 changes: 26 additions & 0 deletions system/Config/BaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
* from the environment.
*
* These can be set within the .env file.
*
* @phpstan-consistent-constructor
*/
class BaseConfig
{
Expand All @@ -37,6 +39,11 @@ class BaseConfig
*/
public static $registrars = [];

/**
* Whether to override properties by Env vars and Registrars.
*/
public static bool $override = true;

/**
* Has module discovery happened yet?
*
Expand All @@ -51,6 +58,21 @@ class BaseConfig
*/
protected static $moduleConfig;

public static function __set_state(array $array)
{
static::$override = false;
$obj = new static();
static::$override = true;

$properties = array_keys(get_object_vars($obj));

foreach ($properties as $property) {
$obj->{$property} = $array[$property];
}

return $obj;
}

/**
* Will attempt to get environment variables with names
* that match the properties of the child class.
Expand All @@ -61,6 +83,10 @@ public function __construct()
{
static::$moduleConfig = config(Modules::class);

if (! static::$override) {
return;
}

$this->registerProperties();

$properties = array_keys(get_object_vars($this));
Expand Down
56 changes: 55 additions & 1 deletion system/Config/Factories.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ class Factories
*/
protected static $instances = [];

/**
* Whether the component instances are updated?
*
* @var array<string, true> [component => true]
*
* @internal For caching only
*/
protected static $updated = [];

/**
* Define the class to load. You can *override* the concrete class.
*
Expand Down Expand Up @@ -153,6 +162,7 @@ public static function __callStatic(string $component, array $arguments)

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

// If a short classname is specified, also register FQCN to share the instance.
if (! isset(self::$aliases[$options['component']][$class])) {
Expand Down Expand Up @@ -383,7 +393,8 @@ public static function reset(?string $component = null)
unset(
static::$options[$component],
static::$aliases[$component],
static::$instances[$component]
static::$instances[$component],
static::$updated[$component]
);

return;
Expand All @@ -392,6 +403,7 @@ public static function reset(?string $component = null)
static::$options = [];
static::$aliases = [];
static::$instances = [];
static::$updated = [];
}

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

return $alias;
}

/**
* Gets component data for caching.
*
* @internal For caching only
*/
public static function getComponentInstances(string $component): array
{
if (! isset(static::$aliases[$component])) {
return [
'aliases' => [],
'instances' => [],
];
}

return [
'aliases' => static::$aliases[$component],
'instances' => self::$instances[$component],
];
}

/**
* Sets component data
*
* @internal For caching only
*/
public static function setComponentInstances(string $component, array $data): void
{
static::$aliases[$component] = $data['aliases'];
self::$instances[$component] = $data['instances'];
unset(self::$updated[$component]);
}

/**
* Whether the component instances are updated?
*
* @internal For caching only
*/
public static function isUpdated(string $component): bool
{
return isset(self::$updated[$component]);
}
}
2 changes: 1 addition & 1 deletion system/Config/Services.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static function cache(?Cache $config = null, bool $getShared = true)
return static::getSharedInstance('cache', $config);
}

$config ??= new Cache();
$config ??= config(Cache::class);

return CacheFactory::getHandler($config);
}
Expand Down
2 changes: 1 addition & 1 deletion system/HTTP/UserAgent.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class UserAgent
*/
public function __construct(?UserAgents $config = null)
{
$this->config = $config ?? new UserAgents();
$this->config = $config ?? config(UserAgents::class);

if (isset($_SERVER['HTTP_USER_AGENT'])) {
$this->agent = trim($_SERVER['HTTP_USER_AGENT']);
Expand Down
20 changes: 20 additions & 0 deletions system/Modules/Modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* Modules Class
*
* @see https://codeigniter.com/user_guide/general/modules.html
*
* @phpstan-consistent-constructor
*/
class Modules
{
Expand All @@ -39,6 +41,11 @@ class Modules
*/
public $aliases = [];

public function __construct()
{
// For @phpstan-consistent-constructor
}

/**
* Should the application auto-discover the requested resource.
*/
Expand All @@ -50,4 +57,17 @@ public function shouldDiscover(string $alias): bool

return in_array(strtolower($alias), $this->aliases, true);
}

public static function __set_state(array $array)
{
$obj = new static();

$properties = array_keys(get_object_vars($obj));

foreach ($properties as $property) {
$obj->{$property} = $array[$property];
}

return $obj;
}
}
Loading

0 comments on commit f4c17e8

Please sign in to comment.