modifs.mineures sans commentaires
This commit is contained in:
parent
8612a9dae4
commit
8079d111cc
29
src/cache/CacheChannel.php
vendored
29
src/cache/CacheChannel.php
vendored
@ -23,42 +23,19 @@ class CacheChannel extends CapacitorChannel implements IteratorAggregate {
|
||||
"primary key (group_id, id, key_index)",
|
||||
];
|
||||
|
||||
static function with(CapacitorStorage $storage, ?iterable $rows=null, $cursorId=null): self {
|
||||
static function with(?iterable $rows=null, $cursorId=null, ?CapacitorStorage $storage=null): self {
|
||||
$storage ??= cache::storage();
|
||||
$channel = (new static($cursorId))->initStorage($storage);
|
||||
if ($rows !== null) $channel->build($rows);
|
||||
return $channel;
|
||||
}
|
||||
|
||||
static function verifix_id(&$cursorId): void {
|
||||
$cursorId ??= utils::uuidgen();
|
||||
if (is_array($cursorId)) {
|
||||
$keys = array_keys($cursorId);
|
||||
if (array_key_exists("group_id", $cursorId)) $groupIdKey = "group_id";
|
||||
else $groupIdKey = $keys[1] ?? null;
|
||||
$groupId = strval($cursorId[$groupIdKey] ?? "");
|
||||
if (array_key_exists("id", $cursorId)) $idKey = "id";
|
||||
else $idKey = $keys[0] ?? null;
|
||||
$id = strval($cursorId[$idKey] ?? "");
|
||||
} else {
|
||||
$groupId = "";
|
||||
$id = strval($cursorId);
|
||||
}
|
||||
# si le groupe ou le nom sont trop grand, en faire un hash
|
||||
if (strlen($groupId) > 32) {
|
||||
$groupId = md5($groupId);
|
||||
}
|
||||
if (strlen($id) > 128) {
|
||||
$id = substr($id, 0, 128 - 32).md5($id);
|
||||
}
|
||||
$cursorId = ["group_id" => $groupId, "id" => $id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $cursorId
|
||||
*/
|
||||
function __construct($cursorId) {
|
||||
parent::__construct();
|
||||
self::verifix_id($cursorId);
|
||||
cache::verifix_id($cursorId);
|
||||
$this->cursorId = $cursorId;
|
||||
}
|
||||
|
||||
|
7
src/cache/CacheFile.php
vendored
7
src/cache/CacheFile.php
vendored
@ -19,6 +19,11 @@ class CacheFile extends SharedFile {
|
||||
|
||||
const EXT = ".cache";
|
||||
|
||||
static function with($data, ?string $file=null): self {
|
||||
if ($data instanceof self) return $data;
|
||||
else return new static($file, $data);
|
||||
}
|
||||
|
||||
protected function ensure_source($source): CacheData {
|
||||
if ($source instanceof CacheData) return $source;
|
||||
if (cv::subclass_of($source, CacheData::class)) return new $source();
|
||||
@ -26,7 +31,7 @@ class CacheFile extends SharedFile {
|
||||
throw ValueException::invalid_type($source, CacheData::class);
|
||||
}
|
||||
|
||||
function __construct($file, $data=null, ?array $params=null) {
|
||||
function __construct(?string $file, $data=null, ?array $params=null) {
|
||||
$file ??= path::join(sys_get_temp_dir(), utils::uuidgen());
|
||||
$file = path::ensure_ext($file, self::EXT);
|
||||
$this->basedir = path::dirname($file);
|
||||
|
68
src/cache/CacheManager.php
vendored
Normal file
68
src/cache/CacheManager.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
namespace nulib\cache;
|
||||
|
||||
use nulib\cl;
|
||||
|
||||
/**
|
||||
* Class CacheManager: un gestionnaire de cache permettant de désactiver la mise
|
||||
* en cache d'une valeur dans le cadre d'une session.
|
||||
*
|
||||
* en effet, si on désactive le cache, il doit être réactivé après que la valeur
|
||||
* est calculée, pour éviter qu'une valeur soit calculée encore et encore dans
|
||||
* une session de travail
|
||||
*/
|
||||
class CacheManager {
|
||||
function __construct(?array $includes=null, ?array $excludes=null) {
|
||||
$this->shouldCaches = [];
|
||||
$this->defaultCache = true;
|
||||
$this->includes = $includes;
|
||||
$this->excludes = $excludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array tableau {id => shouldCache} indiquant si l'élément id doit être
|
||||
* mis en cache
|
||||
*/
|
||||
protected array $shouldCaches;
|
||||
|
||||
/**
|
||||
* @var bool valeur par défaut de shouldCache si la valeur n'est pas trouvée
|
||||
* dans $shouldCache
|
||||
*/
|
||||
protected bool $defaultCache;
|
||||
|
||||
/**
|
||||
* @var array|null groupes à toujours inclure dans le cache. pour les
|
||||
* identifiants de ces groupe, {@link self::shouldCache()} retourne toujours
|
||||
* true.
|
||||
*
|
||||
* $excludes est prioritaire par rapport à $includes
|
||||
*/
|
||||
protected ?array $includes;
|
||||
|
||||
/**
|
||||
* @var array|null groupes à exclure de la mise en cache. la mise en cache est
|
||||
* toujours calculée pour les identifiants de ces groupes.
|
||||
*/
|
||||
protected ?array $excludes;
|
||||
|
||||
function setNoCache(bool $noCache=true, bool $reset=true): self {
|
||||
if ($reset) $this->shouldCaches = [];
|
||||
$this->defaultCache = !$noCache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function shouldCache(string $id, ?string $groupId=null, bool $reset=true): bool {
|
||||
if ($groupId !== null) {
|
||||
$includes = $this->includes;
|
||||
$shouldInclude = $includes !== null && in_array($groupId, $includes);
|
||||
$excludes = $this->excludes;
|
||||
$shouldExclude = $excludes !== null && in_array($groupId, $excludes);
|
||||
if ($shouldInclude && !$shouldExclude) return true;
|
||||
}
|
||||
$cacheId = "$groupId-$id";
|
||||
$shouldCache = cl::get($this->shouldCaches, $cacheId, $this->defaultCache);
|
||||
$this->shouldCaches[$cacheId] = $reset?: $shouldCache;
|
||||
return $shouldCache;
|
||||
}
|
||||
}
|
61
src/cache/cache.php
vendored
61
src/cache/cache.php
vendored
@ -4,6 +4,7 @@ namespace nulib\cache;
|
||||
use nulib\app;
|
||||
use nulib\db\CapacitorStorage;
|
||||
use nulib\db\sqlite\SqliteStorage;
|
||||
use nulib\ext\utils;
|
||||
use nulib\php\func;
|
||||
|
||||
class cache {
|
||||
@ -15,7 +16,7 @@ class cache {
|
||||
|
||||
protected static ?CapacitorStorage $storage = null;
|
||||
|
||||
protected static function storage(): CapacitorStorage {
|
||||
static function storage(): CapacitorStorage {
|
||||
return self::$storage ??= new SqliteStorage(self::dbfile());
|
||||
}
|
||||
|
||||
@ -23,13 +24,59 @@ class cache {
|
||||
return self::$storage = $storage;
|
||||
}
|
||||
|
||||
static function all(?iterable $rows, $cursorId=null): iterable {
|
||||
CacheChannel::verifix_id($cursorId);
|
||||
$file = "row-{$cursorId["group_id"]}-{$cursorId["id"]}";
|
||||
$cache = new CacheFile($file, function() use ($rows, $cursorId) {
|
||||
CacheChannel::with(self::storage(), null, $cursorId)->build($rows);
|
||||
protected static ?CacheManager $manager = null;
|
||||
|
||||
static function manager(): CacheManager {
|
||||
return self::$manager ??= new CacheManager();
|
||||
}
|
||||
|
||||
static function set_manager(CacheManager $manager): CacheManager {
|
||||
return self::$manager = $manager;
|
||||
}
|
||||
|
||||
static function nc(bool $noCache=true, bool $reset=false): void {
|
||||
self::manager()->setNoCache($noCache, $reset);
|
||||
}
|
||||
|
||||
protected static function should_cache(string $id, ?string $groupId=null, bool $reset=true): bool {
|
||||
return self::manager()->shouldCache($id, $groupId, $reset);
|
||||
}
|
||||
|
||||
static function verifix_id(&$cacheId): void {
|
||||
$cacheId ??= utils::uuidgen();
|
||||
if (is_array($cacheId)) {
|
||||
$keys = array_keys($cacheId);
|
||||
if (array_key_exists("id", $cacheId)) $idKey = "id";
|
||||
else $idKey = $keys[0] ?? null;
|
||||
$id = strval($cacheId[$idKey] ?? "");
|
||||
if (array_key_exists("group_id", $cacheId)) $groupIdKey = "group_id";
|
||||
else $groupIdKey = $keys[1] ?? null;
|
||||
$groupId = strval($cacheId[$groupIdKey] ?? "");
|
||||
} else {
|
||||
$id = strval($cacheId);
|
||||
$groupId = "";
|
||||
}
|
||||
# si le groupe ou le nom sont trop grand, en faire un hash
|
||||
if (strlen($groupId) > 32) $groupId = md5($groupId);
|
||||
if (strlen($id) > 128) $id = substr($id, 0, 128 - 32).md5($id);
|
||||
$cacheId = ["group_id" => $groupId, "id" => $id];
|
||||
}
|
||||
|
||||
static function get(callable $compute, $dataId=null, ?string $file=null) {
|
||||
self::verifix_id($dataId);
|
||||
$file ??= "{$dataId["group_id"]}-{$dataId["id"]}";
|
||||
$noCache = !self::should_cache($dataId["id"], $dataId["group_id"]);
|
||||
return CacheFile::with($compute, $file)->get(null, $noCache);
|
||||
}
|
||||
|
||||
static function all(?iterable $rows, $cursorId=null, ?string $file=null): iterable {
|
||||
self::verifix_id($cursorId);
|
||||
$file ??= "{$cursorId["group_id"]}-{$cursorId["id"]}--rows";
|
||||
$ccursorId = new CacheFile($file, function() use ($rows, $cursorId) {
|
||||
CacheChannel::with(null, $cursorId)->build($rows);
|
||||
return $cursorId;
|
||||
});
|
||||
return CacheChannel::with(self::storage(), null, $cache->get());
|
||||
$noCache = !self::should_cache($cursorId["id"], $cursorId["group_id"]);
|
||||
return CacheChannel::with(null, $ccursorId->get(null, $noCache));
|
||||
}
|
||||
}
|
||||
|
2
tests/cache/.gitignore
vendored
2
tests/cache/.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
/capacitor.db*
|
||||
/*.db*
|
||||
/*.cache
|
||||
|
2
tests/cache/CursorChannelTest.php
vendored
2
tests/cache/CursorChannelTest.php
vendored
@ -11,7 +11,7 @@ class CursorChannelTest extends _TestCase {
|
||||
["a" => 1, "b" => 2],
|
||||
];
|
||||
|
||||
$channel = CacheChannel::with(self::$storage, $data, "numbers");
|
||||
$channel = CacheChannel::with($data, "numbers", self::$storage);
|
||||
$count = 0;
|
||||
foreach ($channel as $key => $item) {
|
||||
msg::info("one: $key => {$item["a"]}");
|
||||
|
2
tests/cache/_TestCase.php
vendored
2
tests/cache/_TestCase.php
vendored
@ -12,7 +12,7 @@ class _TestCase extends TestCase {
|
||||
static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
msg::set_messenger_class(StdMessenger::class);
|
||||
self::$storage = new SqliteStorage(__DIR__."/capacitor.db");
|
||||
self::$storage = new SqliteStorage(__DIR__."/cache.db");
|
||||
cache::set_storage(self::$storage);
|
||||
}
|
||||
|
||||
|
45
tests/cache/cacheTest.php
vendored
45
tests/cache/cacheTest.php
vendored
@ -1,16 +1,18 @@
|
||||
<?php
|
||||
namespace nulib\cache;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\output\msg;
|
||||
|
||||
class cacheTest extends _TestCase {
|
||||
const DATA = [
|
||||
"fr" => ["a" => "un", "b" => "deux"],
|
||||
"eng" => ["a" => "one", "b" => "two"],
|
||||
["a" => 1, "b" => 2],
|
||||
];
|
||||
|
||||
function gendata() {
|
||||
$data = [
|
||||
"fr" => ["a" => "un", "b" => "deux"],
|
||||
"eng" => ["a" => "one", "b" => "two"],
|
||||
["a" => 1, "b" => 2],
|
||||
];
|
||||
foreach ($data as $key => $item) {
|
||||
foreach (self::DATA as $key => $item) {
|
||||
msg::info("yield $key");
|
||||
yield $key => $item;
|
||||
sleep(2);
|
||||
@ -18,13 +20,36 @@ class cacheTest extends _TestCase {
|
||||
msg::info("fin gendata");
|
||||
}
|
||||
|
||||
function testUsage() {
|
||||
$data = cache::all($this->gendata(),"gendata");
|
||||
function _testRows(iterable $rows) {
|
||||
$count = 0;
|
||||
foreach ($data as $key => $item) {
|
||||
msg::info("got $key => ".var_export($item, true));
|
||||
foreach ($rows as $key => $row) {
|
||||
msg::info("got $key => ".var_export($row, true));
|
||||
$count++;
|
||||
}
|
||||
self::assertSame(3, $count);
|
||||
}
|
||||
|
||||
function testUsage() {
|
||||
msg::section("all");
|
||||
$rows = cache::all($this->gendata(),"gendata");
|
||||
$this->_testRows($rows);
|
||||
|
||||
msg::section("get");
|
||||
$rows = cache::get(function() {
|
||||
return self::DATA;
|
||||
},"gendata");
|
||||
$this->_testRows($rows);
|
||||
}
|
||||
|
||||
function testNc() {
|
||||
cache::nc();
|
||||
|
||||
msg::section("first pass");
|
||||
$rows = cache::all($this->gendata(),"gendata");
|
||||
$this->_testRows($rows);
|
||||
|
||||
msg::section("second pass");
|
||||
$rows = cache::all($this->gendata(),"gendata");
|
||||
$this->_testRows($rows);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user