Files
michaelschiemer/src/Framework/Discovery/Storage/FileSystemDiscoveryStorage.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

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;
}
}