- Fix RedisCache driver to handle MGET failures gracefully with fallback - Add comprehensive discovery context comparison debug tools - Identify root cause: WEB context discovery missing 166 items vs CLI - WEB context missing RequestFactory class entirely (52 vs 69 commands) - Improved exception handling with detailed binding diagnostics
383 lines
12 KiB
PHP
383 lines
12 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Application\Controller;
|
|
|
|
use App\Framework\Attributes\Route;
|
|
use App\Framework\Http\Headers;
|
|
use App\Framework\Http\HttpRequest;
|
|
use App\Framework\Http\HttpResponse;
|
|
use App\Framework\Http\Method;
|
|
use App\Framework\Http\Status;
|
|
use App\Framework\QrCode\ErrorCorrectionLevel;
|
|
use App\Framework\QrCode\QrCodeGenerator;
|
|
use App\Framework\QrCode\QrCodeVersion;
|
|
use App\Framework\Router\Result\HtmlResult;
|
|
|
|
/**
|
|
* QR Code Test Controller
|
|
*
|
|
* Displays example QR codes for testing purposes in development
|
|
*/
|
|
final readonly class QrCodeTestController
|
|
{
|
|
public function __construct(
|
|
private QrCodeGenerator $qrCodeGenerator
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Show QR code test page with multiple examples
|
|
*/
|
|
#[Route(path: '/test/qr-codes', method: Method::GET)]
|
|
public function showTestPage(HttpRequest $request): HtmlResult
|
|
{
|
|
// Generate various test QR codes
|
|
$examples = [
|
|
[
|
|
'title' => 'Simple Text',
|
|
'data' => 'Hello, World!',
|
|
'description' => 'Basic text QR code (Version 1)',
|
|
'version' => null,
|
|
'errorLevel' => null,
|
|
],
|
|
[
|
|
'title' => 'URL Example',
|
|
'data' => 'https://example.com/test?param=value',
|
|
'description' => 'Website URL QR code',
|
|
'version' => null,
|
|
'errorLevel' => ErrorCorrectionLevel::M,
|
|
],
|
|
[
|
|
'title' => 'TOTP Example',
|
|
'data' => 'otpauth://totp/TestApp:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestApp&algorithm=SHA1&digits=6&period=30',
|
|
'description' => 'TOTP authenticator setup (Version 3)',
|
|
'version' => QrCodeVersion::forTotp(),
|
|
'errorLevel' => ErrorCorrectionLevel::M,
|
|
],
|
|
[
|
|
'title' => 'WiFi Connection',
|
|
'data' => 'WIFI:T:WPA;S:TestNetwork;P:password123;H:false;;',
|
|
'description' => 'WiFi connection QR code',
|
|
'version' => null,
|
|
'errorLevel' => ErrorCorrectionLevel::L,
|
|
],
|
|
[
|
|
'title' => 'Contact Card',
|
|
'data' => 'BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nTEL:+49123456789\nEMAIL:john@example.com\nEND:VCARD',
|
|
'description' => 'vCard contact information',
|
|
'version' => null,
|
|
'errorLevel' => ErrorCorrectionLevel::M,
|
|
],
|
|
];
|
|
|
|
$qrCodes = [];
|
|
|
|
foreach ($examples as $example) {
|
|
try {
|
|
// Generate SVG
|
|
$svg = $this->qrCodeGenerator->generateSvg(
|
|
$example['data'],
|
|
$example['errorLevel'],
|
|
$example['version']
|
|
);
|
|
|
|
// Generate data URI
|
|
$dataUri = $this->qrCodeGenerator->generateDataUri(
|
|
$example['data'],
|
|
$example['errorLevel'],
|
|
$example['version']
|
|
);
|
|
|
|
// Analyze the data
|
|
$analysis = $this->qrCodeGenerator->analyzeData($example['data']);
|
|
|
|
$qrCodes[] = [
|
|
'title' => $example['title'],
|
|
'description' => $example['description'],
|
|
'data' => $example['data'],
|
|
'svg' => $svg,
|
|
'dataUri' => $dataUri,
|
|
'analysis' => $analysis,
|
|
'success' => true,
|
|
];
|
|
} catch (\Exception $e) {
|
|
$qrCodes[] = [
|
|
'title' => $example['title'],
|
|
'description' => $example['description'],
|
|
'data' => $example['data'],
|
|
'error' => $e->getMessage(),
|
|
'success' => false,
|
|
];
|
|
}
|
|
}
|
|
|
|
$html = $this->generateTestPageHtml($qrCodes);
|
|
|
|
return new HtmlResult($html);
|
|
}
|
|
|
|
/**
|
|
* Generate individual QR code for API testing
|
|
*/
|
|
#[Route(path: '/test/qr-code', method: Method::GET)]
|
|
public function generateTestQrCode(HttpRequest $request): HtmlResult|HttpResponse
|
|
{
|
|
$data = (string) $request->query->get('data', 'Test QR Code from API');
|
|
$format = $request->query->get('format', 'svg'); // svg or datauri
|
|
$errorLevel = $request->query->get('error', 'M');
|
|
$version = $request->query->get('version');
|
|
|
|
try {
|
|
// Parse error correction level
|
|
$errorCorrectionLevel = match($errorLevel) {
|
|
'L' => ErrorCorrectionLevel::L,
|
|
'Q' => ErrorCorrectionLevel::Q,
|
|
'H' => ErrorCorrectionLevel::H,
|
|
default => ErrorCorrectionLevel::M,
|
|
};
|
|
|
|
// Parse version if provided
|
|
$qrVersion = $version ? new QrCodeVersion((int) $version) : null;
|
|
|
|
if ($format === 'datauri') {
|
|
$result = $this->qrCodeGenerator->generateDataUri($data, $errorCorrectionLevel, $qrVersion);
|
|
|
|
return new HtmlResult("<img src=\"{$result}\" alt=\"QR Code\" style=\"max-width: 100%;\"/>");
|
|
} else {
|
|
$svg = $this->qrCodeGenerator->generateSvg($data, $errorCorrectionLevel, $qrVersion);
|
|
|
|
return new HttpResponse(
|
|
Status::OK,
|
|
new Headers(['Content-Type' => 'image/svg+xml']),
|
|
$svg
|
|
);
|
|
}
|
|
} catch (\Exception $e) {
|
|
return new HtmlResult(
|
|
"<h1>QR Code Generation Error</h1><p>{$e->getMessage()}</p>",
|
|
Status::INTERNAL_SERVER_ERROR
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate test page HTML
|
|
* @param array<int, array<string, mixed>> $qrCodes
|
|
*/
|
|
private function generateTestPageHtml(array $qrCodes): string
|
|
{
|
|
$examples = '';
|
|
|
|
foreach ($qrCodes as $qrCode) {
|
|
if ($qrCode['success']) {
|
|
$analysis = $qrCode['analysis'];
|
|
$analysisHtml = '';
|
|
foreach ($analysis as $key => $value) {
|
|
$displayValue = is_object($value) ? basename(str_replace('\\', '/', get_class($value))) : $value;
|
|
$analysisHtml .= "<tr><td>{$key}</td><td>{$displayValue}</td></tr>";
|
|
}
|
|
|
|
$examples .= "
|
|
<div class=\"qr-example\">
|
|
<h3>{$qrCode['title']}</h3>
|
|
<p class=\"description\">{$qrCode['description']}</p>
|
|
|
|
<div class=\"qr-container\">
|
|
<div class=\"qr-code\">
|
|
<img src=\"{$qrCode['dataUri']}\" alt=\"{$qrCode['title']} QR Code\" />
|
|
</div>
|
|
|
|
<div class=\"qr-info\">
|
|
<h4>Data:</h4>
|
|
<pre class=\"data\">" . htmlspecialchars($qrCode['data']) . "</pre>
|
|
|
|
<h4>Analysis:</h4>
|
|
<table class=\"analysis\">
|
|
{$analysisHtml}
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>";
|
|
} else {
|
|
$examples .= "
|
|
<div class=\"qr-example error\">
|
|
<h3>{$qrCode['title']} - ERROR</h3>
|
|
<p class=\"description\">{$qrCode['description']}</p>
|
|
<p class=\"error-message\">Error: {$qrCode['error']}</p>
|
|
<pre class=\"data\">" . htmlspecialchars($qrCode['data']) . "</pre>
|
|
</div>";
|
|
}
|
|
}
|
|
|
|
return "
|
|
<!DOCTYPE html>
|
|
<html lang=\"de\">
|
|
<head>
|
|
<meta charset=\"UTF-8\">
|
|
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
|
|
<title>QR Code Test Page</title>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
line-height: 1.6;
|
|
background: #f5f5f5;
|
|
}
|
|
|
|
h1 {
|
|
color: #333;
|
|
text-align: center;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.api-info {
|
|
background: #e3f2fd;
|
|
border: 1px solid #2196f3;
|
|
border-radius: 4px;
|
|
padding: 15px;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.api-info h3 {
|
|
margin-top: 0;
|
|
color: #1976d2;
|
|
}
|
|
|
|
.api-info code {
|
|
background: #fff;
|
|
padding: 2px 6px;
|
|
border-radius: 3px;
|
|
font-family: Monaco, Consolas, monospace;
|
|
}
|
|
|
|
.qr-example {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin-bottom: 2rem;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.qr-example.error {
|
|
border-left: 4px solid #f44336;
|
|
background: #ffebee;
|
|
}
|
|
|
|
.qr-example h3 {
|
|
margin-top: 0;
|
|
color: #333;
|
|
}
|
|
|
|
.description {
|
|
color: #666;
|
|
font-style: italic;
|
|
}
|
|
|
|
.error-message {
|
|
color: #d32f2f;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.qr-container {
|
|
display: flex;
|
|
gap: 20px;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.qr-code {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.qr-code img {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
max-width: 200px;
|
|
}
|
|
|
|
.qr-info {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.qr-info h4 {
|
|
margin: 1rem 0 0.5rem 0;
|
|
color: #555;
|
|
}
|
|
|
|
.data {
|
|
background: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 4px;
|
|
padding: 10px;
|
|
font-family: Monaco, Consolas, monospace;
|
|
font-size: 12px;
|
|
overflow-x: auto;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.analysis {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.analysis td {
|
|
padding: 4px 8px;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
|
|
.analysis td:first-child {
|
|
font-weight: bold;
|
|
color: #666;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.qr-container {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.qr-code img {
|
|
max-width: 150px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>🧪 QR Code Test Page</h1>
|
|
|
|
<div class=\"api-info\">
|
|
<h3>📡 API Endpoints</h3>
|
|
<p><strong>Dynamic QR Code Generation:</strong><br>
|
|
<code>GET /test/qr-code?data=Your+Data&format=svg&error=M&version=3</code></p>
|
|
|
|
<p><strong>Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>data</code> - Text to encode (URL encoded)</li>
|
|
<li><code>format</code> - Output format: <code>svg</code> (default) or <code>datauri</code></li>
|
|
<li><code>error</code> - Error correction: <code>L</code>, <code>M</code> (default), <code>Q</code>, <code>H</code></li>
|
|
<li><code>version</code> - QR version 1-40 (auto-detect if omitted)</li>
|
|
</ul>
|
|
|
|
<p><strong>Examples:</strong><br>
|
|
<code>/test/qr-code?data=Hello+World</code><br>
|
|
<code>/test/qr-code?data=https://example.com&error=H</code><br>
|
|
<code>/test/qr-code?data=Test&format=datauri&version=2</code></p>
|
|
</div>
|
|
|
|
{$examples}
|
|
|
|
<div style=\"text-align: center; margin-top: 3rem; color: #666; font-size: 14px;\">
|
|
<p>✅ QR Code Framework Module - Fully Functional</p>
|
|
<p>Generated by Custom PHP Framework QR Code Generator</p>
|
|
</div>
|
|
</body>
|
|
</html>";
|
|
}
|
|
}
|