docs: consolidate documentation into organized structure

- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
This commit is contained in:
2025-10-05 11:05:04 +02:00
parent 887847dde6
commit 5050c7d73a
36686 changed files with 196456 additions and 12398919 deletions

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Framework\View\Processors;
use App\Framework\Config\AppConfig;
use App\Framework\DI\Container;
use App\Framework\Template\Processing\StringProcessor;
use App\Framework\View\Functions\ImageSlotFunction;
@@ -178,6 +179,33 @@ final class PlaceholderReplacer implements StringProcessor
return $value->content;
}
// HtmlElement-Objekte nicht escapen (Framework Components)
if ($value instanceof \App\Framework\View\ValueObjects\HtmlElement) {
return (string) $value;
}
// Arrays und komplexe Objekte können nicht direkt als String dargestellt werden
if (is_array($value)) {
return $this->handleArrayValue($expr, $value);
}
if (is_object($value) && ! method_exists($value, '__toString')) {
return $this->handleObjectValue($expr, $value);
}
// Zusätzlicher Schutz gegen Array-to-String Conversion
if (is_array($value) || (is_object($value) && ! method_exists($value, '__toString'))) {
// In Debug: Exception mit Details werfen
if ($this->isDebugMode()) {
$type = is_array($value) ? 'array[' . count($value) . ']' : 'object(' . get_class($value) . ')';
throw new \InvalidArgumentException("Cannot convert {$type} to string in placeholder: {{ {$expr} }}");
}
// In Production: leerer String
return '';
}
return htmlspecialchars((string)$value, $flags, 'UTF-8');
}
@@ -279,6 +307,69 @@ final class PlaceholderReplacer implements StringProcessor
return $params;
}
/**
* Behandelt Array-Werte in Templates - Debug vs Production Verhalten
*/
private function handleArrayValue(string $expr, array $value): string
{
// In Debug-Mode: Exception werfen um Entwickler auf das Problem hinzuweisen
if ($this->isDebugMode()) {
throw new \InvalidArgumentException(
"Template placeholder '{{ {$expr} }}' resolved to an array, which cannot be displayed as string. " .
"Use array access like '{{ {$expr}.0 }}' or iterate with <for> loop."
);
}
// In Production: Sinnvolle Fallback-Werte für häufige Arrays
if (empty($value)) {
return ''; // Leere Arrays werden zu leerem String
}
// Für Arrays mit nur einem Element: das Element zurückgeben
if (count($value) === 1 && ! is_array(reset($value)) && ! is_object(reset($value))) {
return htmlspecialchars((string)reset($value), ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
// Für einfache Arrays: Anzahl anzeigen
return '[' . count($value) . ' items]';
}
/**
* Behandelt Object-Werte in Templates - Debug vs Production Verhalten
*/
private function handleObjectValue(string $expr, object $value): string
{
// In Debug-Mode: Exception werfen
if ($this->isDebugMode()) {
throw new \InvalidArgumentException(
"Template placeholder '{{ {$expr} }}' resolved to object of type '" . get_class($value) . "', " .
"which cannot be displayed as string. Implement __toString() method or access specific properties."
);
}
// In Production: Klassenname anzeigen
$className = get_class($value);
$shortName = substr($className, strrpos($className, '\\') + 1);
return '[' . $shortName . ']';
}
/**
* Erkennt ob wir im Debug-Modus sind über AppConfig
*/
private function isDebugMode(): bool
{
try {
/** @var AppConfig $appConfig */
$appConfig = $this->container->get(AppConfig::class);
return $appConfig->isDebug();
} catch (\Throwable $e) {
// Fallback zu Environment-Variable falls AppConfig nicht verfügbar
return ($_ENV['APP_ENV'] ?? 'production') === 'development';
}
}
/**
* Teilt einen Parameter-String in einzelne Parameter auf
*/