340 lines
13 KiB
PHP
340 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* Copyright seit 2024 Webshop System
|
|
*
|
|
* Frontend-Produktdetail-Controller für das Webshop-System
|
|
*
|
|
* @author Webshop System
|
|
* @license GPL v3
|
|
*/
|
|
|
|
namespace App\Front\Controllers;
|
|
|
|
use Doctrine\DBAL\DriverManager;
|
|
use Doctrine\DBAL\Exception;
|
|
|
|
class ProductController
|
|
{
|
|
public function show($id)
|
|
{
|
|
// DB-Verbindung herstellen
|
|
$connectionParams = [
|
|
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
|
|
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
|
|
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
|
|
'host' => getenv('DB_HOST') ?: 'db',
|
|
'driver' => 'pdo_mysql',
|
|
'port' => getenv('DB_PORT') ?: 3306,
|
|
'charset' => 'utf8mb4',
|
|
];
|
|
|
|
try {
|
|
$conn = DriverManager::getConnection($connectionParams);
|
|
|
|
// Produkt mit Kategorie laden
|
|
$stmt = $conn->prepare('
|
|
SELECT p.*, c.name as category_name, c.id as category_id
|
|
FROM ws_product p
|
|
LEFT JOIN ws_category c ON p.category_id = c.id
|
|
WHERE p.id = ? AND p.active = 1
|
|
');
|
|
$stmt->execute([$id]);
|
|
$product = $stmt->fetchAssociative();
|
|
|
|
if (!$product) {
|
|
$this->render('front/error/404.html.twig', [
|
|
'title' => 'Webshop - Produkt nicht gefunden',
|
|
'message' => 'Das angeforderte Produkt wurde nicht gefunden.'
|
|
]);
|
|
return;
|
|
}
|
|
|
|
// Bewertungen laden
|
|
$stmt = $conn->prepare('
|
|
SELECT r.*, c.first_name, c.last_name
|
|
FROM ws_review r
|
|
LEFT JOIN ws_customer c ON r.customer_id = c.id
|
|
WHERE r.product_id = ? AND r.active = 1
|
|
ORDER BY r.created_at DESC
|
|
');
|
|
$stmt->execute([$id]);
|
|
$reviews = $stmt->fetchAllAssociative();
|
|
|
|
// Durchschnittsbewertung berechnen
|
|
$stmt = $conn->prepare('
|
|
SELECT AVG(rating) as avg_rating, COUNT(*) as total_reviews
|
|
FROM ws_review
|
|
WHERE product_id = ? AND active = 1
|
|
');
|
|
$stmt->execute([$id]);
|
|
$ratingStats = $stmt->fetchAssociative();
|
|
|
|
// Verwandte Produkte laden (gleiche Kategorie)
|
|
$stmt = $conn->prepare('
|
|
SELECT p.*, c.name as category_name
|
|
FROM ws_product p
|
|
LEFT JOIN ws_category c ON p.category_id = c.id
|
|
WHERE p.category_id = ? AND p.id != ? AND p.active = 1
|
|
ORDER BY RAND()
|
|
LIMIT 4
|
|
');
|
|
$stmt->execute([$product['category_id'], $id]);
|
|
$relatedProducts = $stmt->fetchAllAssociative();
|
|
|
|
// Produktbilder laden
|
|
$stmt = $conn->prepare('
|
|
SELECT * FROM ws_product_image
|
|
WHERE product_id = ?
|
|
ORDER BY sort_order ASC
|
|
');
|
|
$stmt->execute([$id]);
|
|
$productImages = $stmt->fetchAllAssociative();
|
|
|
|
// Produktvarianten laden (falls vorhanden)
|
|
$stmt = $conn->prepare('
|
|
SELECT * FROM ws_product_variant
|
|
WHERE product_id = ? AND active = 1
|
|
ORDER BY sort_order ASC
|
|
');
|
|
$stmt->execute([$id]);
|
|
$productVariants = $stmt->fetchAllAssociative();
|
|
|
|
$this->render('front/product/show.html.twig', [
|
|
'title' => 'Webshop - ' . $product['name'],
|
|
'product' => $product,
|
|
'reviews' => $reviews,
|
|
'ratingStats' => $ratingStats,
|
|
'relatedProducts' => $relatedProducts,
|
|
'productImages' => $productImages,
|
|
'productVariants' => $productVariants
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
$this->render('front/error/500.html.twig', [
|
|
'title' => 'Webshop - Fehler',
|
|
'message' => 'Ein Fehler ist aufgetreten: ' . $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public function addReview()
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
header('Location: /');
|
|
return;
|
|
}
|
|
|
|
$productId = $_POST['product_id'] ?? null;
|
|
$rating = $_POST['rating'] ?? null;
|
|
$comment = $_POST['comment'] ?? '';
|
|
$customerId = $_SESSION['customer_id'] ?? null;
|
|
|
|
if (!$productId || !$rating || !$customerId) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Ungültige Daten']);
|
|
return;
|
|
}
|
|
|
|
$connectionParams = [
|
|
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
|
|
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
|
|
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
|
|
'host' => getenv('DB_HOST') ?: 'db',
|
|
'driver' => 'pdo_mysql',
|
|
'port' => getenv('DB_PORT') ?: 3306,
|
|
'charset' => 'utf8mb4',
|
|
];
|
|
|
|
try {
|
|
$conn = DriverManager::getConnection($connectionParams);
|
|
|
|
// Prüfen ob bereits eine Bewertung existiert
|
|
$stmt = $conn->prepare('
|
|
SELECT id FROM ws_review
|
|
WHERE product_id = ? AND customer_id = ?
|
|
');
|
|
$stmt->execute([$productId, $customerId]);
|
|
$existingReview = $stmt->fetchAssociative();
|
|
|
|
if ($existingReview) {
|
|
// Bewertung aktualisieren
|
|
$stmt = $conn->prepare('
|
|
UPDATE ws_review
|
|
SET rating = ?, comment = ?, updated_at = NOW()
|
|
WHERE id = ?
|
|
');
|
|
$stmt->execute([$rating, $comment, $existingReview['id']]);
|
|
} else {
|
|
// Neue Bewertung erstellen
|
|
$stmt = $conn->prepare('
|
|
INSERT INTO ws_review (product_id, customer_id, rating, comment, active, created_at)
|
|
VALUES (?, ?, ?, ?, 1, NOW())
|
|
');
|
|
$stmt->execute([$productId, $customerId, $rating, $comment]);
|
|
}
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => true, 'message' => 'Bewertung erfolgreich gespeichert']);
|
|
|
|
} catch (Exception $e) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Fehler: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function addToWishlist()
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Ungültige Anfrage']);
|
|
return;
|
|
}
|
|
|
|
$productId = $_POST['product_id'] ?? null;
|
|
$customerId = $_SESSION['customer_id'] ?? null;
|
|
|
|
if (!$productId || !$customerId) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Nicht angemeldet']);
|
|
return;
|
|
}
|
|
|
|
$connectionParams = [
|
|
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
|
|
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
|
|
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
|
|
'host' => getenv('DB_HOST') ?: 'db',
|
|
'driver' => 'pdo_mysql',
|
|
'port' => getenv('DB_PORT') ?: 3306,
|
|
'charset' => 'utf8mb4',
|
|
];
|
|
|
|
try {
|
|
$conn = DriverManager::getConnection($connectionParams);
|
|
|
|
// Prüfen ob bereits in Wunschliste
|
|
$stmt = $conn->prepare('
|
|
SELECT id FROM ws_wishlist
|
|
WHERE product_id = ? AND customer_id = ?
|
|
');
|
|
$stmt->execute([$productId, $customerId]);
|
|
$existing = $stmt->fetchAssociative();
|
|
|
|
if ($existing) {
|
|
// Aus Wunschliste entfernen
|
|
$stmt = $conn->prepare('DELETE FROM ws_wishlist WHERE id = ?');
|
|
$stmt->execute([$existing['id']]);
|
|
$message = 'Aus Wunschliste entfernt';
|
|
$inWishlist = false;
|
|
} else {
|
|
// Zur Wunschliste hinzufügen
|
|
$stmt = $conn->prepare('
|
|
INSERT INTO ws_wishlist (product_id, customer_id, created_at)
|
|
VALUES (?, ?, NOW())
|
|
');
|
|
$stmt->execute([$productId, $customerId]);
|
|
$message = 'Zur Wunschliste hinzugefügt';
|
|
$inWishlist = true;
|
|
}
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode([
|
|
'success' => true,
|
|
'message' => $message,
|
|
'in_wishlist' => $inWishlist
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Fehler: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function quickView()
|
|
{
|
|
$productId = $_GET['id'] ?? null;
|
|
|
|
if (!$productId) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Produkt-ID fehlt']);
|
|
return;
|
|
}
|
|
|
|
$connectionParams = [
|
|
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
|
|
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
|
|
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
|
|
'host' => getenv('DB_HOST') ?: 'db',
|
|
'driver' => 'pdo_mysql',
|
|
'port' => getenv('DB_PORT') ?: 3306,
|
|
'charset' => 'utf8mb4',
|
|
];
|
|
|
|
try {
|
|
$conn = DriverManager::getConnection($connectionParams);
|
|
|
|
$stmt = $conn->prepare('
|
|
SELECT p.*, c.name as category_name
|
|
FROM ws_product p
|
|
LEFT JOIN ws_category c ON p.category_id = c.id
|
|
WHERE p.id = ? AND p.active = 1
|
|
');
|
|
$stmt->execute([$productId]);
|
|
$product = $stmt->fetchAssociative();
|
|
|
|
if (!$product) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Produkt nicht gefunden']);
|
|
return;
|
|
}
|
|
|
|
// Quick View HTML generieren
|
|
$html = $this->generateQuickViewHtml($product);
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode([
|
|
'success' => true,
|
|
'html' => $html
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Fehler: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
private function generateQuickViewHtml($product)
|
|
{
|
|
return '
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">' . htmlspecialchars($product['name']) . '</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<img src="' . htmlspecialchars($product['image']) . '"
|
|
class="img-fluid"
|
|
alt="' . htmlspecialchars($product['name']) . '">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>' . htmlspecialchars($product['name']) . '</h6>
|
|
<p class="text-muted">' . htmlspecialchars($product['category_name']) . '</p>
|
|
<p>' . htmlspecialchars(substr($product['description'], 0, 200)) . '...</p>
|
|
<h5 class="text-success">€' . number_format($product['price'], 2, ',', '.') . '</h5>
|
|
<button class="btn btn-primary add-to-cart-quick"
|
|
data-product-id="' . $product['id'] . '">
|
|
<i class="fas fa-cart-plus me-2"></i>Zum Warenkorb
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>';
|
|
}
|
|
|
|
protected function render($template, $data = [])
|
|
{
|
|
// Einfache Template-Engine (später durch Twig ersetzen)
|
|
extract($data);
|
|
include __DIR__ . '/../../templates/' . $template;
|
|
}
|
|
}
|