Files
michaelschiemer/src/Framework/LiveComponents/Caching/CacheKeyBuilder.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

170 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\LiveComponents\Caching;
use App\Framework\Cache\CacheKey;
/**
* Cache Key Builder
*
* Builds intelligent cache keys for LiveComponents with varyBy support.
*
* Key Format: livecomponent:{component_name}:{base_key}:{vary_suffix}
*
* Examples:
* - livecomponent:user-stats:total-count:u:123:l:en
* - livecomponent:product-list:category-5:l:de:f:new-ui
* - livecomponent:dashboard:widgets:global
*
* Framework Pattern: Readonly service class
*/
final readonly class CacheKeyBuilder
{
/**
* Build cache key with varyBy support
*
* @param string $componentName - Component name (e.g., "user-stats")
* @param string $baseKey - Base cache key from component
* @param VaryBy|null $varyBy - VaryBy specification
* @param CacheContext|null $context - Current cache context
* @return CacheKey - Complete cache key
*/
public function build(
string $componentName,
string $baseKey,
?VaryBy $varyBy = null,
?CacheContext $context = null
): CacheKey {
// Start with component prefix
$parts = ['livecomponent', $componentName, $baseKey];
// Add varyBy suffix if specified
if ($varyBy && $context) {
$varySuffix = $varyBy->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;
}
}