pool->getItem($this->rootKey($npub, $dTag)); if (!$item->isHit()) { return null; } return $this->unwrap($item->get()); } public function getCategory(string $slug): ?Event { if ($slug === '') { return null; } $item = $this->pool->getItem($this->categoryKey($slug)); if (!$item->isHit()) { return null; } return $this->unwrap($item->get()); } /** * @throws InvalidArgumentException */ public function putRoot(string $npub, string $dTag, Event $event): void { $item = $this->pool->getItem($this->rootKey($npub, $dTag)); $item->set(serialize($event)); $item->expiresAfter(self::PERSIST_TTL); $this->pool->save($item); } /** * @throws InvalidArgumentException */ public function putCategory(string $slug, Event $event): void { if ($slug === '') { return; } $item = $this->pool->getItem($this->categoryKey($slug)); $item->set(serialize($event)); $item->expiresAfter(self::PERSIST_TTL); $this->pool->save($item); } /** * Remove a cached category index (NIP-09 / local invalidation). * * @throws InvalidArgumentException */ public function deleteCategory(string $slug): void { if ($slug === '') { return; } $this->pool->deleteItem($this->categoryKey($slug)); } /** * Remove the cached root magazine index for this npub + d_tag. * * @throws InvalidArgumentException */ public function deleteRoot(string $npub, string $dTag): void { $this->pool->deleteItem($this->rootKey($npub, $dTag)); } private function rootKey(string $npub, string $dTag): string { return self::ROOT_PREFIX.hash('sha256', $npub."\0".$dTag); } /** * Category `d` / slug strings may contain colons (NIP-33 `a` segments); PSR-6 keys must not use `{}()/\@:`. */ private function categoryKey(string $slug): string { return self::CAT_PREFIX.hash('sha256', $slug); } private function unwrap(mixed $value): ?Event { if (!\is_string($value) || $value === '') { return null; } $e = unserialize($value, ['allowed_classes' => [Event::class]]); if (!$e instanceof Event) { return null; } return $e; } }