186 lines
6.6 KiB
PHP
186 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Tenant;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Event;
|
|
use App\Models\EventJoinToken;
|
|
use App\Support\JoinTokenLayoutRegistry;
|
|
use Dompdf\Dompdf;
|
|
use Dompdf\Options;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Str;
|
|
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
|
|
|
class EventJoinTokenLayoutController extends Controller
|
|
{
|
|
public function index(Request $request, Event $event, EventJoinToken $joinToken)
|
|
{
|
|
$this->ensureBelongsToEvent($event, $joinToken);
|
|
|
|
$layouts = JoinTokenLayoutRegistry::toResponse(function (string $layoutId, string $format) use ($event, $joinToken) {
|
|
return route('tenant.events.join-tokens.layouts.download', [
|
|
'event' => $event,
|
|
'joinToken' => $joinToken,
|
|
'layout' => $layoutId,
|
|
'format' => $format,
|
|
]);
|
|
});
|
|
|
|
return response()->json([
|
|
'data' => $layouts,
|
|
]);
|
|
}
|
|
|
|
public function download(Request $request, Event $event, EventJoinToken $joinToken, string $layout, string $format)
|
|
{
|
|
$this->ensureBelongsToEvent($event, $joinToken);
|
|
|
|
$layoutConfig = JoinTokenLayoutRegistry::find($layout);
|
|
|
|
if (! $layoutConfig) {
|
|
abort(404, 'Layout nicht gefunden.');
|
|
}
|
|
|
|
if (! in_array($format, ['pdf', 'svg'], true)) {
|
|
abort(404, 'Unbekanntes Exportformat.');
|
|
}
|
|
|
|
$layoutConfig = $this->applyCustomization($layoutConfig, $joinToken);
|
|
|
|
$tokenUrl = url('/e/'.$joinToken->token);
|
|
|
|
$qrPngDataUri = 'data:image/png;base64,'.base64_encode(
|
|
QrCode::format('png')
|
|
->margin(0)
|
|
->size($layoutConfig['qr']['size_px'])
|
|
->generate($tokenUrl)
|
|
);
|
|
|
|
$backgroundStyle = $this->buildBackgroundStyle($layoutConfig);
|
|
$eventName = $this->resolveEventName($event);
|
|
|
|
$viewData = [
|
|
'layout' => $layoutConfig,
|
|
'event' => $event,
|
|
'eventName' => $eventName,
|
|
'token' => $joinToken,
|
|
'tokenUrl' => $tokenUrl,
|
|
'qrPngDataUri' => $qrPngDataUri,
|
|
'backgroundStyle' => $backgroundStyle,
|
|
'customization' => $joinToken->metadata['layout_customization'] ?? null,
|
|
];
|
|
|
|
$filename = sprintf('%s-%s.%s', Str::slug($eventName ?: 'event'), $layoutConfig['id'], $format);
|
|
|
|
if ($format === 'svg') {
|
|
$svg = view('layouts.join-token.svg', $viewData)->render();
|
|
|
|
return response($svg)
|
|
->header('Content-Type', 'image/svg+xml')
|
|
->header('Content-Disposition', 'attachment; filename="'.$filename.'"');
|
|
}
|
|
|
|
$html = view('layouts.join-token.pdf', $viewData)->render();
|
|
|
|
$options = new Options;
|
|
$options->set('isHtml5ParserEnabled', true);
|
|
$options->set('isRemoteEnabled', true);
|
|
$options->set('defaultFont', 'Helvetica');
|
|
|
|
$dompdf = new Dompdf($options);
|
|
$dompdf->setPaper(strtoupper($layoutConfig['paper']), $layoutConfig['orientation'] === 'landscape' ? 'landscape' : 'portrait');
|
|
$dompdf->loadHtml($html, 'UTF-8');
|
|
$dompdf->render();
|
|
|
|
return response($dompdf->output())
|
|
->header('Content-Type', 'application/pdf')
|
|
->header('Content-Disposition', 'attachment; filename="'.$filename.'"');
|
|
}
|
|
|
|
private function ensureBelongsToEvent(Event $event, EventJoinToken $joinToken): void
|
|
{
|
|
if ($joinToken->event_id !== $event->id) {
|
|
abort(404);
|
|
}
|
|
}
|
|
|
|
private function resolveEventName(Event $event): string
|
|
{
|
|
$name = $event->name;
|
|
|
|
if (is_array($name)) {
|
|
$locale = $event->default_locale ?? 'de';
|
|
|
|
return $name[$locale] ?? $name['de'] ?? reset($name) ?: 'Event';
|
|
}
|
|
|
|
return is_string($name) && $name !== '' ? $name : 'Event';
|
|
}
|
|
|
|
private function applyCustomization(array $layout, EventJoinToken $joinToken): array
|
|
{
|
|
$customization = data_get($joinToken->metadata, 'layout_customization');
|
|
|
|
if (! is_array($customization)) {
|
|
return $layout;
|
|
}
|
|
|
|
$layoutId = $customization['layout_id'] ?? null;
|
|
if (is_string($layoutId) && isset($layout['id']) && $layoutId !== $layout['id']) {
|
|
// Allow customization to target a specific layout; if mismatch, skip style overrides.
|
|
// General text overrides are still applied below.
|
|
}
|
|
|
|
$colorKeys = [
|
|
'accent' => 'accent_color',
|
|
'text' => 'text_color',
|
|
'background' => 'background_color',
|
|
'secondary' => 'secondary_color',
|
|
'badge' => 'badge_color',
|
|
];
|
|
|
|
foreach ($colorKeys as $layoutKey => $customKey) {
|
|
if (isset($customization[$customKey]) && is_string($customization[$customKey])) {
|
|
$layout[$layoutKey] = $customization[$customKey];
|
|
}
|
|
}
|
|
|
|
if (isset($customization['background_gradient']) && is_array($customization['background_gradient'])) {
|
|
$layout['background_gradient'] = $customization['background_gradient'];
|
|
}
|
|
|
|
foreach (['headline' => 'name', 'subtitle', 'description', 'badge_label', 'instructions_heading', 'link_heading', 'cta_label', 'cta_caption', 'link_label'] as $customKey => $layoutKey) {
|
|
if (isset($customization[$customKey]) && is_string($customization[$customKey])) {
|
|
$layout[$layoutKey] = $customization[$customKey];
|
|
}
|
|
}
|
|
|
|
if (array_key_exists('instructions', $customization) && is_array($customization['instructions'])) {
|
|
$layout['instructions'] = array_values(array_filter($customization['instructions'], fn ($value) => is_string($value) && trim($value) !== ''));
|
|
}
|
|
|
|
if (! empty($customization['logo_data_url']) && is_string($customization['logo_data_url'])) {
|
|
$layout['logo_url'] = $customization['logo_data_url'];
|
|
} elseif (! empty($customization['logo_url']) && is_string($customization['logo_url'])) {
|
|
$layout['logo_url'] = $customization['logo_url'];
|
|
}
|
|
|
|
return $layout;
|
|
}
|
|
|
|
private function buildBackgroundStyle(array $layout): string
|
|
{
|
|
$gradient = $layout['background_gradient'] ?? null;
|
|
|
|
if (is_array($gradient) && ! empty($gradient['stops'])) {
|
|
$angle = $gradient['angle'] ?? 180;
|
|
$stops = implode(',', $gradient['stops']);
|
|
|
|
return sprintf('linear-gradient(%ddeg,%s)', $angle, $stops);
|
|
}
|
|
|
|
return $layout['background'] ?? '#FFFFFF';
|
|
}
|
|
}
|