Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace App\Framework\Filesystem\Traits;
use App\Framework\Filesystem\Exceptions\FileWriteException;
/**
* Trait für Append Storage-Operationen
*
* Implementiert Append-Funktionalität für Logs,
* Analytics und Stream-artige Daten.
*/
trait AppendableStorageTrait
{
public function append(string $path, string $content): void
{
$resolvedPath = $this->resolvePath($path);
$dir = dirname($resolvedPath);
if (! is_dir($dir)) {
$this->createDirectory($path);
}
if (@file_put_contents($resolvedPath, $content, FILE_APPEND | LOCK_EX) === false) {
throw new FileWriteException($path);
}
}
public function appendLine(string $path, string $line): void
{
$this->append($path, $line . PHP_EOL);
}
public function appendJson(string $path, array $data): void
{
$this->appendLine($path, json_encode($data));
}
public function appendCsv(string $path, array $row): void
{
$resolvedPath = $this->resolvePath($path);
$handle = @fopen($resolvedPath, 'a');
if ($handle === false) {
throw new FileWriteException($path);
}
if (@fputcsv($handle, $row) === false) {
@fclose($handle);
throw new FileWriteException($path);
}
@fclose($handle);
}
public function appendWithTimestamp(string $path, string $content): void
{
$timestampedContent = '[' . date('Y-m-d H:i:s') . '] ' . $content;
$this->appendLine($path, $timestampedContent);
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Framework\Filesystem\Traits;
use App\Framework\Filesystem\Exceptions\FileWriteException;
/**
* Trait für Atomic Storage-Operationen
*
* Implementiert atomare Schreiboperationen durch temporäre Dateien
* und rename()-Operation für Data Consistency.
*/
trait AtomicStorageTrait
{
public function putAtomic(string $path, string $content): void
{
$tempPath = $path . '.tmp.' . uniqid();
$this->put($tempPath, $content);
$resolvedPath = $this->resolvePath($path);
$resolvedTempPath = $this->resolvePath($tempPath);
if (! @rename($resolvedTempPath, $resolvedPath)) {
@unlink($resolvedTempPath);
throw new FileWriteException($path);
}
}
public function updateAtomic(string $path, callable $updateCallback): void
{
$originalContent = $this->exists($path) ? $this->get($path) : '';
$newContent = $updateCallback($originalContent);
$this->putAtomic($path, $newContent);
}
public function updateJsonAtomic(string $path, callable $updateCallback): void
{
$originalData = $this->exists($path) ? json_decode($this->get($path), true) ?? [] : [];
$newData = $updateCallback($originalData);
$this->putAtomic($path, json_encode($newData, JSON_PRETTY_PRINT));
}
}

View File

@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace App\Framework\Filesystem\Traits;
use App\Framework\Filesystem\Exceptions\FileNotFoundException;
use App\Framework\Filesystem\Exceptions\FileReadException;
use App\Framework\Filesystem\Exceptions\FileWriteException;
/**
* Trait für Compression Storage-Operationen
*
* Implementiert automatische Komprimierung für große Dateien,
* ideal für Analytics-Daten, Logs und Archive.
*/
trait CompressibleStorageTrait
{
public function putCompressed(string $path, string $content, string $algorithm = 'gzip'): void
{
$compressedContent = match ($algorithm) {
'gzip' => gzencode($content),
'deflate' => gzdeflate($content),
'bzip2' => bzcompress($content),
default => throw new \InvalidArgumentException("Unsupported compression algorithm: {$algorithm}")
};
if ($compressedContent === false) {
throw new FileWriteException($path);
}
$this->put($path . '.' . $algorithm, $compressedContent);
}
public function getCompressed(string $path): string
{
// Automatische Erkennung der Komprimierung basierend auf Dateiendung
$pathInfo = pathinfo($path);
$algorithm = $pathInfo['extension'] ?? '';
if (! in_array($algorithm, ['gzip', 'gz', 'deflate', 'bzip2', 'bz2'])) {
throw new \InvalidArgumentException("Cannot detect compression algorithm from path: {$path}");
}
if (! $this->exists($path)) {
throw new FileNotFoundException($path);
}
$compressedContent = $this->get($path);
$content = match ($algorithm) {
'gzip', 'gz' => gzdecode($compressedContent),
'deflate' => gzinflate($compressedContent),
'bzip2', 'bz2' => bzdecompress($compressedContent),
default => throw new \InvalidArgumentException("Unsupported compression algorithm: {$algorithm}")
};
if ($content === false) {
throw new FileReadException($path);
}
return $content;
}
public function compress(string $path, string $algorithm = 'gzip'): void
{
if (! $this->exists($path)) {
throw new FileNotFoundException($path);
}
$content = $this->get($path);
$compressedPath = $path . '.' . $algorithm;
$this->putCompressed($path, $content, $algorithm);
$this->delete($path);
// Komprimierte Datei zurück zum ursprünglichen Pfad verschieben
$this->copy($compressedPath, $path);
$this->delete($compressedPath);
}
public function decompress(string $path): void
{
$content = $this->getCompressed($path);
// Entferne Komprimierungs-Extension
$pathInfo = pathinfo($path);
$algorithm = $pathInfo['extension'] ?? '';
$decompressedPath = $pathInfo['dirname'] . '/' . $pathInfo['filename'];
$this->put($decompressedPath, $content);
$this->delete($path);
}
public function isCompressed(string $path): bool
{
if (! $this->exists($path)) {
return false;
}
$pathInfo = pathinfo($path);
$extension = $pathInfo['extension'] ?? '';
return in_array($extension, ['gzip', 'gz', 'deflate', 'bzip2', 'bz2']);
}
public function getAvailableAlgorithms(): array
{
$algorithms = [];
if (function_exists('gzencode')) {
$algorithms[] = 'gzip';
}
if (function_exists('gzdeflate')) {
$algorithms[] = 'deflate';
}
if (function_exists('bzcompress')) {
$algorithms[] = 'bzip2';
}
return $algorithms;
}
}

View File

@@ -0,0 +1,151 @@
<?php
declare(strict_types=1);
namespace App\Framework\Filesystem\Traits;
use App\Framework\Filesystem\Exceptions\FileNotFoundException;
use App\Framework\Filesystem\Exceptions\FileReadException;
use App\Framework\Filesystem\Exceptions\FileWriteException;
/**
* Trait für File-Locking Storage-Operationen
*
* Implementiert File-Locking für kritische Operationen
* und verhindert Data Corruption bei Concurrent Access.
*/
trait LockableStorageTrait
{
public function withExclusiveLock(string $path, callable $operation): mixed
{
$resolvedPath = $this->resolvePath($path);
$handle = @fopen($resolvedPath, 'c+');
if ($handle === false) {
throw new FileWriteException($path);
}
if (! @flock($handle, LOCK_EX)) {
@fclose($handle);
throw new FileWriteException($path);
}
try {
return $operation($handle);
} finally {
@flock($handle, LOCK_UN);
@fclose($handle);
}
}
public function withSharedLock(string $path, callable $operation): mixed
{
if (! $this->exists($path)) {
throw new FileNotFoundException($path);
}
$resolvedPath = $this->resolvePath($path);
$handle = @fopen($resolvedPath, 'r');
if ($handle === false) {
throw new FileReadException($path);
}
if (! @flock($handle, LOCK_SH)) {
@fclose($handle);
throw new FileReadException($path);
}
try {
return $operation($handle);
} finally {
@flock($handle, LOCK_UN);
@fclose($handle);
}
}
public function isLocked(string $path): bool
{
if (! $this->exists($path)) {
return false;
}
$resolvedPath = $this->resolvePath($path);
$handle = @fopen($resolvedPath, 'r');
if ($handle === false) {
return false;
}
$isLocked = ! @flock($handle, LOCK_EX | LOCK_NB);
if (! $isLocked) {
@flock($handle, LOCK_UN);
}
@fclose($handle);
return $isLocked;
}
public function putWithLock(string $path, string $content): void
{
$this->withExclusiveLock($path, function ($handle) use ($content) {
if (@ftruncate($handle, 0) === false || @rewind($handle) === false) {
throw new FileWriteException('Lock operation failed');
}
if (@fwrite($handle, $content) === false) {
throw new FileWriteException('Lock operation failed');
}
});
}
public function updateWithLock(string $path, callable $updateCallback): void
{
$this->withExclusiveLock($path, function ($handle) use ($updateCallback) {
$originalContent = '';
if (@rewind($handle) !== false) {
$originalContent = @stream_get_contents($handle) ?: '';
}
$newContent = $updateCallback($originalContent);
if (@ftruncate($handle, 0) === false || @rewind($handle) === false) {
throw new FileWriteException('Lock operation failed');
}
if (@fwrite($handle, $newContent) === false) {
throw new FileWriteException('Lock operation failed');
}
});
}
public function appendWithLock(string $path, string $content): void
{
$resolvedPath = $this->resolvePath($path);
$dir = dirname($resolvedPath);
if (! is_dir($dir)) {
$this->createDirectory($path);
}
$handle = @fopen($resolvedPath, 'a');
if ($handle === false) {
throw new FileWriteException($path);
}
if (! @flock($handle, LOCK_EX)) {
@fclose($handle);
throw new FileWriteException($path);
}
try {
if (@fwrite($handle, $content) === false) {
throw new FileWriteException($path);
}
} finally {
@flock($handle, LOCK_UN);
@fclose($handle);
}
}
}

View File

@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace App\Framework\Filesystem\Traits;
use App\Framework\Filesystem\Exceptions\FileNotFoundException;
use App\Framework\Filesystem\Exceptions\FileReadException;
use App\Framework\Filesystem\Exceptions\FileWriteException;
/**
* Trait für Stream-basierte Storage-Operationen
*
* Implementiert Stream-Funktionalität für große Dateien
* ohne komplettes Laden in den Speicher.
*/
trait StreamableStorageTrait
{
public function readStream(string $path)
{
if (! $this->exists($path)) {
throw new FileNotFoundException($path);
}
$resolvedPath = $this->resolvePath($path);
$stream = @fopen($resolvedPath, 'r');
if ($stream === false) {
throw new FileReadException($path);
}
return $stream;
}
public function writeStream(string $path)
{
$resolvedPath = $this->resolvePath($path);
$dir = dirname($resolvedPath);
if (! is_dir($dir)) {
$this->createDirectory($path);
}
$stream = @fopen($resolvedPath, 'w');
if ($stream === false) {
throw new FileWriteException($path);
}
return $stream;
}
public function appendStream(string $path)
{
$resolvedPath = $this->resolvePath($path);
$dir = dirname($resolvedPath);
if (! is_dir($dir)) {
$this->createDirectory($path);
}
$stream = @fopen($resolvedPath, 'a');
if ($stream === false) {
throw new FileWriteException($path);
}
return $stream;
}
public function putStream(string $path, $stream): void
{
$writeStream = $this->writeStream($path);
if (@stream_copy_to_stream($stream, $writeStream) === false) {
@fclose($writeStream);
throw new FileWriteException($path);
}
@fclose($writeStream);
}
public function copyStream(string $source, string $destination): void
{
$sourceStream = $this->readStream($source);
$this->putStream($destination, $sourceStream);
@fclose($sourceStream);
}
public function readLines(string $path): \Generator
{
$stream = $this->readStream($path);
try {
while (($line = @fgets($stream)) !== false) {
yield rtrim($line, "\r\n");
}
} finally {
@fclose($stream);
}
}
}