Files
preauth/src/MonitorCacheKeys.php
T
lyra 408d75dda1
Sync GitHub / sync (push) Successful in 8s
chore: nice-to-have improvements for v1.0
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
2026-08-11 16:37:23 -04:00

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);
}
}