Sync GitHub / sync (push) Successful in 8s
Code quality: - Create AppConstants class with shared constants: - FAR_FUTURE_DATE (replaces duplicated '2999-12-31' strings) - MAX_INPUT_LENGTH (replaces duplicated 128 in Payload and StringTrait) - Extract duplicated 'hi $id' response body into StringTrait::authSuccessResponse() method, used by AcceptListener, AllowListener, and LoginManager - Add missing @throws InvalidArgumentException annotations to MonitorCacheKeys (getItem, hasItem, deleteItem, deleteItems, commit) Configuration: - Add proper env var type casting in services.yaml: - COOKIE_TTL → env(int:) - SUBDOMAIN_REDIRECT → env(bool:) - IP_TTL → env(int:) - TEAPOT → env(bool:) Documentation: - Create CONTRIBUTING.md with development setup, code style, testing guidelines, and PR process
203 lines
5.9 KiB
PHP
203 lines
5.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App;
|
|
|
|
use OutOfBoundsException;
|
|
use Psr\Cache\CacheItemInterface;
|
|
use Psr\Cache\CacheItemPoolInterface;
|
|
use Psr\Cache\InvalidArgumentException;
|
|
|
|
/* we must *NOT* store the key-list item or values within this object
|
|
* because it can change from outside this object instance */
|
|
final readonly class MonitorCacheKeys implements CacheItemPoolInterface
|
|
{
|
|
private const string KEY_LIST = '__key_list';
|
|
private const string CHANGE_LIST = '__chg_list';
|
|
public const int UPDATED = 1;
|
|
public const int REMOVED = 2;
|
|
|
|
private CacheItemPoolInterface $cache;
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function __construct(CacheItemPoolInterface $cache)
|
|
{
|
|
$this->cache = $cache;
|
|
$items = $cache->getItems([self::KEY_LIST, self::CHANGE_LIST]);
|
|
foreach ($items as $item) {
|
|
if (! $item->isHit()) {
|
|
$this->initialize();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
private function initialize(): void
|
|
{
|
|
$keyList = $this->cache->getItem(self::KEY_LIST);
|
|
$changeList = $this->cache->getItem(self::CHANGE_LIST);
|
|
$keyList->set([]);
|
|
$changeList->set([]);
|
|
$this->cache->saveDeferred($keyList);
|
|
$this->cache->saveDeferred($changeList);
|
|
$this->cache->commit();
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function getKeys(): array
|
|
{
|
|
$keyList = $this->cache->getItem(self::KEY_LIST);
|
|
return array_keys($keyList->get() ?? []);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function getChanges(): array
|
|
{
|
|
$changeList = $this->cache->getItem(self::CHANGE_LIST);
|
|
return $changeList->get() ?? [];
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function markClean(): void
|
|
{
|
|
$changeList = $this->cache->getItem(self::CHANGE_LIST);
|
|
$changeList->set([]);
|
|
$this->cache->save($changeList);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function getItem(string $key): CacheItemInterface
|
|
{
|
|
return $this->cache->getItem($key);
|
|
}
|
|
|
|
/** @return CacheItemInterface[]
|
|
* @throws InvalidArgumentException */
|
|
public function getItems(array $keys = []): iterable
|
|
{
|
|
return $this->cache->getItems($keys);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function hasItem(string $key): bool
|
|
{
|
|
return $this->cache->hasItem($key);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function clear(): bool
|
|
{
|
|
/* only bother clearing the pool if it is not empty */
|
|
if (! empty($this->getKeys())) {
|
|
$response = $this->cache->clear();
|
|
|
|
$this->initialize();
|
|
return $response;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function deleteItem(string $key): bool
|
|
{
|
|
$this->isValid($key);
|
|
$keyList = $this->cache->getItem(self::KEY_LIST);
|
|
$keyValues = $keyList->get();
|
|
if (isset($keyValues[$key])) {
|
|
unset($keyValues[$key]);
|
|
$keyList->set($keyValues);
|
|
$this->cache->saveDeferred($keyList);
|
|
$this->logChange($key, MonitorCacheKeys::REMOVED);
|
|
$this->cache->commit();
|
|
}
|
|
|
|
return $this->cache->deleteItem($key);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function deleteItems(array $keys): bool
|
|
{
|
|
$this->allValid($keys);
|
|
$keyList = $this->cache->getItem(self::KEY_LIST);
|
|
$keyValues = $keyList->get();
|
|
foreach ($keys as $key) {
|
|
if (isset($keyValues[$key])) {
|
|
unset($keyValues[$key]);
|
|
$this->logChange($key, MonitorCacheKeys::REMOVED);
|
|
}
|
|
}
|
|
$keyList->set($keyValues);
|
|
$this->cache->saveDeferred($keyList);
|
|
$this->cache->commit();
|
|
|
|
return $this->cache->deleteItems($keys);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function save(CacheItemInterface $item): bool
|
|
{
|
|
$this->update($item);
|
|
return $this->cache->save($item);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function saveDeferred(CacheItemInterface $item): bool
|
|
{
|
|
$this->update($item);
|
|
return $this->cache->saveDeferred($item);
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
public function commit(): bool
|
|
{
|
|
return $this->cache->commit();
|
|
}
|
|
|
|
/** @throws InvalidArgumentException|OutOfBoundsException */
|
|
private function update(CacheItemInterface $item): void
|
|
{
|
|
$this->isValid($item->getKey());
|
|
$keyList = $this->cache->getItem(self::KEY_LIST);
|
|
$keyValues = $keyList->get();
|
|
$keyValues[$item->getKey()] = true;
|
|
$keyList->set($keyValues);
|
|
$this->logChange($item->getKey());
|
|
$this->cache->saveDeferred($keyList);
|
|
$this->cache->commit();
|
|
}
|
|
|
|
/** @throws OutOfBoundsException */
|
|
private function isValid(string $key): void
|
|
{
|
|
if ($key === self::KEY_LIST || $key === self::CHANGE_LIST) {
|
|
throw new OutOfBoundsException(
|
|
'Can not modify the private key or change lists'
|
|
);
|
|
}
|
|
}
|
|
|
|
/** @throws OutOfBoundsException */
|
|
private function allValid(array $keys): void
|
|
{
|
|
if (in_array(self::KEY_LIST, $keys, true) ||
|
|
in_array(self::CHANGE_LIST, $keys, true)
|
|
) {
|
|
throw new OutOfBoundsException(
|
|
'Can not modify the private key or change lists'
|
|
);
|
|
}
|
|
}
|
|
|
|
/** @throws InvalidArgumentException */
|
|
private function logChange(string $key, int $code = MonitorCacheKeys::UPDATED): void
|
|
{
|
|
$changeList = $this->cache->getItem(self::CHANGE_LIST);
|
|
$changeValues = $changeList->get();
|
|
$changeValues[$key] = $code;
|
|
$changeList->set($changeValues);
|
|
$this->cache->saveDeferred($changeList);
|
|
}
|
|
}
|