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

@@ -0,0 +1,190 @@
<?php
declare(strict_types=1);
namespace App\Framework\Mcp\Shared\Formatters;
use App\Framework\Mcp\Core\ValueObjects\OutputFormat;
/**
* Text Output Formatter
*
* Formatiert Daten als plain text für menschliches Lesen mit strukturierter Ausgabe
*/
final readonly class TextFormatter implements OutputFormatter
{
public function format(mixed $data): array
{
$normalizedData = $this->normalizeData($data);
$textContent = $this->convertToText($normalizedData);
return [
'content' => $textContent,
'format' => $this->getFormat()->value,
'line_count' => substr_count($textContent, "\n") + 1,
'character_count' => strlen($textContent),
'word_count' => str_word_count($textContent)
];
}
public function supports(OutputFormat $format): bool
{
return $format === OutputFormat::TEXT;
}
public function getFormat(): OutputFormat
{
return OutputFormat::TEXT;
}
public function getDescription(): string
{
return $this->getFormat()->getDescription();
}
private function normalizeData(mixed $data): mixed
{
return match (true) {
is_string($data) => $data,
is_numeric($data) => (string) $data,
is_bool($data) => $data ? 'true' : 'false',
is_null($data) => 'null',
is_array($data) => $data,
is_object($data) => (array) $data,
default => (string) $data
};
}
private function convertToText(mixed $data, int $depth = 0): string
{
if (is_string($data)) {
return $data;
}
if (is_scalar($data)) {
return (string) $data;
}
if (is_array($data)) {
return $this->arrayToText($data, $depth);
}
return $this->objectToText($data, $depth);
}
private function arrayToText(array $data, int $depth = 0): string
{
if (empty($data)) {
return "No data available\n";
}
$lines = [];
$indent = str_repeat(' ', $depth);
// Check if it's a simple list or associative array
if ($this->isSimpleList($data)) {
return $this->simpleListToText($data, $indent);
}
// Handle associative arrays or complex structures
foreach ($data as $key => $value) {
$formattedKey = $this->formatKey($key);
if (is_scalar($value) || is_null($value)) {
$formattedValue = $this->formatScalarValue($value);
$lines[] = "{$indent}{$formattedKey}: {$formattedValue}";
} elseif (is_array($value)) {
if (empty($value)) {
$lines[] = "{$indent}{$formattedKey}: (empty)";
} else {
$lines[] = "{$indent}{$formattedKey}:";
$nestedText = $this->arrayToText($value, $depth + 1);
$lines[] = rtrim($nestedText);
}
} else {
$lines[] = "{$indent}{$formattedKey}: " . $this->convertToText($value, $depth + 1);
}
}
return implode("\n", $lines) . "\n";
}
private function objectToText(mixed $data, int $depth = 0): string
{
$className = is_object($data) ? get_class($data) : 'Unknown';
$properties = is_object($data) ? (array) $data : [];
$indent = str_repeat(' ', $depth);
$lines = ["{$indent}Object: {$className}"];
if (!empty($properties)) {
foreach ($properties as $key => $value) {
$cleanKey = ltrim($key, "\0*\0");
$formattedValue = $this->convertToText($value, $depth + 1);
$lines[] = "{$indent} {$cleanKey}: {$formattedValue}";
}
}
return implode("\n", $lines) . "\n";
}
private function isSimpleList(array $data): bool
{
if (empty($data)) {
return false;
}
// Check if all keys are sequential integers starting from 0
$keys = array_keys($data);
$expectedKeys = range(0, count($data) - 1);
if ($keys !== $expectedKeys) {
return false;
}
// Check if all values are scalar
foreach ($data as $value) {
if (!is_scalar($value) && !is_null($value)) {
return false;
}
}
return true;
}
private function simpleListToText(array $data, string $indent): string
{
$lines = [];
foreach ($data as $index => $value) {
$formattedValue = $this->formatScalarValue($value);
$lines[] = "{$indent}- {$formattedValue}";
}
return implode("\n", $lines) . "\n";
}
private function formatKey(string|int $key): string
{
if (is_numeric($key)) {
return "Item {$key}";
}
// Convert snake_case or camelCase to readable format
$formatted = str_replace(['_', '-'], ' ', (string) $key);
$formatted = preg_replace('/([a-z])([A-Z])/', '$1 $2', $formatted);
return ucwords($formatted);
}
private function formatScalarValue(mixed $value): string
{
return match (true) {
is_null($value) => '(null)',
is_bool($value) => $value ? 'Yes' : 'No',
is_string($value) => empty($value) ? '(empty)' : $value,
is_numeric($value) => (string) $value,
default => (string) $value
};
}
}