Files
FDMTech/app/View.php
T

108 lines
5.9 KiB
PHP

<?php
declare(strict_types=1);
namespace FDMTech;
final class View
{
public function __construct(private string $root) {}
public static function escape(mixed $value): string
{
return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
public function render(array $data, ?string $applicationHtml = null): string
{
$e = self::escape(...);
extract($data, EXTR_SKIP);
$cmsHtml = Content::html((string) ($page['published_html'] ?? ''));
$css = Content::css((string) ($page['published_css'] ?? ''));
$cmsStyleTag = $css === '' ? '' : '<style nonce="' . $e($nonce) . '">' . $css . '</style>';
if ($applicationHtml !== null) {
$inner = $applicationHtml;
} elseif ($isDemo && $page['slug'] === 'home' && is_file($this->root . '/templates/home.php')) {
ob_start();
try {
require $this->root . '/templates/home.php';
$inner = ob_get_contents();
} finally {
ob_end_clean();
}
} else {
$inner = $cmsHtml;
}
$content = '<main id="cms-content">' . $inner . '</main>';
if ($isDemo) {
$content = '<aside role="note">Tryb demonstracyjny — formularz nie wysyła zgłoszeń.</aside>' . $content;
}
if (is_file($this->root . '/templates/layout.php')) {
ob_start();
try {
require $this->root . '/templates/layout.php';
return ob_get_contents();
} finally {
ob_end_clean();
}
}
// Technical fallback while the independent designer supplies the layout.
$navigation = '';
foreach ($site['navigation'] as $item) {
$navigation .= '<a href="' . $e($item['url']) . '">' . $e($item['label']) . '</a> ';
}
return '<!doctype html><html lang="pl"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">'
. '<title>' . $e($meta['title']) . '</title><meta name="description" content="' . $e($meta['description']) . '">'
. '<meta name="robots" content="' . $e($meta['robots']) . '">'
. ($meta['canonical'] !== '' ? '<link rel="canonical" href="' . $e($meta['canonical']) . '">' : '')
. '<link rel="stylesheet" href="/assets/css/site.css?v=2">' . $cmsStyleTag . '</head><body>'
. '<header><a href="/">' . $e($site['name']) . '</a><nav aria-label="Nawigacja główna">' . $navigation . '</nav></header>'
. $content . '<footer><p>' . $e($site['name']) . '</p>'
. ($site['contact_email'] !== '' ? '<a href="mailto:' . $e($site['contact_email']) . '">' . $e($site['contact_email']) . '</a>' : '')
. ($site['contact_phone'] !== '' ? '<p>' . $e($site['contact_phone']) . '</p>' : '')
. '</footer><script src="/assets/js/site.js?v=2" defer></script></body></html>';
}
public static function form(array $data): string
{
$e = self::escape(...);
$errors = $data['formErrors'];
$values = $data['formValues'];
$html = '<section class="inquiry"><h1>Porozmawiajmy o Twoim projekcie</h1><p>Opisz, czego potrzebujesz. Zgłoszenie trafi do zespołu FDMTech.</p>';
if ($data['formNotice']) {
$html .= '<p role="status">' . $e($data['formNotice']) . '</p>';
}
if ($errors) {
$html .= '<div role="alert"><h2>Sprawdź formularz</h2><ul>';
foreach ($errors as $field => $error) {
$html .= '<li>' . $e($error) . '</li>';
}
$html .= '</ul></div>';
}
$html .= '<form method="post" action="/inquiries"><input type="hidden" name="_csrf" value="' . $e($data['csrfToken']) . '">'
. '<input type="hidden" name="source" value="audit"><div hidden aria-hidden="true"><label>Twoja strona<input name="website" tabindex="-1" autocomplete="off"></label></div>';
foreach (['name' => ['Imię i nazwisko', 160, 'text', 'name'], 'email' => ['E-mail', 254, 'email', 'email'],
'company' => ['Firma (opcjonalnie)', 200, 'text', 'organization'], 'phone' => ['Telefon (opcjonalnie)', 60, 'tel', 'tel'],
'message' => ['Wiadomość', 10000, 'textarea', 'off']] as $field => [$label, $max, $type, $autocomplete]) {
$attributes = ' id="inquiry-' . $field . '" name="' . $field . '" maxlength="' . $max . '" autocomplete="' . $autocomplete . '"'
. (in_array($field, ['name', 'email', 'message'], true) ? ' required' : '')
. (isset($errors[$field]) ? ' aria-invalid="true" aria-describedby="error-' . $field . '"' : '');
$html .= '<div><label for="inquiry-' . $field . '">' . $label . '</label>';
$html .= $type === 'textarea' ? '<textarea rows="7"' . $attributes . '>' . $e($values[$field] ?? '') . '</textarea>'
: '<input type="' . $type . '"' . $attributes . ' value="' . $e($values[$field] ?? '') . '">';
if (isset($errors[$field])) {
$html .= '<p id="error-' . $field . '">' . $e($errors[$field]) . '</p>';
}
$html .= '</div>';
}
$html .= '<div><label><input type="checkbox" name="consent" value="1" required'
. (($values['consent'] ?? '') === '1' ? ' checked' : '')
. (isset($errors['consent']) ? ' aria-invalid="true" aria-describedby="error-consent"' : '')
. '> Zgadzam się na kontakt i przetwarzanie podanych danych w celu obsługi tego zapytania.</label>';
if (isset($errors['consent'])) {
$html .= '<p id="error-consent">' . $e($errors['consent']) . '</p>';
}
return $html . '</div><p>Zapisujemy Twoje zgłoszenie i oddzwaniamy. Potwierdzenia e-mail nie wysyłamy.</p>'
. '<button type="submit"' . ($data['isDemo'] ? ' disabled' : '') . '>Wyślij zapytanie</button></form></section>';
}
}