<?php
# src/Controller/ShopController.php
namespace App\Controller;
use App\Entity\ShopProdukt;
use App\Entity\ShopKategorie;
use App\Entity\Bestellung;
use App\Service\PayPalService;
use App\Service\VPNSetupService;
use App\Repository\ShopProduktRepository;
use App\Repository\ShopKategorieRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
#[Route('/shop')]
class ShopController extends AbstractController
{
private ShopProduktRepository $produktRepository;
private ShopKategorieRepository $kategorieRepository;
private EntityManagerInterface $entityManager;
public function __construct(
ShopProduktRepository $produktRepository,
ShopKategorieRepository $kategorieRepository,
EntityManagerInterface $entityManager
) {
$this->produktRepository = $produktRepository;
$this->kategorieRepository = $kategorieRepository;
$this->entityManager = $entityManager;
}
#[Route('/', name: 'shop_overview', methods: ['GET'])]
public function shopOverview(): Response
{
// Hole alle Produkte und Kategorien aus der Datenbank
$products = $this->produktRepository->findAll();
$kategorien = $this->kategorieRepository->findAll();
return $this->render('shop/overview.html.twig', [
'products' => $products,
'kategorien' => $kategorien,
]);
}
#[Route('/product/{id}', name: 'shop_product_detail', methods: ['GET'])]
public function productDetail(int $id): Response
{
// Suche ein Produkt anhand der ID
$product = $this->produktRepository->find($id);
if (!$product) {
throw $this->createNotFoundException('Produkt nicht gefunden');
}
return $this->render('shop/detail.html.twig', [
'product' => $product,
]);
}
#[Route('/cart/add/{id}', name: 'shop_cart_add', methods: ['POST'])]
public function addToCart(int $id, Request $request): JsonResponse
{
$product = $this->produktRepository->find($id);
if (!$product) {
return new JsonResponse(['error' => 'Produkt nicht gefunden'], 404);
}
// Kasse aus der Session holen
$session = $request->getSession();
$cart = $session->get('cart', []);
// Produkt hinzufügen oder Menge erhöhen
if (isset($cart[$id])) {
$cart[$id]['quantity'] += 1;
} else {
$cart[$id] = [
'product' => $product,
'quantity' => 1
];
}
// Warenkorb in der Session speichern
$session->set('cart', $cart);
return new JsonResponse([
'cartHtml' => $this->renderView('shop/_cart_items.html.twig', ['cart' => $cart]),
'total' => $this->calculateTotal($cart),
'product' => [
'name' => $product->getName(),
'description' => $product->getBeschreibung(),
'price' => number_format($product->getPreis(), 2, ',', '.')
]
]);
}
#[Route('/cart/remove/{id}', name: 'shop_cart_remove', methods: ['POST'])]
public function removeFromCart(int $id, Request $request): JsonResponse
{
try {
// Kasse aus der Session holen
$session = $request->getSession();
$cart = $session->get('cart', []);
// Entferne das Produkt oder reduziere die Menge
if (isset($cart[$id])) {
if ($cart[$id]['quantity'] > 1) {
$cart[$id]['quantity'] -= 1;
} else {
unset($cart[$id]);
}
}
// Kasse in der Session speichern
$session->set('cart', $cart);
// Erfolgsnachricht hinzufügen
$this->addFlash('success', 'Produkt erfolgreich aus dem Warenkorb entfernt');
return new JsonResponse([
'cartHtml' => $this->renderView('shop/_cart_items.html.twig', ['cart' => $cart]),
'total' => $this->calculateTotal($cart)
]);
} catch (\Exception $e) {
// Fehlernachricht hinzufügen
$this->addFlash('error', 'Fehler beim Entfernen aus dem Warenkorb');
return new JsonResponse(['error' => 'Fehler beim Entfernen aus dem Warenkorb'], 500);
}
}
######################
#[Route('/checkout/process', name: 'shop_checkout_process', methods: ['POST'])]
public function checkoutProcess(Request $request): Response
{
if (!$this->getUser()) {
$this->addFlash('error', 'Bitte loggen Sie sich ein, um den Kauf abzuschließen.');
return $this->redirectToRoute('app_login');
}
// Hole die Zahlungsmethode aus dem Request (PayPal oder andere Methoden)
$paymentMethod = $request->request->get('payment_method');
// Warenkorb aus der Session holen
$session = $request->getSession();
$cart = $session->get('cart', []);
if (empty($cart)) {
$this->addFlash('error', 'Der Warenkorb ist leer.');
return $this->redirectToRoute('shop_overview');
}
// Bestellung erstellen
$bestellung = new Bestellung();
$bestellung->setKunde($this->getUser());
$bestellung->setBestelldatum(new \DateTime());
$bestellung->setStatus('pending');
$bestellung->setGesamtbetrag($this->calculateTotal($cart));
foreach ($cart as $cartItem) {
$product = $this->produktRepository->find($cartItem['product']->getId());
if (!$product) {
throw $this->createNotFoundException('Produkt nicht gefunden.');
}
$bestellung->addProdukt($product);
}
$this->entityManager->persist($bestellung);
$this->entityManager->flush();
// Warenkorb leeren
$session->remove('cart');
// Weiterleitung zu PayPal oder Stripe basierend auf der Zahlungsmethode
if ($paymentMethod === 'paypal') {
return $this->redirectToRoute('paypal_payment', ['order_id' => $bestellung->getId()]);
} elseif ($paymentMethod === 'stripe') {
return $this->redirectToRoute('stripe_payment', ['order_id' => $bestellung->getId()]);
}
// Als Fallback zurück zum Shop, falls keine Methode ausgewählt wurde
return $this->redirectToRoute('shop_overview');
}
#[Route('/payment/confirm', name: 'payment_confirm', methods: ['GET'])]
public function confirmPayment(Request $request, PayPalService $paypalService, VPNSetupService $vpnSetupService): Response
{
// Abrufen der PayPal-Bestell-ID vom Rückruf von PayPal
$paypalOrderId = $request->query->get('token'); // Abrufen des Tokens aus der PayPal-Rückmeldung
if (!$paypalOrderId) {
throw $this->createNotFoundException('PayPal-Token nicht gefunden.');
}
// Bestellung anhand der PayPal-Order-ID finden
$bestellung = $this->entityManager->getRepository(Bestellung::class)
->findOneBy(['paypalOrderId' => $paypalOrderId]);
if (!$bestellung) {
throw $this->createNotFoundException('Bestellung nicht gefunden.');
}
// Zahlung bestätigen
$response = $paypalService->captureOrder($paypalOrderId);
if ($response->statusCode === 201) {
// Setze den Bestellstatus auf 'completed'
$bestellung->setStatus('completed');
$this->entityManager->flush();
// Hier wird der VPN-Setup-Service aufgerufen
try {
$vpnSetupService->setupVPNForUser($bestellung->getKunde()); // Kunde aus der Bestellung
$this->addFlash('success', 'Zahlung erfolgreich abgeschlossen und VPN eingerichtet!');
} catch (\Exception $e) {
// Wenn das VPN-Setup fehlschlägt, füge eine Fehlermeldung hinzu
$this->addFlash('error', 'Zahlung erfolgreich, aber VPN-Setup fehlgeschlagen.');
}
// Erfolgreiche Bestellung anzeigen
return $this->render('shop/order_success.html.twig', ['order' => $bestellung]);
}
// Bei Fehler die Nachricht anzeigen
$this->addFlash('error', 'Zahlung fehlgeschlagen.');
return $this->redirectToRoute('shop_overview');
}
#[Route('/payment/paypal/{order_id}', name: 'paypal_payment')]
public function paypalPayment(int $order_id, PayPalService $paypalService): Response
{
// Bestellung aus der Datenbank holen
$bestellung = $this->entityManager->getRepository(Bestellung::class)->find($order_id);
if (!$bestellung) {
throw $this->createNotFoundException('Bestellung nicht gefunden.');
}
// Gesamtsumme der Bestellung holen
$totalAmount = $bestellung->getGesamtbetrag();
// PayPal-Order erstellen
$response = $paypalService->createOrder($totalAmount);
// Speichere die PayPal-Order-ID in der Bestellung
$bestellung->setPaypalOrderId($response->result->id);
$this->entityManager->flush();
// Leite den Benutzer zur PayPal-Zahlungsseite weiter
return $this->redirect($response->result->links[1]->href);
}
#[Route('/checkout/{id?}', name: 'shop_checkout', methods: ['GET', 'POST'])]
public function checkout(?int $id, Request $request): Response
{
// Warenkorb aus der Session holen
$session = $request->getSession();
$cart = $session->get('cart', []);
// Wenn eine Produkt-ID angegeben ist, behandeln wir es als einzelnes Produkt
if ($id) {
$product = $this->produktRepository->find($id);
if (!$product) {
throw $this->createNotFoundException('Produkt nicht gefunden');
}
// Füge das Produkt in den Warenkorb hinzu, falls es noch nicht existiert
if (!isset($cart[$id])) {
$cart[$id] = [
'product' => $product,
'quantity' => 1
];
$session->set('cart', $cart);
}
// Produkte nach Kategorie gruppieren
$allProducts = $this->produktRepository->findAll();
$similarProducts = [];
foreach ($allProducts as $similarProduct) {
$kategorieId = $similarProduct->getKategorie()->getId();
if ($kategorieId !== $product->getKategorie()->getId() && !isset($similarProducts[$kategorieId])) {
$similarProducts[$kategorieId] = $similarProduct;
}
}
return $this->render('Shop/checkout.html.twig', [
'product' => $product,
'cart' => $cart,
'similar_products' => array_values($similarProducts),
]);
}
// Allgemeiner Checkout, wenn keine ID vorhanden ist
if (empty($cart)) {
$this->addFlash('error', 'Ihr Warenkorb ist leer.');
return $this->render('Shop/empty_cart.html.twig'); // Ein spezielles Template für leere Warenkörbe
}
// Gesamtsumme berechnen für den Warenkorb-Checkout
$total = $this->calculateTotal($cart);
return $this->render('Shop/checkout.html.twig', [
'cart' => $cart,
'total' => $total,
'similar_products' => [] // Keine ähnlichen Produkte im allgemeinen Warenkorb-Checkout
]);
}
private function calculateTotal(array $cart): float
{
$total = 0;
foreach ($cart as $item) {
$total += $item['product']->getPreis() * $item['quantity'];
}
return $total; // Rückgabe als float
}
#[Route('/admin/product/update-sort-order', name: 'admin_shop_product_update_sort_order', methods: ['POST'])]
public function updateSortOrder(Request $request, CsrfTokenManagerInterface $csrfTokenManager): JsonResponse
{
$token = $request->request->get('_token');
if (!$csrfTokenManager->isTokenValid(new CsrfToken('update_sort_order', $token))) {
return new JsonResponse(['error' => 'Invalid CSRF token'], 400);
}
$productId = $request->request->get('id');
$newSortOrder = (int)$request->request->get('sortOrder');
// Produkt suchen
$product = $this->produktRepository->find($productId);
if (!$product) {
return new JsonResponse(['error' => 'Produkt nicht gefunden'], 404);
}
// Sortierreihenfolge aktualisieren
$product->setSortOrder($newSortOrder);
$this->entityManager->flush();
return new JsonResponse(['success' => true, 'message' => 'Sortierreihenfolge erfolgreich aktualisiert']);
}
#[Route('/payment/stripe/{order_id}', name: 'stripe_payment')]
public function stripePayment(int $order_id)
{
// Logik für Stripe-Zahlung
}
}