- 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.
200 lines
6.4 KiB
PHP
200 lines
6.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Core;
|
|
|
|
use App\Framework\Cache\Cache;
|
|
use App\Framework\Cache\CacheKey;
|
|
use App\Framework\Core\ValueObjects\ClassName;
|
|
use App\Framework\Discovery\FileVisitor;
|
|
use App\Framework\Discovery\ReflectionAwareVisitor;
|
|
use App\Framework\Filesystem\ValueObjects\FilePath;
|
|
use App\Framework\Reflection\WrappedReflectionClass;
|
|
|
|
/**
|
|
* Visitor zum Auffinden von Interface-Implementierungen
|
|
*/
|
|
final class InterfaceImplementationVisitor implements FileVisitor, ReflectionAwareVisitor
|
|
{
|
|
/** @var array<string, mixed> */
|
|
private array $interfaces = [];
|
|
|
|
/** @var array<string, array<int, string>> */
|
|
private array $implementations = [];
|
|
|
|
/** @var array<string, array<int, string>> */
|
|
private array $implementationsByClass = [];
|
|
|
|
/**
|
|
* @param array<int, string> $targetInterfaces Die zu suchenden Interfaces
|
|
*/
|
|
public function __construct(
|
|
private readonly array $targetInterfaces = []
|
|
) {
|
|
}
|
|
|
|
public function onScanStart(): void
|
|
{
|
|
$this->implementations = [];
|
|
$this->implementationsByClass = [];
|
|
}
|
|
|
|
public function onIncrementalScanStart(): void
|
|
{
|
|
// Bei inkrementellem Scan behalten wir vorhandene Implementierungen
|
|
// und aktualisieren sie mit neuen Daten
|
|
}
|
|
|
|
public function onIncrementalScanComplete(): void
|
|
{
|
|
// Sortiere nach inkrementellem Scan
|
|
$this->sortImplementations();
|
|
}
|
|
|
|
public function visitClass(ClassName $className, FilePath $filePath): void
|
|
{
|
|
// This method is kept for backward compatibility but should not be used
|
|
// when ReflectionProvider is available. The UnifiedDiscoveryService will
|
|
// prefer visitClassWithReflection() when possible.
|
|
}
|
|
|
|
public function visitClassWithReflection(ClassName $className, FilePath $filePath, WrappedReflectionClass $reflection): void
|
|
{
|
|
try {
|
|
// Skip abstract classes and interfaces - only process instantiable classes
|
|
if (! $reflection->isInstantiable()) {
|
|
return;
|
|
}
|
|
|
|
// Alte Einträge für diese Klasse entfernen (wichtig für inkrementelle Scans)
|
|
$classNameStr = $className->getFullyQualified();
|
|
$this->removeImplementationsForClass($classNameStr);
|
|
|
|
// Prüfe, ob die Klasse eines der Ziel-Interfaces implementiert
|
|
foreach ($this->targetInterfaces as $interface) {
|
|
if ($reflection->implementsInterface($interface)) {
|
|
if (! isset($this->implementations[$interface])) {
|
|
$this->implementations[$interface] = [];
|
|
}
|
|
|
|
// Prüfe auf Duplikate
|
|
if (! in_array($classNameStr, $this->implementations[$interface])) {
|
|
$this->implementations[$interface][] = $classNameStr;
|
|
|
|
// Umgekehrten Index für schnelleren Zugriff aufbauen
|
|
if (! isset($this->implementationsByClass[$classNameStr])) {
|
|
$this->implementationsByClass[$classNameStr] = [];
|
|
}
|
|
$this->implementationsByClass[$classNameStr][] = $interface;
|
|
}
|
|
}
|
|
}
|
|
} catch (\Throwable $e) {
|
|
// Silent failure - skip this class and continue with discovery
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Entfernt alle Interface-Implementierungen für eine bestimmte Klasse
|
|
*/
|
|
private function removeImplementationsForClass(string $className): void
|
|
{
|
|
if (! isset($this->implementationsByClass[$className])) {
|
|
return;
|
|
}
|
|
|
|
foreach ($this->implementationsByClass[$className] as $interface) {
|
|
if (isset($this->implementations[$interface])) {
|
|
$key = array_search($className, $this->implementations[$interface]);
|
|
if ($key !== false) {
|
|
unset($this->implementations[$interface][$key]);
|
|
// Array-Indizes neu numerieren
|
|
$this->implementations[$interface] = array_values($this->implementations[$interface]);
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($this->implementationsByClass[$className]);
|
|
}
|
|
|
|
public function onScanComplete(): void
|
|
{
|
|
// Sortiere Implementierungen für konsistente Reihenfolge
|
|
$this->sortImplementations();
|
|
}
|
|
|
|
/**
|
|
* Sortiert alle Implementierungen für konsistente Ergebnisse
|
|
*/
|
|
private function sortImplementations(): void
|
|
{
|
|
foreach ($this->implementations as &$classes) {
|
|
sort($classes);
|
|
}
|
|
}
|
|
|
|
public function loadFromCache(Cache $cache): void
|
|
{
|
|
$cacheItem = $cache->get($this->getCacheKey());
|
|
if ($cacheItem->isHit) {
|
|
if (is_array($cacheItem->value) && isset($cacheItem->value['implementations'], $cacheItem->value['byClass'])) {
|
|
$this->implementations = $cacheItem->value['implementations'];
|
|
$this->implementationsByClass = $cacheItem->value['byClass'];
|
|
}
|
|
}
|
|
}
|
|
|
|
public function getCacheKey(): CacheKey
|
|
{
|
|
return CacheKey::fromString('interface_implementations');
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function getCacheableData(): array
|
|
{
|
|
return [
|
|
'implementations' => $this->implementations,
|
|
'byClass' => $this->implementationsByClass,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Gibt alle Implementierungen eines Interfaces zurück
|
|
* @return array<int, string>
|
|
*/
|
|
public function getImplementations(string $interface): array
|
|
{
|
|
return $this->implementations[$interface] ?? [];
|
|
}
|
|
|
|
/**
|
|
* Prüft, ob eine Klasse ein bestimmtes Interface implementiert
|
|
*/
|
|
public function doesImplement(string $className, string $interface): bool
|
|
{
|
|
return isset($this->implementationsByClass[$className]) &&
|
|
in_array($interface, $this->implementationsByClass[$className]);
|
|
}
|
|
|
|
/**
|
|
* Gibt alle Interfaces zurück, die eine Klasse implementiert
|
|
* @return array<int, string>
|
|
*/
|
|
public function getClassInterfaces(string $className): array
|
|
{
|
|
return $this->implementationsByClass[$className] ?? [];
|
|
}
|
|
|
|
/**
|
|
* Gibt alle gefundenen Implementierungen zurück
|
|
* @return array<string, array<int, string>>
|
|
*/
|
|
public function getAllImplementations(): array
|
|
{
|
|
return $this->implementations;
|
|
}
|
|
}
|