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:
130
src/Application/Http/BatchController.php
Normal file
130
src/Application/Http/BatchController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Application\Http;
|
||||
|
||||
use App\Framework\Attributes\Route;
|
||||
use App\Framework\Exception\FrameworkException;
|
||||
use App\Framework\Http\Batch\BatchProcessor;
|
||||
use App\Framework\Http\Batch\BatchRequest;
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\HttpResponse;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\Request;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Serialization\JsonSerializer;
|
||||
use App\Framework\Serialization\JsonSerializerConfig;
|
||||
|
||||
/**
|
||||
* Controller for handling batch API requests
|
||||
*/
|
||||
final readonly class BatchController
|
||||
{
|
||||
public function __construct(
|
||||
private BatchProcessor $batchProcessor,
|
||||
private JsonSerializer $jsonSerializer
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route(path: '/api/batch', method: Method::POST)]
|
||||
public function processBatch(Request $request): HttpResponse
|
||||
{
|
||||
try {
|
||||
// Validate content type
|
||||
$contentType = $request->headers->getFirst('Content-Type', '');
|
||||
if (! str_contains($contentType, 'application/json')) {
|
||||
return $this->errorResponse(
|
||||
'Content-Type must be application/json',
|
||||
Status::BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
// Parse batch request
|
||||
$batchData = $this->jsonSerializer->deserialize($request->body);
|
||||
if (! is_array($batchData)) {
|
||||
return $this->errorResponse(
|
||||
'Invalid JSON structure',
|
||||
Status::BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
$batchRequest = BatchRequest::fromArray($batchData);
|
||||
|
||||
// Process batch operations
|
||||
$responses = $this->batchProcessor->process($batchRequest);
|
||||
|
||||
// Return batch responses
|
||||
$responseData = [
|
||||
'responses' => array_map(fn ($response) => $response->toArray(), $responses),
|
||||
'total' => count($responses),
|
||||
'successful' => count(array_filter($responses, fn ($r) => $r->error === null)),
|
||||
'failed' => count(array_filter($responses, fn ($r) => $r->error !== null)),
|
||||
];
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize(
|
||||
$responseData,
|
||||
JsonSerializerConfig::pretty()
|
||||
)
|
||||
);
|
||||
|
||||
} catch (FrameworkException $e) {
|
||||
return $this->errorResponse($e->getMessage(), Status::BAD_REQUEST);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->errorResponse(
|
||||
'Internal server error',
|
||||
Status::INTERNAL_SERVER_ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route(path: '/api/batch/info', method: Method::GET)]
|
||||
public function getBatchInfo(Request $request): HttpResponse
|
||||
{
|
||||
$info = [
|
||||
'max_operations' => 100,
|
||||
'max_concurrent_operations' => 10,
|
||||
'supported_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
||||
'continue_on_error_supported' => true,
|
||||
'example_request' => [
|
||||
'operations' => [
|
||||
[
|
||||
'id' => 'get-user-1',
|
||||
'method' => 'GET',
|
||||
'path' => '/api/users/1',
|
||||
'headers' => ['Authorization' => 'Bearer token'],
|
||||
],
|
||||
[
|
||||
'id' => 'create-post',
|
||||
'method' => 'POST',
|
||||
'path' => '/api/posts',
|
||||
'headers' => ['Content-Type' => 'application/json'],
|
||||
'body' => '{"title": "Test Post", "content": "Hello World"}',
|
||||
],
|
||||
],
|
||||
'continue_on_error' => false,
|
||||
],
|
||||
];
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize(
|
||||
$info,
|
||||
JsonSerializerConfig::pretty()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function errorResponse(string $message, Status $status): HttpResponse
|
||||
{
|
||||
return new HttpResponse(
|
||||
status: $status,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize(['error' => $message])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Application\Http\Controllers;
|
||||
@@ -11,6 +12,7 @@ use App\Framework\Router\Result\WebSocketResult;
|
||||
|
||||
final class ChatController
|
||||
{
|
||||
/** @var array<string, WebSocketConnection> */
|
||||
private array $connections = [];
|
||||
|
||||
#[Auth]
|
||||
@@ -18,53 +20,56 @@ final class ChatController
|
||||
public function chatWebSocket(): WebSocketResult
|
||||
{
|
||||
return new WebSocketResult()
|
||||
->onConnect(function(WebSocketConnection $connection) {
|
||||
->onConnect(function (WebSocketConnection $connection) {
|
||||
$this->connections[$connection->getId()] = $connection;
|
||||
|
||||
// Willkommensnachricht senden
|
||||
$connection->sendJson([
|
||||
'type' => 'system',
|
||||
'message' => 'Willkommen im Chat!',
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
]);
|
||||
|
||||
// Andere Benutzer benachrichtigen
|
||||
$this->broadcast([
|
||||
'type' => 'user_joined',
|
||||
'message' => 'Ein neuer Benutzer ist dem Chat beigetreten',
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
], $connection->getId());
|
||||
})
|
||||
->onMessage(function(WebSocketConnection $connection, string $message) {
|
||||
->onMessage(function (WebSocketConnection $connection, string $message) {
|
||||
$data = json_decode($message, true);
|
||||
|
||||
if (!$data || !isset($data['type'])) {
|
||||
if (! $data || ! isset($data['type'])) {
|
||||
$connection->sendJson(['error' => 'Invalid message format']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($data['type']) {
|
||||
case 'chat_message':
|
||||
$this->handleChatMessage($connection, $data);
|
||||
|
||||
break;
|
||||
case 'ping':
|
||||
$connection->sendJson(['type' => 'pong']);
|
||||
|
||||
break;
|
||||
default:
|
||||
$connection->sendJson(['error' => 'Unknown message type']);
|
||||
}
|
||||
})
|
||||
->onClose(function(WebSocketConnection $connection, int $code, string $reason) {
|
||||
->onClose(function (WebSocketConnection $connection, int $code, string $reason) {
|
||||
unset($this->connections[$connection->getId()]);
|
||||
|
||||
// Andere Benutzer benachrichtigen
|
||||
$this->broadcast([
|
||||
'type' => 'user_left',
|
||||
'message' => 'Ein Benutzer hat den Chat verlassen',
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
]);
|
||||
})
|
||||
->onError(function(WebSocketConnection $connection, \Throwable $error) {
|
||||
->onError(function (WebSocketConnection $connection, \Throwable $error) {
|
||||
error_log("WebSocket error: " . $error->getMessage());
|
||||
$connection->close(1011, 'Internal server error');
|
||||
})
|
||||
@@ -75,8 +80,9 @@ final class ChatController
|
||||
|
||||
private function handleChatMessage(WebSocketConnection $sender, array $data): void
|
||||
{
|
||||
if (!isset($data['message'])) {
|
||||
if (! isset($data['message'])) {
|
||||
$sender->sendJson(['error' => 'Message content required']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -84,7 +90,7 @@ final class ChatController
|
||||
'type' => 'chat_message',
|
||||
'user_id' => $sender->getId(),
|
||||
'message' => $data['message'],
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
];
|
||||
|
||||
// Nachricht an alle Verbindungen senden
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Application\Http\Controllers;
|
||||
|
||||
use App\Framework\Attributes\Route;
|
||||
use App\Framework\Auth\Auth;
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\Timer;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\SseStream;
|
||||
use App\Framework\Http\Status;
|
||||
@@ -16,6 +19,11 @@ use App\Framework\Router\Result\SseResultWithCallback;
|
||||
*/
|
||||
final class NotificationController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Timer $timer
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stellt einen SSE-Stream für allgemeine Benachrichtigungen bereit
|
||||
*/
|
||||
@@ -39,7 +47,7 @@ final class NotificationController
|
||||
'type' => 'info',
|
||||
'title' => 'Willkommen',
|
||||
'message' => 'Sie sind jetzt mit Echtzeit-Updates verbunden.',
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
],
|
||||
'notification',
|
||||
'notif-' . uniqid()
|
||||
@@ -57,7 +65,7 @@ final class NotificationController
|
||||
{
|
||||
// SSE-Result mit benutzerdefinierten Headern
|
||||
$result = new SseResult(Status::OK, 3000, [
|
||||
'X-User-ID' => (string)$userId
|
||||
'X-User-ID' => (string)$userId,
|
||||
]);
|
||||
|
||||
// Verbindungsbestätigung mit Benutzer-ID
|
||||
@@ -65,7 +73,7 @@ final class NotificationController
|
||||
[
|
||||
'message' => 'Verbunden mit dem Benutzer-Stream',
|
||||
'userId' => $userId,
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
],
|
||||
'connected',
|
||||
'conn-user-' . $userId
|
||||
@@ -95,15 +103,15 @@ final class NotificationController
|
||||
'type' => 'message',
|
||||
'title' => 'Neue Nachricht',
|
||||
'message' => 'Sie haben eine neue Nachricht erhalten',
|
||||
'timestamp' => time() - 300 // Vor 5 Minuten
|
||||
'timestamp' => time() - 300, // Vor 5 Minuten
|
||||
],
|
||||
[
|
||||
'id' => 'notif-' . uniqid(),
|
||||
'type' => 'system',
|
||||
'title' => 'System-Update',
|
||||
'message' => 'Das System wurde aktualisiert',
|
||||
'timestamp' => time() - 3600 // Vor 1 Stunde
|
||||
]
|
||||
'timestamp' => time() - 3600, // Vor 1 Stunde
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -118,7 +126,7 @@ final class NotificationController
|
||||
#$result = new SseResultWithCallback(Status::OK, 3000);
|
||||
|
||||
// Callback für dynamische Updates festlegen
|
||||
$callback = function(SseStream $stream) {
|
||||
$callback = function (SseStream $stream) {
|
||||
// Simuliere neue Benachrichtigungen (mit 10% Wahrscheinlichkeit)
|
||||
if (rand(1, 10) === 1) {
|
||||
$notificationTypes = ['info', 'warning', 'update', 'message'];
|
||||
@@ -129,13 +137,13 @@ final class NotificationController
|
||||
'type' => $type,
|
||||
'title' => 'Neue ' . ucfirst($type) . '-Benachrichtigung',
|
||||
'message' => 'Dies ist eine dynamisch generierte Benachrichtigung vom Typ ' . $type,
|
||||
'timestamp' => time()
|
||||
'timestamp' => time(),
|
||||
];
|
||||
|
||||
$stream->sendJson($notification, 'notification', $notification['id']);
|
||||
|
||||
// Kleine Pause nach dem Senden, um das Testszenario zu simulieren
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4,92 +4,150 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Application\Http\Controllers;
|
||||
|
||||
use App\Application\Service\QrCodeService;
|
||||
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
|
||||
use App\Framework\Attributes\Route;
|
||||
use App\Framework\Auth\Auth;
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\HttpResponse;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Responses\JsonResponse;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\QrCode\ErrorCorrectionLevel;
|
||||
use App\Framework\QrCode\QrCodeGenerator;
|
||||
use App\Framework\QrCode\QrCodeVersion;
|
||||
|
||||
final class QrCodeController
|
||||
/**
|
||||
* QR Code API Controller
|
||||
*
|
||||
* Provides API endpoints for QR code generation using the Framework QrCode module
|
||||
*/
|
||||
final readonly class QrCodeController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly QrCodeService $qrCodeService
|
||||
private QrCodeGenerator $qrCodeGenerator
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert einen QR-Code als SVG
|
||||
* Generate QR code as SVG
|
||||
*/
|
||||
#[Auth]
|
||||
#[Route(path: '/api/qrcode/svg', method: Method::GET)]
|
||||
public function generateSvg(): Response
|
||||
{
|
||||
$data = $_GET['data'] ?? 'https://example.com';
|
||||
$errorLevel = $this->getErrorLevel($_GET['error_level'] ?? 'M');
|
||||
$moduleSize = (int) ($_GET['module_size'] ?? 4);
|
||||
$margin = (int) ($_GET['margin'] ?? 4);
|
||||
$foreground = $_GET['foreground'] ?? '#000000';
|
||||
$background = $_GET['background'] ?? '#FFFFFF';
|
||||
$errorLevel = $this->parseErrorLevel($_GET['error'] ?? 'M');
|
||||
$version = $_GET['version'] ?? null;
|
||||
|
||||
$config = new QrCodeConfig($moduleSize, $margin, $foreground, $background);
|
||||
try {
|
||||
$qrVersion = $version ? new QrCodeVersion((int) $version) : null;
|
||||
|
||||
$svg = $this->qrCodeService->generateSvg($data, $errorLevel, $config);
|
||||
$svg = $this->qrCodeGenerator->generateSvg($data, $errorLevel, $qrVersion);
|
||||
|
||||
return new Response(
|
||||
body: $svg,
|
||||
status: Status::OK,
|
||||
headers: ['Content-Type' => 'image/svg+xml']
|
||||
);
|
||||
return new HttpResponse(
|
||||
status : Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'image/svg+xml']),
|
||||
body : $svg
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse(
|
||||
body : ['error' => $e->getMessage()],
|
||||
status: Status::BAD_REQUEST
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert einen QR-Code als PNG
|
||||
* Generate QR code as Data URI (base64 encoded SVG)
|
||||
*/
|
||||
#[Auth]
|
||||
#[Route(path: '/api/qrcode/png', method: Method::GET)]
|
||||
public function generatePng(): Response
|
||||
#[Route(path: '/api/qrcode/datauri', method: Method::GET)]
|
||||
public function generateDataUri(): Response
|
||||
{
|
||||
$data = $_GET['data'] ?? 'https://example.com';
|
||||
$errorLevel = $this->getErrorLevel($_GET['error_level'] ?? 'M');
|
||||
$moduleSize = (int) ($_GET['module_size'] ?? 4);
|
||||
$margin = (int) ($_GET['margin'] ?? 4);
|
||||
$errorLevel = $this->parseErrorLevel($_GET['error'] ?? 'M');
|
||||
$version = $_GET['version'] ?? null;
|
||||
|
||||
$config = new QrCodeConfig($moduleSize, $margin);
|
||||
try {
|
||||
$qrVersion = $version ? new QrCodeVersion((int) $version) : null;
|
||||
|
||||
$png = $this->qrCodeService->generatePng($data, $errorLevel, $config);
|
||||
$dataUri = $this->qrCodeGenerator->generateDataUri($data, $errorLevel, $qrVersion);
|
||||
|
||||
return new Response(
|
||||
body: $png,
|
||||
status: Status::OK,
|
||||
headers: ['Content-Type' => 'image/png']
|
||||
);
|
||||
return new JsonResponse(
|
||||
body : ['dataUri' => $dataUri]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse(
|
||||
body : ['error' => $e->getMessage()],
|
||||
status: Status::BAD_REQUEST
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert einen QR-Code als ASCII-Art
|
||||
* Analyze data and get QR code recommendations
|
||||
*/
|
||||
#[Auth]
|
||||
#[Route(path: '/api/qrcode/ascii', method: Method::GET)]
|
||||
public function generateAscii(): Response
|
||||
#[Route(path: '/api/qrcode/analyze', method: Method::GET)]
|
||||
public function analyzeData(): Response
|
||||
{
|
||||
$data = $_GET['data'] ?? 'https://example.com';
|
||||
$errorLevel = $this->getErrorLevel($_GET['error_level'] ?? 'M');
|
||||
$data = $_GET['data'] ?? null;
|
||||
|
||||
$ascii = $this->qrCodeService->generateAscii($data, $errorLevel);
|
||||
if (empty($data)) {
|
||||
return new JsonResponse(
|
||||
body : ['error' => 'Data parameter is required'],
|
||||
status: Status::BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
return new Response(
|
||||
body: "<pre>$ascii</pre>",
|
||||
status: Status::OK,
|
||||
headers: ['Content-Type' => 'text/html; charset=utf-8']
|
||||
);
|
||||
try {
|
||||
$analysis = $this->qrCodeGenerator->analyzeData($data);
|
||||
|
||||
return new JsonResponse(
|
||||
body : $analysis,
|
||||
status: Status::OK
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse(
|
||||
body : ['error' => $e->getMessage()],
|
||||
status: Status::BAD_REQUEST
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Konvertiert einen String in ein ErrorCorrectionLevel-Enum
|
||||
* Generate TOTP QR code specifically optimized for authenticator apps
|
||||
*/
|
||||
private function getErrorLevel(string $level): ErrorCorrectionLevel
|
||||
#[Route(path: '/api/qrcode/totp', method: Method::GET)]
|
||||
public function generateTotpQrCode(): HttpResponse
|
||||
{
|
||||
$totpUri = $_GET['uri'] ?? null;
|
||||
|
||||
if (empty($totpUri)) {
|
||||
return new HttpResponse(
|
||||
status : Status::BAD_REQUEST,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body : json_encode(['error' => 'TOTP URI parameter is required'])
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$svg = $this->qrCodeGenerator->generateTotpQrCode($totpUri);
|
||||
|
||||
return new HttpResponse(
|
||||
status : Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'image/svg+xml']),
|
||||
body : $svg
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return new HttpResponse(
|
||||
status : Status::BAD_REQUEST,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body : json_encode(['error' => $e->getMessage()])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse error correction level from string
|
||||
*/
|
||||
private function parseErrorLevel(string $level): ErrorCorrectionLevel
|
||||
{
|
||||
return match (strtoupper($level)) {
|
||||
'L' => ErrorCorrectionLevel::L,
|
||||
|
||||
131
src/Application/Http/Examples/BatchExampleController.php
Normal file
131
src/Application/Http/Examples/BatchExampleController.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Application\Http\Examples;
|
||||
|
||||
use App\Framework\Attributes\Route;
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\HttpResponse;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\Request;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Serialization\JsonSerializer;
|
||||
use App\Framework\Serialization\JsonSerializerConfig;
|
||||
|
||||
/**
|
||||
* Example controller for demonstrating batch API functionality
|
||||
*/
|
||||
final readonly class BatchExampleController
|
||||
{
|
||||
public function __construct(
|
||||
private JsonSerializer $jsonSerializer
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route(path: '/api/examples/users/{id}', method: Method::GET)]
|
||||
public function getUser(Request $request): HttpResponse
|
||||
{
|
||||
$userId = $request->queryParams['id'] ?? '1';
|
||||
|
||||
$user = [
|
||||
'id' => (int) $userId,
|
||||
'name' => "User {$userId}",
|
||||
'email' => "user{$userId}@example.com",
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize($user, JsonSerializerConfig::pretty())
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(path: '/api/examples/posts', method: Method::POST)]
|
||||
public function createPost(Request $request): HttpResponse
|
||||
{
|
||||
$data = $this->jsonSerializer->deserialize($request->body);
|
||||
|
||||
if (! is_array($data) || empty($data['title'])) {
|
||||
return new HttpResponse(
|
||||
status: Status::BAD_REQUEST,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize(['error' => 'Title is required'])
|
||||
);
|
||||
}
|
||||
|
||||
$post = [
|
||||
'id' => random_int(1000, 9999),
|
||||
'title' => $data['title'],
|
||||
'content' => $data['content'] ?? '',
|
||||
'author_id' => $data['author_id'] ?? 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::CREATED,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize($post, JsonSerializerConfig::pretty())
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(path: '/api/examples/posts/{id}', method: Method::PUT)]
|
||||
public function updatePost(Request $request): HttpResponse
|
||||
{
|
||||
$postId = $request->queryParams['id'] ?? '1';
|
||||
$data = $this->jsonSerializer->deserialize($request->body);
|
||||
|
||||
if (! is_array($data)) {
|
||||
return new HttpResponse(
|
||||
status: Status::BAD_REQUEST,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize(['error' => 'Invalid JSON data'])
|
||||
);
|
||||
}
|
||||
|
||||
$post = [
|
||||
'id' => (int) $postId,
|
||||
'title' => $data['title'] ?? "Post {$postId}",
|
||||
'content' => $data['content'] ?? '',
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize($post, JsonSerializerConfig::pretty())
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(path: '/api/examples/posts/{id}', method: Method::DELETE)]
|
||||
public function deletePost(Request $request): HttpResponse
|
||||
{
|
||||
$postId = $request->queryParams['id'] ?? '1';
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::NO_CONTENT,
|
||||
headers: new Headers([]),
|
||||
body: ''
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(path: '/api/examples/slow', method: Method::GET)]
|
||||
public function slowEndpoint(Request $request): HttpResponse
|
||||
{
|
||||
// Simulate slow operation for testing concurrent processing
|
||||
$delay = (int) ($request->queryParams['delay'] ?? 1);
|
||||
$maxDelay = min($delay, 5); // Maximum 5 seconds
|
||||
sleep($maxDelay);
|
||||
|
||||
return new HttpResponse(
|
||||
status: Status::OK,
|
||||
headers: new Headers(['Content-Type' => 'application/json']),
|
||||
body: $this->jsonSerializer->serialize([
|
||||
'message' => 'Slow operation completed',
|
||||
'delay' => $maxDelay,
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Application\Http;
|
||||
|
||||
use App\Framework\Attributes\Route;
|
||||
use App\Framework\CommandBus\CommandBus;
|
||||
use App\Framework\Http\HeaderKey;
|
||||
use App\Framework\Http\Request;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\Request;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Router\ActionResult;
|
||||
use App\Framework\Router\Result\ViewResult;
|
||||
use App\Framework\Router\Result\Redirect;
|
||||
use App\Framework\Meta\MetaData;
|
||||
use App\Framework\Router\ActionResult;
|
||||
use App\Framework\Router\Result\Redirect;
|
||||
use App\Framework\Router\Result\ViewResult;
|
||||
use App\Framework\Smartlinks\Actions\ActionRegistry;
|
||||
use App\Framework\Smartlinks\Commands\ExecuteSmartlinkCommand;
|
||||
use App\Framework\Smartlinks\Commands\GenerateSmartlinkCommand;
|
||||
@@ -27,7 +29,8 @@ final readonly class Smartlink
|
||||
private ActionRegistry $actionRegistry,
|
||||
private SmartlinkService $smartlinkService,
|
||||
private GenerateSmartlinkHandler $handler,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/smartlink/{token}', method: Method::GET)]
|
||||
#[Route('/smartlink/{token}', method: Method::POST)]
|
||||
@@ -46,7 +49,7 @@ final readonly class Smartlink
|
||||
|
||||
// Token validieren
|
||||
$smartlinkData = $this->smartlinkService->validate($smartlinkToken);
|
||||
if (!$smartlinkData) {
|
||||
if (! $smartlinkData) {
|
||||
return new ViewResult(
|
||||
template: 'smartlinks-error',
|
||||
metaData: new MetaData(
|
||||
@@ -55,7 +58,7 @@ final readonly class Smartlink
|
||||
),
|
||||
data: [
|
||||
'error' => 'Ungültiger oder abgelaufener Link',
|
||||
'error_code' => 'INVALID_TOKEN'
|
||||
'error_code' => 'INVALID_TOKEN',
|
||||
],
|
||||
status: Status::NOT_FOUND
|
||||
);
|
||||
@@ -63,7 +66,7 @@ final readonly class Smartlink
|
||||
|
||||
// Action holen
|
||||
$action = $this->actionRegistry->get($smartlinkData->action);
|
||||
if (!$action) {
|
||||
if (! $action) {
|
||||
return new ViewResult(
|
||||
template: 'smartlinks-error',
|
||||
metaData: new MetaData(
|
||||
@@ -72,7 +75,7 @@ final readonly class Smartlink
|
||||
),
|
||||
data: [
|
||||
'error' => 'Unbekannte Aktion',
|
||||
'error_code' => 'UNKNOWN_ACTION'
|
||||
'error_code' => 'UNKNOWN_ACTION',
|
||||
],
|
||||
status: Status::BAD_REQUEST
|
||||
);
|
||||
@@ -85,7 +88,7 @@ final readonly class Smartlink
|
||||
'query_params' => $request->queryParameters ?? [],
|
||||
#'ip_address' => $request->serverEnvironment->ipAddress?->value,
|
||||
'user_agent' => $request->headers->getFirst(HeaderKey::USER_AGENT),
|
||||
'headers' => $request->headers
|
||||
'headers' => $request->headers,
|
||||
];
|
||||
|
||||
// Command ausführen
|
||||
@@ -93,7 +96,7 @@ final readonly class Smartlink
|
||||
$result = $this->commandBus->dispatch($command);
|
||||
|
||||
// Ergebnis verarbeiten
|
||||
if (!$result->isSuccess()) {
|
||||
if (! $result->isSuccess()) {
|
||||
return new ViewResult(
|
||||
template: $action->getErrorTemplate(),
|
||||
metaData: new MetaData(
|
||||
@@ -103,7 +106,7 @@ final readonly class Smartlink
|
||||
data: [
|
||||
'error' => $result->message,
|
||||
'errors' => $result->errors,
|
||||
'action' => $action->getName()
|
||||
'action' => $action->getName(),
|
||||
],
|
||||
status: Status::BAD_REQUEST
|
||||
);
|
||||
@@ -123,7 +126,7 @@ final readonly class Smartlink
|
||||
data: [
|
||||
'result' => $result,
|
||||
'action' => $action->getName(),
|
||||
'token' => $token
|
||||
'token' => $token,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -137,7 +140,7 @@ final readonly class Smartlink
|
||||
data: [
|
||||
'error' => 'Ein Fehler ist aufgetreten',
|
||||
'error_code' => 'SYSTEM_ERROR',
|
||||
'debug_message' => $e->getMessage() // Nur für Development
|
||||
'debug_message' => $e->getMessage(), // Nur für Development
|
||||
],
|
||||
status: Status::INTERNAL_SERVER_ERROR
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user