Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
212
src/Framework/Cache/CachePattern.php
Normal file
212
src/Framework/Cache/CachePattern.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Cache;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Cache pattern identifier for wildcard-based operations
|
||||
* Supports patterns like "user:*", "cache.*.data", etc.
|
||||
*/
|
||||
final readonly class CachePattern implements CacheIdentifier
|
||||
{
|
||||
private const int MAX_PATTERN_LENGTH = 150;
|
||||
private const string PATTERN_MARKER = 'pattern:';
|
||||
|
||||
private function __construct(
|
||||
private string $pattern,
|
||||
private string $compiledRegex
|
||||
) {
|
||||
$this->validate($pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cache pattern from wildcard string
|
||||
*
|
||||
* Supports:
|
||||
* - user:* (matches user:123, user:456, etc.)
|
||||
* - cache.*.data (matches cache.sessions.data, cache.users.data)
|
||||
* - temp:** (matches temp:anything:nested:deeply)
|
||||
*/
|
||||
public static function fromWildcard(string $pattern): self
|
||||
{
|
||||
$regex = self::compilePattern($pattern);
|
||||
|
||||
return new self($pattern, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pattern for all keys with prefix
|
||||
*/
|
||||
public static function withPrefix(string $prefix): self
|
||||
{
|
||||
return self::fromWildcard($prefix . '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pattern for all user-related keys
|
||||
*/
|
||||
public static function forUser(string|int $userId): self
|
||||
{
|
||||
return self::fromWildcard("user:{$userId}:*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pattern for all session keys
|
||||
*/
|
||||
public static function forSessions(): self
|
||||
{
|
||||
return self::fromWildcard('session:*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pattern for temporary keys
|
||||
*/
|
||||
public static function forTemporary(): self
|
||||
{
|
||||
return self::fromWildcard('temp:**');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pattern for namespace
|
||||
*/
|
||||
public static function forNamespace(string $namespace): self
|
||||
{
|
||||
return self::fromWildcard("{$namespace}:**");
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
public function getType(): CacheIdentifierType
|
||||
{
|
||||
return CacheIdentifierType::PATTERN;
|
||||
}
|
||||
|
||||
public function equals(CacheIdentifier $other): bool
|
||||
{
|
||||
return $other instanceof self && $this->pattern === $other->pattern;
|
||||
}
|
||||
|
||||
public function matchesKey(CacheKey $key): bool
|
||||
{
|
||||
return preg_match($this->compiledRegex, $key->toString()) === 1;
|
||||
}
|
||||
|
||||
public function getNormalizedString(): string
|
||||
{
|
||||
return self::PATTERN_MARKER . $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original wildcard pattern
|
||||
*/
|
||||
public function getPattern(): string
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get compiled regex pattern
|
||||
*/
|
||||
public function getCompiledRegex(): string
|
||||
{
|
||||
return $this->compiledRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if pattern is simple prefix (ends with single *)
|
||||
*/
|
||||
public function isSimplePrefix(): bool
|
||||
{
|
||||
return str_ends_with($this->pattern, '*') &&
|
||||
substr_count($this->pattern, '*') === 1 &&
|
||||
! str_contains($this->pattern, '**');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prefix part for simple prefix patterns
|
||||
*/
|
||||
public function getPrefix(): ?string
|
||||
{
|
||||
if (! $this->isSimplePrefix()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return substr($this->pattern, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if pattern matches deep nesting (**)
|
||||
*/
|
||||
public function isDeepPattern(): bool
|
||||
{
|
||||
return str_contains($this->pattern, '**');
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate selectivity (0.0 = matches everything, 1.0 = very specific)
|
||||
*/
|
||||
public function getSelectivity(): float
|
||||
{
|
||||
$wildcardCount = substr_count($this->pattern, '*');
|
||||
$deepCount = substr_count($this->pattern, '**');
|
||||
$length = strlen($this->pattern);
|
||||
|
||||
// More specific patterns have higher selectivity
|
||||
$specificity = $length / max(1, $wildcardCount * 5 + $deepCount * 10);
|
||||
|
||||
return min(1.0, $specificity / 20); // Normalize to 0-1 range
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile wildcard pattern to regex
|
||||
*/
|
||||
private static function compilePattern(string $pattern): string
|
||||
{
|
||||
// Escape special regex characters except * and **
|
||||
$escaped = preg_quote($pattern, '/');
|
||||
|
||||
// Replace escaped wildcards back
|
||||
$escaped = str_replace('\\*\\*', '__DEEP_WILDCARD__', $escaped);
|
||||
$escaped = str_replace('\\*', '__WILDCARD__', $escaped);
|
||||
|
||||
// Convert to regex
|
||||
$regex = str_replace('__DEEP_WILDCARD__', '.*', $escaped);
|
||||
$regex = str_replace('__WILDCARD__', '[^:]*', $regex);
|
||||
|
||||
return '/^' . $regex . '$/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the pattern
|
||||
*/
|
||||
private function validate(string $pattern): void
|
||||
{
|
||||
if (empty($pattern)) {
|
||||
throw new InvalidArgumentException('Cache pattern cannot be empty');
|
||||
}
|
||||
|
||||
if (strlen($pattern) > self::MAX_PATTERN_LENGTH) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Cache pattern length exceeds maximum of %d characters (got %d)',
|
||||
self::MAX_PATTERN_LENGTH,
|
||||
strlen($pattern)
|
||||
));
|
||||
}
|
||||
|
||||
// Check for invalid characters
|
||||
if (preg_match('/[\s\n\r\t\0\x0B]/', $pattern)) {
|
||||
throw new InvalidArgumentException('Cache pattern contains invalid characters');
|
||||
}
|
||||
|
||||
// Validate wildcard usage
|
||||
if (str_contains($pattern, '***')) {
|
||||
throw new InvalidArgumentException('Cache pattern cannot contain more than two consecutive wildcards');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user