apply($context); $parts[] = $varySuffix; } else { $parts[] = 'global'; } $keyString = implode(':', $parts); return CacheKey::fromString($keyString); } /** * Build cache key from callable varyBy * * Allows dynamic varyBy logic per component. * * @param string $componentName - Component name * @param string $baseKey - Base cache key * @param callable $varyByCallable - Callable that returns VaryBy * @param CacheContext|null $context - Current cache context * @return CacheKey - Complete cache key */ public function buildFromCallable( string $componentName, string $baseKey, callable $varyByCallable, ?CacheContext $context = null ): CacheKey { $varyBy = $varyByCallable($context); if (! $varyBy instanceof VaryBy) { throw new \InvalidArgumentException( 'varyBy callable must return VaryBy instance' ); } return $this->build($componentName, $baseKey, $varyBy, $context); } /** * Build cache key with array-based varyBy * * Convenience method for simple varyBy arrays. * * @param string $componentName - Component name * @param string $baseKey - Base cache key * @param array $varyByArray - Array like ['userId', 'locale'] * @param CacheContext|null $context - Current cache context * @return CacheKey - Complete cache key */ public function buildFromArray( string $componentName, string $baseKey, array $varyByArray, ?CacheContext $context = null ): CacheKey { $varyBy = $this->varyByFromArray($varyByArray); return $this->build($componentName, $baseKey, $varyBy, $context); } /** * Convert array to VaryBy * * Supports: 'userId', 'locale', 'roles', ['featureFlags' => [...]], ['custom' => [...]] */ private function varyByFromArray(array $array): VaryBy { $userId = in_array('userId', $array, true); $locale = in_array('locale', $array, true); $roles = in_array('roles', $array, true); $featureFlags = []; $custom = []; foreach ($array as $key => $value) { if ($key === 'featureFlags' && is_array($value)) { $featureFlags = $value; } elseif ($key === 'custom' && is_array($value)) { $custom = $value; } } return new VaryBy( userId: $userId, locale: $locale, roles: $roles, featureFlags: $featureFlags, custom: $custom ); } /** * Parse cache key to extract components * * Useful for debugging and introspection. * * @param CacheKey $cacheKey - Cache key to parse * @return array{component: string, base_key: string, vary_suffix: string}|null */ public function parse(CacheKey $cacheKey): ?array { $parts = explode(':', $cacheKey->toString()); if (count($parts) < 4 || $parts[0] !== 'livecomponent') { return null; } return [ 'component' => $parts[1], 'base_key' => $parts[2], 'vary_suffix' => implode(':', array_slice($parts, 3)), ]; } /** * Check if cache key belongs to specific component */ public function isComponentKey(CacheKey $cacheKey, string $componentName): bool { $parsed = $this->parse($cacheKey); return $parsed && $parsed['component'] === $componentName; } }