Initale Einrichtung

This commit is contained in:
2026-05-04 18:46:12 +02:00
parent 8f944776a9
commit a675873437
24 changed files with 2776 additions and 1 deletions
+269
View File
@@ -0,0 +1,269 @@
<?php
declare(strict_types=1);
require __DIR__ . '/Support/functions.php';
require __DIR__ . '/Repository/RecordRepositoryInterface.php';
require __DIR__ . '/Repository/JsonRepository.php';
require __DIR__ . '/Repository/MySqlJsonRepository.php';
require __DIR__ . '/Services/BookingService.php';
require __DIR__ . '/Services/InvoicePdfService.php';
session_start();
function runApplication(): void
{
$config = require dirname(__DIR__) . '/config.php';
[$bookingRepository, $invoiceRepository] = resolveRepositories($config);
$bookingService = new BookingService($bookingRepository, $invoiceRepository, $config);
$invoicePdfService = new InvoicePdfService($config);
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
if ($method === 'POST' && $path === '/book') {
handlePublicBooking($bookingService);
return;
}
if ($method === 'POST' && $path === '/admin/login') {
handleAdminLogin($config['admin']);
return;
}
if ($method === 'POST' && $path === '/admin/logout') {
handleAdminLogout();
return;
}
if ($path === '/admin/invoice/pdf') {
requireAdmin();
handleInvoicePdf($bookingService, $invoicePdfService);
return;
}
if (str_starts_with($path, '/admin')) {
handleAdminRequest($path, $method, $bookingService);
return;
}
renderHome($bookingService, $config);
}
function resolveRepositories(array $config): array
{
$databaseFile = $config['database']['credentials_file'];
if (file_exists($databaseFile)) {
$databaseConfig = require $databaseFile;
if (is_array($databaseConfig) && ($databaseConfig['enabled'] ?? false) === true) {
try {
$tablePrefix = (string) ($databaseConfig['table_prefix'] ?? $config['database']['table_prefix'] ?? '');
$dsn = sprintf(
'mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4',
$databaseConfig['host'],
$databaseConfig['port'] ?? 3306,
$databaseConfig['database']
);
$pdo = new PDO($dsn, $databaseConfig['username'], $databaseConfig['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
return [
new MySqlJsonRepository($pdo, resolveTableName($tablePrefix, $config['database']['tables']['bookings'])),
new MySqlJsonRepository($pdo, resolveTableName($tablePrefix, $config['database']['tables']['invoices'])),
];
} catch (Throwable $exception) {
error_log('MySQL-Verbindung fehlgeschlagen, JSON-Fallback aktiv: ' . $exception->getMessage());
}
}
}
return [
new JsonRepository($config['storage']['bookings']),
new JsonRepository($config['storage']['invoices']),
];
}
function resolveTableName(string $prefix, string $table): string
{
return $prefix . $table;
}
function handlePublicBooking(BookingService $bookingService): void
{
try {
$bookingService->createPublicBooking($_POST);
flash('success', 'Deine Anfrage wurde gespeichert. Wir melden uns zeitnah mit der Bestaetigung und allen Details.');
} catch (Throwable $exception) {
flash('error', $exception->getMessage());
flash('old', $_POST);
}
redirect('/');
}
function handleAdminLogin(array $adminConfig): void
{
$username = trim((string) ($_POST['username'] ?? ''));
$password = (string) ($_POST['password'] ?? '');
if ($username === $adminConfig['username'] && hash_equals($adminConfig['password'], $password)) {
$_SESSION['admin_authenticated'] = true;
flash('success', 'Admin-Bereich geoeffnet.');
} else {
flash('error', 'Die Admin-Zugangsdaten sind nicht korrekt.');
}
redirect('/admin');
}
function handleAdminLogout(): void
{
unset($_SESSION['admin_authenticated']);
flash('success', 'Du wurdest aus dem Admin-Bereich abgemeldet.');
redirect('/admin');
}
function handleAdminRequest(string $path, string $method, BookingService $bookingService): void
{
if (!isAdminAuthenticated()) {
renderAdminLogin();
return;
}
if ($method === 'POST' && $path === '/admin/create') {
try {
$bookingService->createAdminBooking($_POST);
flash('success', 'Die Bestellung wurde fuer den Kunden angelegt.');
} catch (Throwable $exception) {
flash('error', $exception->getMessage());
flash('admin_old', $_POST);
}
redirect('/admin/create');
}
if ($method === 'POST' && $path === '/admin/order/update') {
try {
$bookingService->updateBooking((string) ($_POST['booking_id'] ?? ''), $_POST);
flash('success', 'Der Auftrag wurde aktualisiert.');
} catch (Throwable $exception) {
flash('error', $exception->getMessage());
}
redirect('/admin/order?id=' . urlencode((string) ($_POST['booking_id'] ?? '')));
}
if ($method === 'POST' && $path === '/admin/order/invoice') {
try {
$invoiceId = $bookingService->createInvoiceForBooking((string) ($_POST['booking_id'] ?? ''), $_POST);
flash('success', 'Die Rechnung wurde erstellt.');
redirect('/admin/order?id=' . urlencode((string) ($_POST['booking_id'] ?? '')) . '&invoice=' . urlencode($invoiceId));
} catch (Throwable $exception) {
flash('error', $exception->getMessage());
redirect('/admin/order?id=' . urlencode((string) ($_POST['booking_id'] ?? '')));
}
}
if ($path === '/admin/create') {
renderAdminCreate($bookingService);
return;
}
if ($path === '/admin/order') {
renderAdminOrder($bookingService);
return;
}
renderAdminDashboard($bookingService);
}
function handleInvoicePdf(BookingService $bookingService, InvoicePdfService $invoicePdfService): void
{
$invoiceId = (string) ($_GET['id'] ?? '');
$invoice = $bookingService->findInvoice($invoiceId);
if ($invoice === null) {
http_response_code(404);
echo 'Rechnung nicht gefunden.';
return;
}
$pdf = $invoicePdfService->render($invoice);
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . $invoice['invoice_number'] . '.pdf"');
header('Content-Length: ' . strlen($pdf));
echo $pdf;
}
function renderHome(BookingService $bookingService, array $config): void
{
render('home', [
'pageTitle' => 'Fotobox mieten',
'config' => $config,
'flashSuccess' => flash('success'),
'flashError' => flash('error'),
'old' => flash('old') ?? [],
'bookings' => $bookingService->getHighlightedBookings(),
]);
}
function renderAdminLogin(): void
{
render('admin/login', [
'pageTitle' => 'Admin Login',
'flashSuccess' => flash('success'),
'flashError' => flash('error'),
]);
}
function renderAdminDashboard(BookingService $bookingService): void
{
render('admin/dashboard', [
'pageTitle' => 'Admin Dashboard',
'flashSuccess' => flash('success'),
'flashError' => flash('error'),
'stats' => $bookingService->getDashboardStats(),
'bookings' => $bookingService->getBookings(),
'invoices' => $bookingService->getInvoices(),
]);
}
function renderAdminCreate(BookingService $bookingService): void
{
render('admin/create', [
'pageTitle' => 'Kundenbestellung anlegen',
'flashSuccess' => flash('success'),
'flashError' => flash('error'),
'old' => flash('admin_old') ?? [],
'defaults' => $bookingService->getAdminDefaults(),
]);
}
function renderAdminOrder(BookingService $bookingService): void
{
$bookingId = (string) ($_GET['id'] ?? '');
$booking = $bookingService->findBooking($bookingId);
if ($booking === null) {
http_response_code(404);
echo 'Auftrag nicht gefunden.';
return;
}
render('admin/order', [
'pageTitle' => 'Auftrag ' . $booking['reference'],
'flashSuccess' => flash('success'),
'flashError' => flash('error'),
'booking' => $booking,
'invoice' => $booking['invoice_id'] ? $bookingService->findInvoice($booking['invoice_id']) : null,
'statusOptions' => $bookingService->getStatusOptions(),
'paymentOptions' => $bookingService->getPaymentStatusOptions(),
]);
}