wip: extend model, admin crud

This commit is contained in:
Björn Fromme committed 2026-07-16 17:13:15 +02:00
1 parent a6ba4fac0d
commit d9f29a5a5a
38 files changed
+1240 -830

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260630080409 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price ADD season VARCHAR(20) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price DROP season');
}
}
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Accommodation;
use App\Entity\Groups\Accommodation;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CalendarController extends AbstractController
{
#[Route('/admin/accommodation/{id}/calendar', name: 'app_admin_accommodation_calendar', methods: ['GET'])]
public function index(Accommodation $accommodation, Request $request): Response
{
return $this->render('admin/accommodation/_calendar_section.html.twig', [
'accommodation' => $accommodation,
'startMonth' => $request->query->get('month'),
]);
}
}
@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Accommodation;
use App\Entity\Groups\Accommodation;
use App\Form\Admin\Groups\AccommodationType;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CreateController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation/create', name: 'app_admin_accommodation_create')]
public function index(Request $request): Response
{
$accommodation = new Accommodation();
$form = $this->createForm(AccommodationType::class, $accommodation, ['hx_post' => $request->getRequestUri()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($accommodation);
$this->entityManager->flush();
$this->addFlash('success', 'Das Gruppenhaus wurde angelegt');
$this->logger->info('Created accommodation', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
]);
return new HxRedirectResponse($this->generateUrl('app_admin_accommodation'));
}
return $this->render('admin/accommodation/modal_create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
}
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Accommodation;
use App\Entity\Groups\Accommodation;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class DeleteController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation/{id}/delete', name: 'app_admin_accommodation_delete')]
public function index(Accommodation $accommodation, Request $request): Response
{
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($accommodation);
$this->entityManager->flush();
$this->addFlash('success', 'Das Gruppenhaus wurde gelöscht');
$this->logger->info('Deleted accommodation', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
]);
return new HxRedirectResponse($this->generateUrl('app_admin_accommodation'));
}
return $this->render('admin/accommodation/modal_delete.html.twig', [
'accommodation' => $accommodation,
]);
}
}
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Accommodation;
use App\Entity\Groups\Accommodation;
use App\Form\Admin\Groups\AccommodationType;
use App\Service\CmsDataProvider;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class EditController extends AbstractController
{
public function __construct(
private readonly CmsDataProvider $cmsDataProvider,
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation/{id}/edit', name: 'app_admin_accommodation_edit')]
public function index(Accommodation $accommodation, Request $request): Response
{
// fetch additional data from cms if available
$cmsData = [];
if (null !== $accommodation->getCode()) {
$cmsData = $this->cmsDataProvider->getHotelDetails($accommodation->getCode());
}
$form = $this->createForm(AccommodationType::class, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($accommodation);
$this->entityManager->flush();
$this->addFlash('success', 'Das Gruppenhaus wurde aktualisiert');
$this->logger->info('Updated accommodation', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', ['id' => $accommodation->getId()]);
}
return $this->render('admin/accommodation/edit.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
'cmsData' => $cmsData,
]);
}
}
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Accommodation;
use App\Repository\Groups\AccommodationRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class IndexController extends AbstractController
{
public function __construct(
private readonly AccommodationRepository $accommodationRepository,
) {
}
#[Route('/admin/accommodation', name: 'app_admin_accommodation')]
public function index(): Response
{
$accommodations = $this->accommodationRepository->findBy([], ['code' => 'ASC']);
return $this->render('admin/accommodation/index.html.twig', [
'accommodations' => $accommodations,
]);
}
}
@@ -1,131 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Groups\Accommodation;
use App\Form\Admin\Groups\AccommodationType;
use App\Htmx\HxRedirectResponse;
use App\Repository\Groups\AccommodationRepository;
use App\Service\CmsDataProvider;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class AccommodationController extends AbstractController
{
public function __construct(
private readonly AccommodationRepository $accommodationRepository,
private readonly CmsDataProvider $cmsDataProvider,
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation', name: 'app_admin_accommodation')]
public function index(): Response
{
$accommodations = $this->accommodationRepository->findBy([], ['code' => 'ASC']);
return $this->render('admin/accommodation/index.html.twig', [
'accommodations' => $accommodations,
]);
}
#[Route('/admin/accommodation/create', name: 'app_admin_accommodation_create')]
public function create(Request $request): Response
{
$accommodation = new Accommodation();
$form = $this->createForm(AccommodationType::class, $accommodation, ['hx_post' => $request->getRequestUri()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($accommodation);
$this->entityManager->flush();
$this->addFlash('success', 'Das Gruppenhaus wurde angelegt');
$this->logger->info('Created accommodation', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
]);
return new HxRedirectResponse($this->generateUrl('app_admin_accommodation'));
}
return $this->render('admin/accommodation/modal_create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
#[Route('/admin/accommodation/{id}/edit', name: 'app_admin_accommodation_edit')]
public function edit(Accommodation $accommodation, Request $request): Response
{
// fetch additional data from cms if available
$cmsData = [];
if (null !== $accommodation->getCode()) {
$cmsData = $this->cmsDataProvider->getHotelDetails($accommodation->getCode());
}
$form = $this->createForm(AccommodationType::class, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($accommodation);
$this->entityManager->flush();
$this->addFlash('success', 'Das Gruppenhaus wurde aktualisiert');
$this->logger->info('Updated accommodation', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', ['id' => $accommodation->getId()]);
}
return $this->render('admin/accommodation/edit.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
'cmsData' => $cmsData,
]);
}
#[Route('/admin/accommodation/{id}/calendar', name: 'app_admin_accommodation_calendar', methods: ['GET'])]
public function calendar(Accommodation $accommodation, Request $request): Response
{
return $this->render('admin/accommodation/_calendar_section.html.twig', [
'accommodation' => $accommodation,
'startMonth' => $request->query->get('month'),
]);
}
#[Route('/admin/accommodation/{id}/delete', name: 'app_admin_accommodation_delete')]
public function delete(Accommodation $accommodation, Request $request): Response
{
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($accommodation);
$this->entityManager->flush();
$this->addFlash('success', 'Das Gruppenhaus wurde gelöscht');
$this->logger->info('Deleted accommodation', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
]);
return new HxRedirectResponse($this->generateUrl('app_admin_accommodation'));
}
return $this->render('admin/accommodation/modal_delete.html.twig', [
'accommodation' => $accommodation,
]);
}
}
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AccommodationPrice;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\AccommodationPrice;
use App\Form\Admin\Groups\AccommodationPriceType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CreateController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation-price/{id}/create', name: 'app_admin_accommodationprice_create')]
public function index(Accommodation $accommodation, Request $request): Response
{
$accommodationPrice = new AccommodationPrice();
$form = $this->createForm(AccommodationPriceType::class, $accommodationPrice, ['currency' => $accommodation->getCurrency()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accommodation->addAccommodationPrice($accommodationPrice);
$this->entityManager->persist($accommodationPrice);
$this->entityManager->flush();
$this->addFlash('success', 'Der Preis wurde angelegt');
$this->logger->info('Created accommodation price', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'date_range' => [
'from' => $accommodationPrice->getDateFrom()->format('Y-m-d'),
'to' => $accommodationPrice->getDateTo()->format('Y-m-d'),
]
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/accommodation_price/create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
}
@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AccommodationPrice;
use App\Entity\Groups\AccommodationPrice;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class DeleteController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation-price/{id}/delete', name: 'app_admin_accommodationprice_delete')]
public function index(AccommodationPrice $accommodationPrice, Request $request): Response
{
$accommodation = $accommodationPrice->getAccommodation();
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($accommodationPrice);
$this->entityManager->flush();
$this->addFlash('success', 'Der Preis wurde gelöscht');
$this->logger->info('Deleted accommodation price', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'date_range' => [
'from' => $accommodationPrice->getDateFrom()->format('Y-m-d'),
'to' => $accommodationPrice->getDateTo()->format('Y-m-d'),
]
]);
$returnUrl = $this->generateUrl('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/accommodation_price/modal_delete.html.twig', [
'accommodationPrice' => $accommodationPrice,
'accommodation' => $accommodation,
]);
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AccommodationPrice;
use App\Entity\Groups\AccommodationPrice;
use App\Form\Admin\Groups\AccommodationPriceType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class EditController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation-price/{id}/edit', name: 'app_admin_accommodationprice_edit', defaults: ['duplicate' => false])]
#[Route('/admin/accommodation-price/{id}/duplicate', name: 'app_admin_accommodationprice_duplicate', defaults: ['duplicate' => true])]
public function index(AccommodationPrice $accommodationPrice, bool $duplicate, Request $request): Response
{
$accommodation = $accommodationPrice->getAccommodation();
if (true === $duplicate) {
$accommodationPrice = clone $accommodationPrice;
}
$form = $this->createForm(AccommodationPriceType::class, $accommodationPrice, ['currency' => $accommodation->getCurrency()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (true === $duplicate) {
$accommodation->addAccommodationPrice($accommodationPrice);
}
$this->entityManager->persist($accommodationPrice);
$this->entityManager->flush();
$this->addFlash('success', 'Der Preis wurde aktualisiert');
$this->logger->info('Edited accommodation price', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'date_range' => [
'from' => $accommodationPrice->getDateFrom()->format('Y-m-d'),
'to' => $accommodationPrice->getDateTo()->format('Y-m-d'),
]
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/accommodation_price/edit.html.twig', [
'accommodation' => $accommodation,
'accommodationPrice' => $accommodationPrice,
'form' => $form,
'duplicate' => $duplicate,
]);
}
}
@@ -1,145 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\AccommodationPrice;
use App\Form\Admin\Groups\AccommodationPriceType;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class AccommodationPriceController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/accommodation-price/{id}/create', name: 'app_admin_accommodationprice_create')]
public function create(Accommodation $accommodation, Request $request): Response
{
$accommodationPrice = new AccommodationPrice();
$form = $this->getForm($accommodationPrice, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accommodation->addAccommodationPrice($accommodationPrice);
$this->entityManager->persist($accommodationPrice);
$this->entityManager->flush();
$this->addFlash('success', 'Der Preis wurde angelegt');
$this->logger->info('Created accommodation price', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'date_range' => [
'from' => $accommodationPrice->getDateFrom()->format('Y-m-d'),
'to' => $accommodationPrice->getDateTo()->format('Y-m-d'),
]
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/accommodation_price/create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
#[Route('/admin/accommodation-price/{id}/edit', name: 'app_admin_accommodationprice_edit', defaults: ['duplicate' => false])]
#[Route('/admin/accommodation-price/{id}/duplicate', name: 'app_admin_accommodationprice_duplicate', defaults: ['duplicate' => true])]
public function edit(AccommodationPrice $accommodationPrice, bool $duplicate, Request $request): Response
{
$accommodation = $accommodationPrice->getAccommodation();
if (true === $duplicate) {
$accommodationPrice = clone $accommodationPrice;
}
$form = $this->getForm($accommodationPrice, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (true === $duplicate) {
$accommodation->addAccommodationPrice($accommodationPrice);
}
$this->entityManager->persist($accommodationPrice);
$this->entityManager->flush();
$this->addFlash('success', 'Der Preis wurde aktualisiert');
$this->logger->info('Edited accommodation price', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'date_range' => [
'from' => $accommodationPrice->getDateFrom()->format('Y-m-d'),
'to' => $accommodationPrice->getDateTo()->format('Y-m-d'),
]
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/accommodation_price/edit.html.twig', [
'accommodation' => $accommodation,
'accommodationPrice' => $accommodationPrice,
'form' => $form,
'duplicate' => $duplicate,
]);
}
#[Route('/admin/accommodation-price/{id}/delete', name: 'app_admin_accommodationprice_delete')]
public function delete(AccommodationPrice $accommodationPrice, Request $request): Response
{
$accommodation = $accommodationPrice->getAccommodation();
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($accommodationPrice);
$this->entityManager->flush();
$this->addFlash('success', 'Der Preis wurde gelöscht');
$this->logger->info('Deleted accommodation price', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'date_range' => [
'from' => $accommodationPrice->getDateFrom()->format('Y-m-d'),
'to' => $accommodationPrice->getDateTo()->format('Y-m-d'),
]
]);
$returnUrl = $this->generateUrl('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/accommodation_price/modal_delete.html.twig', [
'accommodationPrice' => $accommodationPrice,
'accommodation' => $accommodation,
]);
}
private function getForm(AccommodationPrice $accommodationPrice, Accommodation $accommodation): FormInterface
{
return $this->createForm(AccommodationPriceType::class, $accommodationPrice, ['currency' => $accommodation->getCurrency()]);
}
}
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AdditionalService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\AdditionalService;
use App\Form\Admin\Groups\AdditionalServiceType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CreateController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/additional-service/{id}/create', name: 'app_admin_additionalservice_create')]
public function index(Accommodation $accommodation, Request $request): Response
{
$additionalService = new AdditionalService();
$form = $this->createForm(AdditionalServiceType::class, $additionalService, ['currency' => $accommodation->getCurrency()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accommodation->addAdditionalService($additionalService);
$this->entityManager->persist($additionalService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Zusatzleistung wurde angelegt');
$this->logger->info('Created additional service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $additionalService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/additional_service/create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
}
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AdditionalService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\AdditionalService;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class DeleteController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/additional-service/{id}/delete', name: 'app_admin_additionalservice_delete')]
public function index(AdditionalService $additionalService, Request $request): Response
{
$accommodation = $additionalService->getAccommodation();
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($additionalService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Zusatzleistung wurde gelöscht');
$this->logger->info('Deleted additional service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $additionalService->getLabel(),
]);
$returnUrl = $this->generateUrl('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/additional_service/modal_delete.html.twig', [
'additionalService' => $additionalService,
'accommodation' => $accommodation,
]);
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AdditionalService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\AdditionalService;
use App\Form\Admin\Groups\AdditionalServiceType;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class EditController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/additional-service/{id}/edit', name: 'app_admin_additionalservice_edit', defaults: ['duplicate' => false])]
#[Route('/admin/additional-service/{id}/duplicate', name: 'app_admin_additionalservice_duplicate', defaults: ['duplicate' => true])]
public function index(AdditionalService $additionalService, bool $duplicate, Request $request): Response
{
$accommodation = $additionalService->getAccommodation();
if (true === $duplicate) {
$additionalService = clone $additionalService;
}
$form = $this->createForm(AdditionalServiceType::class, $additionalService, ['currency' => $accommodation->getCurrency()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (true === $duplicate) {
$accommodation->addAdditionalService($additionalService);
}
$this->entityManager->persist($additionalService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Zusatzleistung wurde aktualisiert');
$this->logger->info('Edited additional service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $additionalService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/additional_service/edit.html.twig', [
'accommodation' => $accommodation,
'additionalService' => $additionalService,
'form' => $form,
'duplicate' => $duplicate,
]);
}
}
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\AdditionalService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\Accommodation;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class SortingController extends AbstractController
{
use SortingControllerTrait;
public function __construct(private readonly EntityManagerInterface $entityManager)
{
}
#[Route('/admin/additional-service/sort/{id}', name: 'app_admin_additionalservice_sort', methods: ['POST'])]
public function index(Accommodation $accommodation, Request $request): Response
{
$this->applySorting($accommodation->getAdditionalServices(), $request->request->all('sorting'));
$this->entityManager->flush();
return new Response('', Response::HTTP_NO_CONTENT);
}
}
@@ -1,148 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\AdditionalService;
use App\Form\Admin\Groups\AdditionalServiceType;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class AdditionalServiceController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/additional-service/{id}/create', name: 'app_admin_additionalservice_create')]
public function create(Accommodation $accommodation, Request $request): Response
{
$additionalService = new AdditionalService();
$form = $this->getForm($additionalService, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accommodation->addAdditionalService($additionalService);
$this->entityManager->persist($additionalService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Zusatzleistung wurde angelegt');
$this->logger->info('Created additional service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $additionalService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/additional_service/create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
#[Route('/admin/additional-service/{id}/edit', name: 'app_admin_additionalservice_edit', defaults: ['duplicate' => false])]
#[Route('/admin/additional-service/{id}/duplicate', name: 'app_admin_additionalservice_duplicate', defaults: ['duplicate' => true])]
public function edit(AdditionalService $additionalService, bool $duplicate, Request $request): Response
{
$accommodation = $additionalService->getAccommodation();
if (true === $duplicate) {
$additionalService = clone $additionalService;
}
$form = $this->getForm($additionalService, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (true === $duplicate) {
$accommodation->addAdditionalService($additionalService);
}
$this->entityManager->persist($additionalService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Zusatzleistung wurde aktualisiert');
$this->logger->info('Edited additional service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $additionalService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/additional_service/edit.html.twig', [
'accommodation' => $accommodation,
'additionalService' => $additionalService,
'form' => $form,
'duplicate' => $duplicate,
]);
}
#[Route('/admin/additional-service/{id}/delete', name: 'app_admin_additionalservice_delete')]
public function delete(AdditionalService $additionalService, Request $request): Response
{
$accommodation = $additionalService->getAccommodation();
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($additionalService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Zusatzleistung wurde gelöscht');
$this->logger->info('Deleted additional service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $additionalService->getLabel(),
]);
$returnUrl = $this->generateUrl('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/additional_service/modal_delete.html.twig', [
'additionalService' => $additionalService,
'accommodation' => $accommodation,
]);
}
#[Route('/admin/additional-service/sort/{id}', name: 'app_admin_additionalservice_sort', methods: ['POST'])]
public function sort(Accommodation $accommodation, Request $request): Response
{
$this->applySorting($accommodation->getAdditionalServices(), $request->request->all('sorting'));
$this->entityManager->flush();
return new Response('', Response::HTTP_NO_CONTENT);
}
private function getForm(AdditionalService $additionalService, ?Accommodation $accommodation): FormInterface
{
return $this->createForm(AdditionalServiceType::class, $additionalService, ['currency' => $accommodation->getCurrency()]);
}
}
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BoardService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\BoardService;
use App\Form\Admin\Groups\BoardServiceType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CreateController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/board-service/{id}/create', name: 'app_admin_boardservice_create')]
public function index(Accommodation $accommodation, Request $request): Response
{
$boardService = new BoardService();
$form = $this->createForm(BoardServiceType::class, $boardService, ['currency' => $accommodation->getCurrency()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accommodation->addBoardService($boardService);
$this->entityManager->persist($boardService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Verpflegungsleistung wurde angelegt');
$this->logger->info('Created board service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $boardService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/board_service/create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
}
@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BoardService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\BoardService;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class DeleteController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/board-service/{id}/delete', name: 'app_admin_boardservice_delete')]
public function index(BoardService $boardService, Request $request): Response
{
$accommodation = $boardService->getAccommodation();
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($boardService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Verpflegungsleistung wurde gelöscht');
$this->logger->info('Deleted board service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $boardService->getLabel(),
]);
$returnUrl = $this->generateUrl('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/board_service/modal_delete.html.twig', [
'boardService' => $boardService,
'accommodation' => $accommodation,
]);
}
}
@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BoardService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\BoardService;
use App\Form\Admin\Groups\BoardServiceType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class EditController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/board-service/{id}/edit', name: 'app_admin_boardservice_edit', defaults: ['duplicate' => false])]
#[Route('/admin/board-service/{id}/duplicate', name: 'app_admin_boardservice_duplicate', defaults: ['duplicate' => true])]
public function index(BoardService $boardService, bool $duplicate, Request $request): Response
{
$accommodation = $boardService->getAccommodation();
if (true === $duplicate) {
$boardService = clone $boardService;
}
$form = $this->createForm(BoardServiceType::class, $boardService, ['currency' => $accommodation->getCurrency()]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (true === $duplicate) {
$accommodation->addBoardService($boardService);
}
$this->entityManager->persist($boardService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Verpflegungsleistung wurde aktualisiert');
$this->logger->info('Edited board service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $boardService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/board_service/edit.html.twig', [
'accommodation' => $accommodation,
'boardService' => $boardService,
'form' => $form,
'duplicate' => $duplicate,
]);
}
}
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BoardService;
use App\Controller\Traits\SortingControllerTrait;
use App\Entity\Groups\Accommodation;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class SortingController extends AbstractController
{
use SortingControllerTrait;
public function __construct(private readonly EntityManagerInterface $entityManager)
{
}
#[Route('/admin/board-service/sort/{id}', name: 'app_admin_boardservice_sort', methods: ['POST'])]
public function index(Accommodation $accommodation, Request $request): Response
{
$this->applySorting($accommodation->getBoardServices(), $request->request->all('sorting'));
$this->entityManager->flush();
return new Response('', Response::HTTP_NO_CONTENT);
}
}
@@ -1,147 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\BoardService;
use App\Form\Admin\Groups\BoardServiceType;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class BoardServiceController extends AbstractController
{
use SortingControllerTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/board-service/{id}/create', name: 'app_admin_boardservice_create')]
public function create(Accommodation $accommodation, Request $request): Response
{
$boardService = new BoardService();
$form = $this->getForm($boardService, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accommodation->addBoardService($boardService);
$this->entityManager->persist($boardService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Verpflegungsleistung wurde angelegt');
$this->logger->info('Created board service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $boardService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/board_service/create.html.twig', [
'accommodation' => $accommodation,
'form' => $form,
]);
}
#[Route('/admin/board-service/{id}/edit', name: 'app_admin_boardservice_edit', defaults: ['duplicate' => false])]
#[Route('/admin/board-service/{id}/duplicate', name: 'app_admin_boardservice_duplicate', defaults: ['duplicate' => true])]
public function edit(BoardService $boardService, bool $duplicate, Request $request): Response
{
$accommodation = $boardService->getAccommodation();
if (true === $duplicate) {
$boardService = clone $boardService;
}
$form = $this->getForm($boardService, $accommodation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (true === $duplicate) {
$accommodation->addBoardService($boardService);
}
$this->entityManager->persist($boardService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Verpflegungsleistung wurde aktualisiert');
$this->logger->info('Edited board service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $boardService->getLabel(),
]);
return $this->redirectToRoute('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
}
return $this->render('admin/board_service/edit.html.twig', [
'accommodation' => $accommodation,
'boardService' => $boardService,
'form' => $form,
'duplicate' => $duplicate,
]);
}
#[Route('/admin/board-service/{id}/delete', name: 'app_admin_boardservice_delete')]
public function delete(BoardService $boardService, Request $request): Response
{
$accommodation = $boardService->getAccommodation();
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($boardService);
$this->entityManager->flush();
$this->addFlash('success', 'Die Verpflegungsleistung wurde gelöscht');
$this->logger->info('Deleted board service', [
'name' => $accommodation->getName(),
'code' => $accommodation->getCode(),
'label' => $boardService->getLabel(),
]);
$returnUrl = $this->generateUrl('app_admin_accommodation_edit', [
'id' => $accommodation->getId(),
]);
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/board_service/modal_delete.html.twig', [
'boardService' => $boardService,
'accommodation' => $accommodation,
]);
}
#[Route('/admin/board-service/sort/{id}', name: 'app_admin_boardservice_sort', methods: ['POST'])]
public function sort(Accommodation $accommodation, Request $request): Response
{
$this->applySorting($accommodation->getBoardServices(), $request->request->all('sorting'));
$this->entityManager->flush();
return new Response('', Response::HTTP_NO_CONTENT);
}
private function getForm(BoardService $boardService, ?Accommodation $accommodation): FormInterface
{
return $this->createForm(BoardServiceType::class, $boardService, ['currency' => $accommodation->getCurrency()]);
}
}
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BookingEditDraft;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\BookingEditDraft;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class DeleteController extends AbstractController
{
use ReturnUrlTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $adminLogger,
) {
}
#[Route('/admin/booking-edit-draft/{id}/delete', name: 'app_admin_bookingeditdraft_delete')]
public function index(BookingEditDraft $draft, Request $request): Response
{
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($draft);
$this->entityManager->flush();
$this->adminLogger->info('Delete booking edit draft', [
'booking_number' => $draft->getBookingNumber(),
]);
$this->addFlash('success', 'Der Buchungsentwurf wurde gelöscht');
$returnUrl = $this->getReturnUrl($request, 'app_admin_bookingeditdraft');
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/booking_edit_draft/modal_delete.html.twig', [
'draft' => $draft,
]);
}
}
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BookingEditDraft;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\BookingEditDraft;
use App\Service\BookingExporter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ExportController extends AbstractController
{
use ReturnUrlTrait;
public function __construct(private readonly BookingExporter $bookingExporter)
{
}
#[Route('/admin/booking-edit-draft/{id}/export', name: 'app_admin_bookingeditdraft_export')]
public function index(BookingEditDraft $draft): Response
{
if (false === $draft->hasExportData()) {
$this->addFlash('warning', 'Der Export ist fehlgeschlagen');
return $this->redirectToRoute('app_admin_bookingeditdraft');
}
try {
return $this->bookingExporter->createExportResponse($draft);
} catch (\RuntimeException $e) {
$this->addFlash('warning', 'Der Export ist fehlgeschlagen: '.$e->getMessage());
return $this->redirectToRoute('app_admin_bookingeditdraft');
}
}
}
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BookingEditDraft;
use App\Controller\Traits\ReturnUrlTrait;
use App\Repository\BookingEditDraftRepository;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class IndexController extends AbstractController
{
use ReturnUrlTrait;
public function __construct(
private readonly BookingEditDraftRepository $bookingEditDraftRepository,
private readonly PaginatorInterface $paginator,
) {
}
#[Route('/admin/booking-edit-draft', name: 'app_admin_bookingeditdraft')]
public function index(Request $request): Response
{
$qb = $this
->bookingEditDraftRepository
->createQueryBuilder('booking_edit_draft')
->leftJoin('booking_edit_draft.user', 'user')
;
$pagination = $this->paginator->paginate(
$qb,
$request->query->getInt('page', 1),
$request->query->getInt('limit', 20),
[
'defaultSortFieldName' => 'booking_edit_draft.createdAt',
'defaultSortDirection' => 'DESC',
]
);
return $this->render('admin/booking_edit_draft/index.html.twig', [
'pagination' => $pagination,
]);
}
}
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\BookingEditDraft;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\BookingEditDraft;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ShowController extends AbstractController
{
use ReturnUrlTrait;
#[Route('/admin/booking-edit-draft/{id}/show', name: 'app_admin_bookingeditdraft_show')]
public function index(BookingEditDraft $draft, Request $request): Response
{
$returnUrl = $this->getReturnUrl($request, 'app_admin_bookingeditdraft');
return $this->render('admin/booking_edit_draft/show.html.twig', [
'draft' => $draft,
'returnUrl' => $returnUrl,
]);
}
}
@@ -1,107 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\BookingEditDraft;
use App\Htmx\HxRedirectResponse;
use App\Repository\BookingEditDraftRepository;
use App\Service\BookingExporter;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class BookingEditDraftController extends AbstractController
{
use ReturnUrlTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly BookingEditDraftRepository $bookingEditDraftRepository,
private readonly PaginatorInterface $paginator,
private readonly BookingExporter $bookingExporter,
private readonly LoggerInterface $adminLogger,
) {
}
#[Route('/admin/booking-edit-draft', name: 'app_admin_bookingeditdraft')]
public function index(Request $request): Response
{
$qb = $this
->bookingEditDraftRepository
->createQueryBuilder('booking_edit_draft')
->leftJoin('booking_edit_draft.user', 'user')
;
$pagination = $this->paginator->paginate(
$qb,
$request->query->getInt('page', 1),
$request->query->getInt('limit', 20),
[
'defaultSortFieldName' => 'booking_edit_draft.createdAt',
'defaultSortDirection' => 'DESC',
]
);
return $this->render('admin/booking_edit_draft/index.html.twig', [
'pagination' => $pagination,
]);
}
#[Route('/admin/booking-edit-draft/{id}/show', name: 'app_admin_bookingeditdraft_show')]
public function show(BookingEditDraft $draft, Request $request): Response
{
$returnUrl = $this->getReturnUrl($request, 'app_admin_bookingeditdraft');
return $this->render('admin/booking_edit_draft/show.html.twig', [
'draft' => $draft,
'returnUrl' => $returnUrl,
]);
}
#[Route('/admin/booking-edit-draft/{id}/delete', name: 'app_admin_bookingeditdraft_delete')]
public function delete(BookingEditDraft $draft, Request $request): Response
{
if (true === $request->isMethod(Request::METHOD_POST)) {
$this->entityManager->remove($draft);
$this->entityManager->flush();
$this->adminLogger->info('Delete booking edit draft', [
'booking_number' => $draft->getBookingNumber(),
]);
$this->addFlash('success', 'Der Buchungsentwurf wurde gelöscht');
$returnUrl = $this->getReturnUrl($request, 'app_admin_bookingeditdraft');
return new HxRedirectResponse($returnUrl);
}
return $this->render('admin/booking_edit_draft/modal_delete.html.twig', [
'draft' => $draft,
]);
}
#[Route('/admin/booking-edit-draft/{id}/export', name: 'app_admin_bookingeditdraft_export')]
public function export(BookingEditDraft $draft): Response
{
if (false === $draft->hasExportData()) {
$this->addFlash('warning', 'Der Export ist fehlgeschlagen');
return $this->redirectToRoute('app_admin_bookingeditdraft');
}
try {
return $this->bookingExporter->createExportResponse($draft);
} catch (\RuntimeException $e) {
$this->addFlash('warning', 'Der Export ist fehlgeschlagen: '.$e->getMessage());
return $this->redirectToRoute('app_admin_bookingeditdraft');
}
}
}
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Log;
use App\Service\XmlDumpReader;
use League\Flysystem\FilesystemException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Attribute\Route;
class DownloadController extends AbstractController
{
public function __construct(private readonly XmlDumpReader $xmlDumpReader)
{
}
#[Route('/admin/log/download/{filename}', name: 'app_admin_log_xmldump_download', requirements: ['filename' => '.+'])]
public function index(string $filename): Response
{
try {
if (false === $this->xmlDumpReader->fileExists($filename)) {
throw $this->createNotFoundException('Dump file not found. It may have been cleaned up.');
}
$content = $this->xmlDumpReader->getContent($filename);
} catch (FilesystemException $e) {
throw $this->createNotFoundException('Failed to read dump file: '.$e->getMessage());
}
$response = new Response($content);
$response->headers->set('Content-Type', 'application/xml');
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
basename($filename)
);
$response->headers->set('Content-Disposition', $disposition);
return $response;
}
}
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Log;
use App\Repository\LogEntryRepository;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class IndexController extends AbstractController
{
public function __construct(
private readonly LogEntryRepository $logEntryRepository,
private readonly PaginatorInterface $paginator,
) {
}
#[Route('/admin/log', name: 'app_admin_log')]
public function index(Request $request): Response
{
$qb = $this
->logEntryRepository
->createQueryBuilder('log_entry')
;
$pagination = $this->paginator->paginate(
$qb,
$request->query->getInt('page', 1),
$request->query->getInt('limit', 50),
[
'defaultSortFieldName' => 'log_entry.createdAt',
'defaultSortDirection' => 'DESC',
]
);
return $this->render('admin/log/index.html.twig', [
'pagination' => $pagination,
]);
}
}
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin\Log;
use App\Entity\LogEntry;
use App\Service\XmlDumpReader;
use League\Flysystem\FilesystemException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class XmlDumpController extends AbstractController
{
public function __construct(private readonly XmlDumpReader $xmlDumpReader)
{
}
#[Route('/admin/log/{id}/xml-dumps', name: 'app_admin_log_xmldumps')]
public function index(LogEntry $logEntry): Response
{
$dumps = [];
try {
$dumps = $this->xmlDumpReader->findDumpsForRequestId($logEntry->getRequestId());
} catch (FilesystemException) {
}
return $this->render('admin/log/xml_dumps.html.twig', [
'logEntry' => $logEntry,
'dumps' => $dumps,
]);
}
}
-90
View File
@@ -1,90 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Log;
use App\Entity\LogEntry;
use App\Repository\LogEntryRepository;
use App\Service\XmlDumpReader;
use Knp\Component\Pager\PaginatorInterface;
use League\Flysystem\FilesystemException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Attribute\Route;
class LogController extends AbstractController
{
public function __construct(
private readonly LogEntryRepository $logEntryRepository,
private readonly PaginatorInterface $paginator,
private readonly XmlDumpReader $xmlDumpReader,
) {
}
#[Route('/admin/log', name: 'app_admin_log')]
public function index(Request $request): Response
{
$qb = $this
->logEntryRepository
->createQueryBuilder('log_entry')
;
$pagination = $this->paginator->paginate(
$qb,
$request->query->getInt('page', 1),
$request->query->getInt('limit', 50),
[
'defaultSortFieldName' => 'log_entry.createdAt',
'defaultSortDirection' => 'DESC',
]
);
return $this->render('admin/log/index.html.twig', [
'pagination' => $pagination,
]);
}
#[Route('/admin/log/{id}/xml-dumps', name: 'app_admin_log_xmldumps')]
public function xmlDumps(LogEntry $logEntry): Response
{
$dumps = [];
try {
$dumps = $this->xmlDumpReader->findDumpsForRequestId($logEntry->getRequestId());
} catch (FilesystemException) {
}
return $this->render('admin/log/xml_dumps.html.twig', [
'logEntry' => $logEntry,
'dumps' => $dumps,
]);
}
#[Route('/admin/log/download/{filename}', name: 'app_admin_log_xmldump_download', requirements: ['filename' => '.+'])]
public function downloadXmlDump(string $filename): Response
{
try {
if (false === $this->xmlDumpReader->fileExists($filename)) {
throw $this->createNotFoundException('Dump file not found. It may have been cleaned up.');
}
$content = $this->xmlDumpReader->getContent($filename);
} catch (FilesystemException $e) {
throw $this->createNotFoundException('Failed to read dump file: '.$e->getMessage());
}
$response = new Response($content);
$response->headers->set('Content-Type', 'application/xml');
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
basename($filename)
);
$response->headers->set('Content-Disposition', $disposition);
return $response;
}
}
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Controller\Admin;
namespace App\Controller\Admin\User;
use App\Repository\UserRepository;
use Knp\Component\Pager\PaginatorInterface;
@@ -11,7 +11,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class UserController extends AbstractController
class IndexController extends AbstractController
{
public function __construct(
private readonly UserRepository $userRepository,
@@ -1,6 +1,6 @@
<?php
namespace App\Controller\Admin;
namespace App\Controller\Traits;
use App\Entity\Groups\SortableEntityInterface;
+16 -1
View File
@@ -6,11 +6,11 @@ use App\Entity\BlameableEntity;
use App\Entity\BlameableEntityInterface;
use App\Entity\TimestampableEntity;
use App\Entity\TimestampableEntityInterface;
use App\Enum\Groups\Season;
use App\Repository\Groups\AccommodationPriceRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ORM\Entity(repositoryClass: AccommodationPriceRepository::class)]
class AccommodationPrice implements BlameableEntityInterface, TimestampableEntityInterface
@@ -36,6 +36,9 @@ class AccommodationPrice implements BlameableEntityInterface, TimestampableEntit
#[Assert\GreaterThan(propertyPath: 'dateFrom', message: 'Das Bis-Datum muss nach dem Von-Datum liegen')]
private ?\DateTimeImmutable $dateTo = null;
#[ORM\Column(length: 20, enumType: Season::class)]
private ?Season $season = null;
#[ORM\Column]
#[Assert\NotNull(message: 'required')]
private ?int $includedPax = null;
@@ -107,6 +110,18 @@ class AccommodationPrice implements BlameableEntityInterface, TimestampableEntit
return $this;
}
public function getSeason(): ?Season
{
return $this->season;
}
public function setSeason(?Season $season): self
{
$this->season = $season;
return $this;
}
public function getIncludedPax(): ?int
{
return $this->includedPax;
+20
View File
@@ -0,0 +1,20 @@
<?php
namespace App\Enum\Groups;
enum Season: string
{
case ADV_SECONDARY = 'adv_secondary';
case SECONDARY = 'secondary';
case PEAK = 'peak';
public function label(): string
{
return 'enum.season.'.$this->value.'.label';
}
public function token(): string
{
return 'enum.season.'.$this->value.'.token';
}
}
@@ -5,9 +5,11 @@ declare(strict_types=1);
namespace App\Form\Admin\Groups;
use App\Entity\Groups\AccommodationPrice;
use App\Enum\Groups\Season;
use App\Form\DatepickerType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EnumType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -28,6 +30,11 @@ class AccommodationPriceType extends AbstractType
'html5' => true,
'widget' => 'single_text',
])
->add('season', EnumType::class, [
'label' => 'Saison',
'class' => Season::class,
'choice_label' => fn($item) => $item->token(),
])
->add('includedPax', IntegerType::class, [
'label' => 'Inklusiv-Personen',
])
+1 -1
View File
@@ -27,7 +27,7 @@ class AccommodationType extends AbstractType
'label' => 'Mindestbelegung Sommer',
])
->add('maxAdolescentAge', IntegerType::class, [
'label' => 'Altersgrenze Jugendliche (6-X Jahre)',
'label' => 'Altersgrenze Jugendliche R',
])
->add('currency', ChoiceType::class, [
'label' => 'Währung',
+45 -57
View File
@@ -1,16 +1,31 @@
{% form_theme form 'forms_admin.html.twig' %}
<h2 class="text-xl font-bold">
Allgemein
</h2>
{{ form_start(form) }}
<div class="grid lg:grid-cols-2 gap-y-4 lg:gap-x-8">
{{ form_row(form.name) }}
{{ form_row(form.code) }}
{{ form_row(form.minPaxSummer) }}
{{ form_row(form.maxAdolescentAge) }}
{{ form_row(form.currency) }}
<div class="grid lg:grid-cols-2 lg:gap-x-8 items-start">
<div class="grid lg:grid-cols-2 gap-y-4 lg:gap-x-4">
<div class="lg:col-span-2">
{{ form_row(form.name) }}
</div>
{{ form_row(form.code) }}
{{ form_row(form.minPaxSummer) }}
{{ form_row(form.maxAdolescentAge) }}
{{ form_row(form.currency) }}
</div>
{% if cmsData is defined and cmsData.name is defined %}
<div class="space-y-4">
{% if cmsData.images.resized.m | length > 0 %}
{% set image = cmsData.images.resized.m[0] %}
<div class="max-w-64">
<img src="{{ image.url }}" alt="{{ image.alt }}" class="block w-full h-auto">
</div>
{% endif %}
<div>
<strong>{{ cmsData.name }}</strong>
<br>
{{ cmsData.address | default('-') | nl2br }}
</div>
</div>
{% endif %}
</div>
<div class="flex justify-between pt-8">
<a href="{{ path('app_admin_accommodation') }}" class="button button--secondary button--small">
@@ -39,16 +54,22 @@
<tr>
<th></th>
<th>
Datums-Bereich
von
</th>
<th>
Preis pro Nacht
bis
</th>
<th>
Preis weitere Person
Saison
</th>
<th>
Mindestbelegung (Nächte)
Pax bis
</th>
<th>
Mindestmiete pro Nacht
</th>
<th>
weitere Personen pro Nacht
</th>
<th>
Unterbelegung
@@ -61,7 +82,16 @@
<tr>
<td></td>
<td>
{{ price.dateFrom | date('d.m.Y') }} - {{ price.dateTo | date('d.m.Y') }}
{{ price.dateFrom | date('d.m.Y') }}
</td>
<td>
{{ price.dateTo | date('d.m.Y') }}
</td>
<td>
{{ price.season.token | trans }}
</td>
<td>
{{ price.includedPax }}
</td>
<td>
{{ (price.effectivePricePerNight / 100) | format_currency(accommodation.currency) }}
@@ -75,9 +105,6 @@
<span class="line-through text-xs">{{ (price.priceAdditionalPerson / 100) | format_currency(accommodation.currency) }}</span>
{% endif %}
</td>
<td>
{{ price.minNights }}
</td>
<td>
{% if price.acceptUndersubscription %}
{{ icon('check', 'w-4 h-4') }}
@@ -259,42 +286,3 @@
neu
</a>
</div>
{% if cmsData is defined and cmsData.success is true %}
<hr class="my-8">
<h2 class="text-xl font-bold">
CMS-Daten
</h2>
<div class="grid lg:grid-cols-2 gap-y-4 lg:gap-x-8">
<div class="space-y-4">
<div>
<h3 class="text-lg font-bold">
Adresse
</h3>
<strong>{{ cmsData.name }}</strong>
<br>
{{ cmsData.address | default('-') | nl2br }}
</div>
<div>
<h3 class="text-lg font-bold">
Beschreibung
</h3>
<div class="[&_p]:pb-4">
{{ cmsData.description | default('-') | raw }}
</div>
</div>
</div>
<div>
<h3 class="text-lg font-bold">
Bilder
</h3>
<div class="grid grid-cols-4 gap-4">
{% for image in cmsData.images.resized.s %}
<img src="{{ image.url }}" alt="{{ image.alt }}" class="block w-full h-auto">
{% endfor %}
</div>
</div>
</div>
{% endif %}
+10
View File
@@ -19,6 +19,16 @@ enum:
per_person: pro Person
per_night: pro Nacht
per_person_per_night: pro Person und Nacht
season:
peak:
label: Hauptsaison
token: HS
secondary:
label: Nebensaison
token: NS
adv_secondary:
label: Vorteils-Nebensaison
token: VNS
paginator:
previous: vorherige