feat: remove easy admin bundle, adopt admin theme
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Admin\Field\JsonDataField;
|
||||
use App\Entity\BookingEditDraft;
|
||||
use App\Entity\User;
|
||||
use App\Service\BookingExporter;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
/** @extends AbstractCrudController<BookingEditDraft> */
|
||||
class BookingEditDraftCrudController extends AbstractCrudController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly BookingExporter $exportService,
|
||||
private readonly AdminUrlGenerator $adminUrlGenerator,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function getEntityFqcn(): string
|
||||
{
|
||||
return BookingEditDraft::class;
|
||||
}
|
||||
|
||||
public function configureActions(Actions $actions): Actions
|
||||
{
|
||||
$exportAction = Action::new('exportExcel', 'Excel Export', 'fa fa-file-excel')
|
||||
->linkToRoute(
|
||||
'admin_booking_draft_export',
|
||||
static fn (BookingEditDraft $entity): array => ['id' => $entity->getId()]
|
||||
)
|
||||
->displayIf(static fn (BookingEditDraft $entity): bool => $entity->hasExportData());
|
||||
|
||||
return $actions
|
||||
->add(Crud::PAGE_INDEX, Action::DETAIL)
|
||||
->add(Crud::PAGE_INDEX, $exportAction)
|
||||
->add(Crud::PAGE_DETAIL, $exportAction)
|
||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
||||
->remove(Crud::PAGE_DETAIL, Action::EDIT)
|
||||
;
|
||||
}
|
||||
|
||||
#[Route('/admin/booking-draft/{id}/export', name: 'admin_booking_draft_export', requirements: ['id' => '\d+'])]
|
||||
public function export(BookingEditDraft $draft): Response
|
||||
{
|
||||
if (false === $draft->hasExportData()) {
|
||||
$this->addFlash('danger', 'Export nicht möglich: Reisedaten fehlen');
|
||||
|
||||
$url = $this->adminUrlGenerator
|
||||
->setController(self::class)
|
||||
->setAction(Action::INDEX)
|
||||
->generateUrl();
|
||||
|
||||
return $this->redirect($url);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->exportService->createExportResponse($draft);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->addFlash('danger', 'Export fehlgeschlagen: '.$e->getMessage());
|
||||
|
||||
$url = $this->adminUrlGenerator
|
||||
->setController(self::class)
|
||||
->setAction(Action::INDEX)
|
||||
->generateUrl();
|
||||
|
||||
return $this->redirect($url);
|
||||
}
|
||||
}
|
||||
|
||||
public function configureCrud(Crud $crud): Crud
|
||||
{
|
||||
return $crud
|
||||
->setEntityLabelInSingular('Buchungsentwurf')
|
||||
->setEntityLabelInPlural('Buchungsentwürfe')
|
||||
->setDefaultSort(['createdAt' => 'DESC']);
|
||||
}
|
||||
|
||||
public function configureFields(string $pageName): iterable
|
||||
{
|
||||
return [
|
||||
IntegerField::new('bookingNumber', 'Vorgang'),
|
||||
AssociationField::new('user', 'Kundenaccount')->formatValue(fn (User $user) => $user->getEmail()),
|
||||
DateTimeField::new('createdAt', 'erstellt am'),
|
||||
DateTimeField::new('updatedAt', 'aktualisiert am'),
|
||||
JsonDataField::new('formData', 'Daten')->onlyOnDetail(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\BookingEditDraft;
|
||||
use App\Entity\LogEntry;
|
||||
use App\Entity\User;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\UserMenu;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
|
||||
class DashboardController extends AbstractDashboardController
|
||||
class DashboardController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/dashboard', name: 'app_admin_dashboard')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('admin/dashboard/index.html.twig');
|
||||
}
|
||||
|
||||
public function configureDashboard(): Dashboard
|
||||
{
|
||||
return Dashboard::new()
|
||||
->setTitle('MyE&P')
|
||||
->setLocales(['de'])
|
||||
->setFaviconPath('build/favicon/icon.svg')
|
||||
;
|
||||
}
|
||||
|
||||
public function configureUserMenu(UserInterface $user): UserMenu
|
||||
{
|
||||
return parent::configureUserMenu($user)
|
||||
->addMenuItems([
|
||||
MenuItem::linkToRoute('MyE&P', 'fa fa-user', 'app_account'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureMenuItems(): iterable
|
||||
{
|
||||
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
|
||||
yield MenuItem::linkToCrud('Log', 'fa fa-list', LogEntry::class);
|
||||
yield MenuItem::linkToCrud('Buchungsentwürfe', 'fa fa-pen-to-square', BookingEditDraft::class);
|
||||
yield MenuItem::linkToCrud('Benutzeraccounts', 'fa fa-users', User::class);
|
||||
return $this->render('admin/dashboard.html.twig');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Admin\Field\JsonDataField;
|
||||
use App\Entity\LogEntry;
|
||||
use App\Repository\LogEntryRepository;
|
||||
use App\Service\XmlDumpReader;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||
use League\Flysystem\FilesystemException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/** @extends AbstractCrudController<LogEntry> */
|
||||
class LogEntryCrudController extends AbstractCrudController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LogEntryRepository $logEntryRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function getEntityFqcn(): string
|
||||
{
|
||||
return LogEntry::class;
|
||||
}
|
||||
|
||||
public function configureActions(Actions $actions): Actions
|
||||
{
|
||||
$viewDumps = Action::new('viewDumps', 'XML Dumps', 'fa fa-file-code')
|
||||
->linkToCrudAction('xmlDumps')
|
||||
->displayIf(static fn (LogEntry $entity): bool => 'bpn' === $entity->getChannel());
|
||||
|
||||
return $actions
|
||||
->add(Crud::PAGE_INDEX, Action::DETAIL)
|
||||
->add(Crud::PAGE_INDEX, $viewDumps)
|
||||
->add(Crud::PAGE_DETAIL, $viewDumps)
|
||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
||||
->remove(Crud::PAGE_INDEX, Action::DELETE)
|
||||
->remove(Crud::PAGE_DETAIL, Action::EDIT)
|
||||
->remove(Crud::PAGE_DETAIL, Action::DELETE)
|
||||
;
|
||||
}
|
||||
|
||||
public function configureCrud(Crud $crud): Crud
|
||||
{
|
||||
return $crud
|
||||
->setEntityLabelInSingular('Logeintrag')
|
||||
->setEntityLabelInPlural('Logeinträge')
|
||||
->setDefaultSort(['createdAt' => 'DESC'])
|
||||
->setSearchFields(['errorCode', 'message', 'channel', 'extra']);
|
||||
}
|
||||
|
||||
public function configureFields(string $pageName): iterable
|
||||
{
|
||||
yield DateTimeField::new('createdAt', 'Zeitstempel');
|
||||
yield TextField::new('errorCode', 'Fehlercode')
|
||||
->formatValue(static fn (?string $value): string => $value ?? '-');
|
||||
yield TextField::new('username', 'Benutzer');
|
||||
yield TextField::new('message', 'Aktion');
|
||||
yield TextField::new('requestId', 'Request ID');
|
||||
yield TextField::new('uri', 'URI');
|
||||
yield JsonDataField::new('context', 'Kontext')->onlyOnDetail();
|
||||
yield JsonDataField::new('extra', 'Extra')->onlyOnDetail();
|
||||
}
|
||||
|
||||
public function xmlDumps(Request $request, XmlDumpReader $xmlDumpService): Response
|
||||
{
|
||||
$entityId = $request->query->getInt('entityId');
|
||||
if ($entityId <= 0) {
|
||||
throw $this->createNotFoundException('Log entry not found.');
|
||||
}
|
||||
|
||||
$entity = $this->logEntryRepository->find($entityId);
|
||||
if (!$entity instanceof LogEntry) {
|
||||
throw $this->createNotFoundException('Log entry not found.');
|
||||
}
|
||||
|
||||
$dumps = [];
|
||||
try {
|
||||
$dumps = $xmlDumpService->findDumpsForRequestId($entity->getRequestId());
|
||||
} catch (FilesystemException) {
|
||||
}
|
||||
|
||||
return $this->render('admin/xml_dump/list.html.twig', [
|
||||
'logEntry' => $entity,
|
||||
'requestId' => $entity->getRequestId(),
|
||||
'dumps' => $dumps,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Repository\UserRepository;
|
||||
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 UserController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepository,
|
||||
private readonly PaginatorInterface $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/user', name: 'app_admin_user')]
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$qb = $this
|
||||
->userRepository
|
||||
->createQueryBuilder('user')
|
||||
;
|
||||
|
||||
$pagination = $this->paginator->paginate(
|
||||
$qb,
|
||||
$request->query->getInt('page', 1),
|
||||
$request->query->getInt('limit', 50),
|
||||
[
|
||||
'defaultSortFieldName' => 'user.lastLoginAt',
|
||||
'defaultSortDirection' => 'DESC',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->render('admin/user/index.html.twig', [
|
||||
'pagination' => $pagination,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\User;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||
|
||||
/** @extends AbstractCrudController<User> */
|
||||
class UserCrudController extends AbstractCrudController
|
||||
{
|
||||
public static function getEntityFqcn(): string
|
||||
{
|
||||
return User::class;
|
||||
}
|
||||
|
||||
public function configureActions(Actions $actions): Actions
|
||||
{
|
||||
return $actions
|
||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
||||
->remove(Crud::PAGE_INDEX, Action::DELETE)
|
||||
;
|
||||
}
|
||||
|
||||
public function configureCrud(Crud $crud): Crud
|
||||
{
|
||||
return $crud
|
||||
->setEntityLabelInSingular('Benutzeraccount')
|
||||
->setEntityLabelInPlural('Benutzeraccounts')
|
||||
->setDefaultSort(['lastLoginAt' => 'DESC']);
|
||||
}
|
||||
|
||||
public function configureFields(string $pageName): iterable
|
||||
{
|
||||
return [
|
||||
TextField::new('email', 'E-Mail'),
|
||||
DateTimeField::new('lastLoginAt', 'letzter Login'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Repository\LogEntryRepository;
|
||||
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\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/admin/xml-dump')]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
class XmlDumpController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly XmlDumpReader $xmlDumpService,
|
||||
private readonly LogEntryRepository $logEntryRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'admin_xml_dump_list', methods: ['GET'])]
|
||||
public function list(int $id): Response
|
||||
{
|
||||
$logEntry = $this->logEntryRepository->find($id);
|
||||
|
||||
if (null === $logEntry) {
|
||||
throw new NotFoundHttpException('Log entry not found.');
|
||||
}
|
||||
|
||||
if ('bpn' !== $logEntry->getChannel()) {
|
||||
throw new NotFoundHttpException('XML dumps are only available for BPN channel entries.');
|
||||
}
|
||||
|
||||
$requestId = $logEntry->getRequestId();
|
||||
$dumps = [];
|
||||
|
||||
try {
|
||||
$dumps = $this->xmlDumpService->findDumpsForRequestId($requestId);
|
||||
} catch (FilesystemException) {
|
||||
// Dumps directory may not exist or be inaccessible
|
||||
}
|
||||
|
||||
return $this->render('admin/xml_dump/list.html.twig', [
|
||||
'logEntry' => $logEntry,
|
||||
'requestId' => $requestId,
|
||||
'dumps' => $dumps,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/download/{filename}', name: 'admin_xml_dump_download', methods: ['GET'], requirements: ['filename' => '.+'])]
|
||||
public function download(string $filename): Response
|
||||
{
|
||||
try {
|
||||
if (false === $this->xmlDumpService->fileExists($filename)) {
|
||||
throw new NotFoundHttpException('Dump file not found. It may have been cleaned up.');
|
||||
}
|
||||
|
||||
$content = $this->xmlDumpService->getContent($filename);
|
||||
} catch (FilesystemException $e) {
|
||||
throw new NotFoundHttpException('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,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Traits;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
trait ReturnUrlTrait
|
||||
{
|
||||
public function getReturnUrl(Request $request, string $defaultRoute, array $parameters = []): string
|
||||
{
|
||||
$defaultUrl = $this->generateUrl($defaultRoute, $parameters);
|
||||
|
||||
return rawurldecode($request->query->get('r', $defaultUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove specified query parameters from a URL.
|
||||
*
|
||||
* @param string $url The URL to process
|
||||
* @param string[] $parametersKeys Array of query parameter keys to remove
|
||||
*
|
||||
* @return string The URL without the specified query parameters
|
||||
*/
|
||||
public function removeQueryParameters(string $url, array $parametersKeys): string
|
||||
{
|
||||
if ([] === $parametersKeys) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$urlParts = parse_url($url);
|
||||
|
||||
if (false === isset($urlParts['query'])) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
parse_str($urlParts['query'], $queryParams);
|
||||
|
||||
foreach ($parametersKeys as $key) {
|
||||
unset($queryParams[$key]);
|
||||
}
|
||||
|
||||
$urlParts['query'] = http_build_query($queryParams);
|
||||
|
||||
if ('' === $urlParts['query']) {
|
||||
unset($urlParts['query']);
|
||||
}
|
||||
|
||||
// Rebuild URL
|
||||
$result = '';
|
||||
if (isset($urlParts['scheme'])) {
|
||||
$result .= $urlParts['scheme'].'://';
|
||||
}
|
||||
if (isset($urlParts['host'])) {
|
||||
$result .= $urlParts['host'];
|
||||
}
|
||||
if (isset($urlParts['port'])) {
|
||||
$result .= ':'.$urlParts['port'];
|
||||
}
|
||||
if (isset($urlParts['path'])) {
|
||||
$result .= $urlParts['path'];
|
||||
}
|
||||
if (isset($urlParts['query'])) {
|
||||
$result .= '?'.$urlParts['query'];
|
||||
}
|
||||
if (isset($urlParts['fragment'])) {
|
||||
$result .= '#'.$urlParts['fragment'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user