refactor(backend): reorganize domains into Core, Commerce, Ticketing and Shared
This commit is contained in:
109
app/Domains/Ticketing/Ticket/Services/TicketPdfService.php
Normal file
109
app/Domains/Ticketing/Ticket/Services/TicketPdfService.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Ticket\Services;
|
||||
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Barryvdh\DomPDF\PDF as DomPdf;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel;
|
||||
use Endroid\QrCode\QrCode;
|
||||
use Endroid\QrCode\Writer\PngWriter;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Throwable;
|
||||
|
||||
class TicketPdfService
|
||||
{
|
||||
/**
|
||||
* @param Collection<int, Ticket> $tickets
|
||||
*/
|
||||
public function download(Tenant $tenant, Collection $tickets): Response
|
||||
{
|
||||
return $this->pdf($tenant, $tickets)->download($this->filename($tickets));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, Ticket> $tickets
|
||||
*/
|
||||
public function contents(Tenant $tenant, Collection $tickets): string
|
||||
{
|
||||
return $this->pdf($tenant, $tickets)->output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, Ticket> $tickets
|
||||
*/
|
||||
public function filename(Collection $tickets): string
|
||||
{
|
||||
return 'tickets_'.$tickets->pluck('id')->implode('_').'.pdf';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, Ticket> $tickets
|
||||
*/
|
||||
private function pdf(Tenant $tenant, Collection $tickets): DomPdf
|
||||
{
|
||||
$tenant->loadMissing('headerLogo');
|
||||
$primaryColor = $this->color($tenant->primary_color, '#009933');
|
||||
$headerBackgroundColor = $this->color($tenant->header_bg_color, $primaryColor);
|
||||
|
||||
return Pdf::loadView('pdf.tickets', [
|
||||
'tenant' => $tenant,
|
||||
'tickets' => $tickets,
|
||||
'logoDataUri' => $this->logoDataUri($tenant),
|
||||
'primaryColor' => $primaryColor,
|
||||
'headerBackgroundColor' => $headerBackgroundColor,
|
||||
'headerTextColor' => $this->contrastingTextColor($headerBackgroundColor),
|
||||
'qrCodes' => $tickets->mapWithKeys(
|
||||
fn (Ticket $ticket): array => [$ticket->id => $this->qrCodeDataUri($ticket->ticket)]
|
||||
),
|
||||
])->setPaper('a4');
|
||||
}
|
||||
|
||||
private function qrCodeDataUri(string $value): string
|
||||
{
|
||||
$qrCode = new QrCode(
|
||||
data: $value,
|
||||
errorCorrectionLevel: ErrorCorrectionLevel::Medium,
|
||||
size: 700,
|
||||
margin: 10,
|
||||
);
|
||||
|
||||
return (new PngWriter)->write($qrCode)->getDataUri();
|
||||
}
|
||||
|
||||
private function logoDataUri(Tenant $tenant): ?string
|
||||
{
|
||||
$logo = $tenant->headerLogo;
|
||||
if ($logo === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$contents = Storage::disk('s3')->get($logo->path);
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'data:'.($logo->mime_type ?: 'image/png').';base64,'.base64_encode($contents);
|
||||
}
|
||||
|
||||
private function color(?string $color, string $fallback): string
|
||||
{
|
||||
return is_string($color) && preg_match('/^#[0-9A-Fa-f]{6}$/', $color)
|
||||
? $color
|
||||
: $fallback;
|
||||
}
|
||||
|
||||
private function contrastingTextColor(string $backgroundColor): string
|
||||
{
|
||||
$red = hexdec(substr($backgroundColor, 1, 2));
|
||||
$green = hexdec(substr($backgroundColor, 3, 2));
|
||||
$blue = hexdec(substr($backgroundColor, 5, 2));
|
||||
$luminance = ($red * 299 + $green * 587 + $blue * 114) / 1000;
|
||||
|
||||
return $luminance > 160 ? '#17211b' : '#ffffff';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user