validate($prefix); } /** * Create cache prefix from string */ public static function fromString(string $prefix): self { return new self($prefix); } /** * Create prefix for general cache items */ public static function general(): self { return new self('cache:'); } /** * Create prefix for query cache items */ public static function query(): self { return new self('query_cache:'); } /** * Create prefix for session items */ public static function session(): self { return new self('session:'); } /** * Create prefix for specific namespace */ public static function forNamespace(string $namespace): self { return new self($namespace . ':'); } /** * Create prefix for user-related items */ public static function forUser(string|int $userId): self { return new self("user:{$userId}:"); } /** * Create prefix for temporary items */ public static function forTemporary(): self { return new self('temp:'); } /** * Get string representation of the prefix */ public function toString(): string { return $this->prefix; } /** * Get the type of cache identifier */ public function getType(): CacheIdentifierType { return CacheIdentifierType::PREFIX; } /** * Check if this prefix equals another identifier */ public function equals(CacheIdentifier $other): bool { return $other instanceof self && $this->prefix === $other->prefix; } /** * Check if this prefix matches a cache key */ public function matchesKey(CacheKey $key): bool { return str_starts_with($key->toString(), $this->prefix); } /** * Get a normalized string for internal cache operations */ public function getNormalizedString(): string { return self::PREFIX_MARKER . $this->prefix; } /** * Create a cache key with this prefix */ public function createKey(string $suffix): CacheKey { return CacheKey::fromString($this->prefix . $suffix); } /** * Remove this prefix from a cache key string */ public function removeFromKey(string $key): string { if (str_starts_with($key, $this->prefix)) { return substr($key, strlen($this->prefix)); } return $key; } /** * Check if prefix ends with separator */ public function hasTrailingSeparator(): bool { return str_ends_with($this->prefix, ':'); } /** * Ensure prefix has trailing separator */ public function withTrailingSeparator(): self { if ($this->hasTrailingSeparator()) { return $this; } return new self($this->prefix . ':'); } /** * Validate the prefix */ private function validate(string $prefix): void { if (empty($prefix)) { throw new InvalidArgumentException('Cache prefix cannot be empty'); } if (strlen($prefix) > self::MAX_PREFIX_LENGTH) { throw new InvalidArgumentException(sprintf( 'Cache prefix length exceeds maximum of %d characters (got %d)', self::MAX_PREFIX_LENGTH, strlen($prefix) )); } // Check for invalid characters if (preg_match('/[\s\n\r\t\0\x0B*?]/', $prefix)) { throw new InvalidArgumentException('Cache prefix contains invalid characters'); } } }