- 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.
344 lines
8.7 KiB
PHP
344 lines
8.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Discovery\Storage;
|
|
|
|
use App\Framework\Async\FiberManager;
|
|
use App\Framework\Filesystem\Directory;
|
|
use App\Framework\Filesystem\File;
|
|
use App\Framework\Filesystem\PermissionChecker;
|
|
use App\Framework\Filesystem\Storage;
|
|
use App\Framework\Filesystem\ValueObjects\FileMetadata;
|
|
use SplFileInfo;
|
|
|
|
/**
|
|
* Implementierung des DiscoveryStorage-Interfaces, die das Filesystem-Modul nutzt
|
|
* und die Discovery-spezifischen Methoden implementiert.
|
|
*
|
|
* Diese Klasse verwendet Composition, um die Funktionalität des Storage-Interfaces
|
|
* zu delegieren und erweitert sie um Discovery-spezifische Funktionen.
|
|
*/
|
|
final class FileSystemDiscoveryStorage implements DiscoveryStorage
|
|
{
|
|
public readonly PermissionChecker $permissions;
|
|
|
|
public readonly FiberManager $fiberManager;
|
|
|
|
/**
|
|
* @param Storage $storage Basis-Storage-Implementierung für Delegation
|
|
* @param PermissionChecker $permissions Permissions-Checker
|
|
* @param FiberManager $fiberManager Fiber-Manager für asynchrone Operationen
|
|
*/
|
|
public function __construct(
|
|
private readonly Storage $storage,
|
|
?PermissionChecker $permissions = null,
|
|
?FiberManager $fiberManager = null
|
|
) {
|
|
$this->permissions = $permissions ?? new PermissionChecker($storage);
|
|
$this->fiberManager = $fiberManager ?? new FiberManager(
|
|
new \App\Framework\DateTime\SystemClock(),
|
|
new \App\Framework\DateTime\SystemTimer()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function get(string $path): string
|
|
{
|
|
return $this->storage->get($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function put(string $path, string $content): void
|
|
{
|
|
$this->storage->put($path, $content);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function exists(string $path): bool
|
|
{
|
|
return $this->storage->exists($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function delete(string $path): void
|
|
{
|
|
$this->storage->delete($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function copy(string $source, string $destination): void
|
|
{
|
|
$this->storage->copy($source, $destination);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function size(string $path): int
|
|
{
|
|
return $this->storage->size($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function lastModified(string $path): int
|
|
{
|
|
return $this->storage->lastModified($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getMimeType(string $path): string
|
|
{
|
|
return $this->storage->getMimeType($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function isReadable(string $path): bool
|
|
{
|
|
return $this->storage->isReadable($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function isWritable(string $path): bool
|
|
{
|
|
return $this->storage->isWritable($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function listDirectory(string $directory): array
|
|
{
|
|
return $this->storage->listDirectory($directory);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function createDirectory(string $path, int $permissions = 0755, bool $recursive = true): void
|
|
{
|
|
$this->storage->createDirectory($path, $permissions, $recursive);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function file(string $path): File
|
|
{
|
|
return $this->storage->file($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function directory(string $path): Directory
|
|
{
|
|
return $this->storage->directory($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function batch(array $operations): array
|
|
{
|
|
return $this->storage->batch($operations);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getMultiple(array $paths): array
|
|
{
|
|
return $this->storage->getMultiple($paths);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function putMultiple(array $files): void
|
|
{
|
|
$this->storage->putMultiple($files);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getMetadataMultiple(array $paths): array
|
|
{
|
|
return $this->storage->getMetadataMultiple($paths);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function findChangedFiles(string $directory, array $fileMetadata): array
|
|
{
|
|
// Finde alle Dateien mit dem Muster
|
|
$allFiles = $this->findFiles($directory, '*.php');
|
|
$changedFiles = [];
|
|
$newFiles = [];
|
|
$modifiedFiles = [];
|
|
|
|
// Prüfe jede Datei auf Änderungen
|
|
foreach ($allFiles as $file) {
|
|
$filePath = $file->getPathname();
|
|
|
|
// Neue Datei (nicht in Metadaten)
|
|
if (! isset($fileMetadata[$filePath])) {
|
|
$newFiles[] = $file;
|
|
$changedFiles[] = $file;
|
|
|
|
continue;
|
|
}
|
|
|
|
// Prüfe auf Änderungen mit detaillierten Metadaten
|
|
try {
|
|
$storedMetadata = FileMetadata::fromArray($fileMetadata[$filePath]);
|
|
|
|
if ($storedMetadata->hasChanged($filePath, $this)) {
|
|
$modifiedFiles[] = $file;
|
|
$changedFiles[] = $file;
|
|
}
|
|
} catch (\Throwable) {
|
|
// Bei Problemen mit Metadaten, behandle als geändert
|
|
$changedFiles[] = $file;
|
|
}
|
|
}
|
|
|
|
return $changedFiles;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function incrementalScan(string $directory, array $fileMetadata): array
|
|
{
|
|
$changedFiles = $this->findChangedFiles($directory, $fileMetadata);
|
|
$updatedMetadata = $fileMetadata;
|
|
|
|
// Aktualisiere Metadaten für geänderte Dateien
|
|
foreach ($changedFiles as $file) {
|
|
$filePath = $file->getPathname();
|
|
|
|
try {
|
|
$metadata = $this->getDiscoveryMetadata($filePath, true);
|
|
$updatedMetadata[$filePath] = $metadata->toArray();
|
|
} catch (\Throwable) {
|
|
// Bei Fehlern, entferne die Metadaten
|
|
unset($updatedMetadata[$filePath]);
|
|
}
|
|
}
|
|
|
|
// Entferne gelöschte Dateien aus Metadaten
|
|
$allFiles = $this->findFiles($directory, '*.php');
|
|
$existingPaths = array_map(fn (SplFileInfo $file) => $file->getPathname(), $allFiles);
|
|
|
|
foreach (array_keys($updatedMetadata) as $path) {
|
|
if (! in_array($path, $existingPaths)) {
|
|
unset($updatedMetadata[$path]);
|
|
}
|
|
}
|
|
|
|
return $updatedMetadata;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function findFiles(string $directory, string $pattern): array
|
|
{
|
|
$result = [];
|
|
$this->findFilesRecursive($directory, $pattern, $result);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Rekursive Hilfsmethode für findFiles
|
|
*/
|
|
private function findFilesRecursive(string $directory, string $pattern, array &$result): void
|
|
{
|
|
if (! is_dir($directory)) {
|
|
return;
|
|
}
|
|
|
|
$files = scandir($directory);
|
|
if ($files === false) {
|
|
return;
|
|
}
|
|
|
|
foreach ($files as $file) {
|
|
if ($file === '.' || $file === '..') {
|
|
continue;
|
|
}
|
|
|
|
$path = $directory . DIRECTORY_SEPARATOR . $file;
|
|
|
|
if (is_dir($path)) {
|
|
$this->findFilesRecursive($path, $pattern, $result);
|
|
} elseif ($this->matchesPattern($file, $pattern)) {
|
|
$result[] = new SplFileInfo($path);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prüft, ob ein Dateiname einem Muster entspricht
|
|
*/
|
|
private function matchesPattern(string $filename, string $pattern): bool
|
|
{
|
|
return fnmatch($pattern, $filename);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getDiscoveryMetadata(string $filePath, bool $calculateChecksum = true): FileMetadata
|
|
{
|
|
return FileMetadata::fromFile($filePath, $this, $calculateChecksum);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getDiscoveryMetadataMultiple(array $filePaths, bool $calculateChecksum = true): array
|
|
{
|
|
$operations = [];
|
|
|
|
foreach ($filePaths as $path) {
|
|
$operations[$path] = fn () => $this->getDiscoveryMetadata($path, $calculateChecksum);
|
|
}
|
|
|
|
return $this->batch($operations);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function registerFileSystemEvents(string $directory, callable $callback): bool
|
|
{
|
|
// Implementierung hängt von der konkreten Event-System-Unterstützung ab
|
|
// Hier eine einfache Implementierung, die immer false zurückgibt
|
|
// In einer realen Implementierung würde hier ein Filesystem-Watcher registriert
|
|
return false;
|
|
}
|
|
}
|