diff --git a/phpstan.neon b/phpstan.neon index 28c7b526..f88ac00d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2760,16 +2760,6 @@ parameters: count: 1 path: src/EventSubscriber/Actions/DashboardSubscriber.php - - - message: "#^Cannot access offset 'document' on mixed\\.$#" - count: 1 - path: src/EventSubscriber/Actions/InvoiceDocumentSubscriber.php - - - - message: "#^Cannot access offset 'token' on mixed\\.$#" - count: 1 - path: src/EventSubscriber/Actions/InvoiceDocumentSubscriber.php - - message: "#^Cannot access offset 'invoice' on mixed\\.$#" count: 1 diff --git a/src/Controller/InvoiceController.php b/src/Controller/InvoiceController.php index 0f0b7525..f8e31455 100644 --- a/src/Controller/InvoiceController.php +++ b/src/Controller/InvoiceController.php @@ -447,6 +447,36 @@ final class InvoiceController extends AbstractController return $this->renderTemplateForm($template, $request); } + #[Route(path: '/document_reload/{document}', name: 'admin_invoice_document_reload', methods: ['GET', 'POST'])] + #[IsGranted('upload_invoice_template')] + public function reloadDocument(string $document, Environment $twig): Response + { + $event = new InvoiceDocumentsEvent($this->service->getDocuments(true)); + $this->dispatcher->dispatch($event); + + $reloaded = false; + + foreach ($event->getInvoiceDocuments() as $doc) { + if ($document === $doc->getId() && $doc->isTwig()) { + $reloaded = true; + try { + $twig->enableAutoReload(); + $twig->load('@invoice/' . basename($doc->getFilename())); + $twig->disableAutoReload(); + $this->flashSuccess('Reloaded template'); + } catch (Exception $ex) { + $this->flashException($ex, 'Failed to reload template: ' . $ex->getMessage()); + } + } + } + + if (!$reloaded) { + throw $this->createNotFoundException('Unknown document: ' . $document); + } + + return $this->redirectToRoute('admin_invoice_document_upload'); + } + #[Route(path: '/document_upload', name: 'admin_invoice_document_upload', methods: ['GET', 'POST'])] #[IsGranted('upload_invoice_template')] public function uploadDocumentAction(Request $request, string $projectDirectory, InvoiceDocumentRepository $documentRepository, Environment $twig, SystemConfiguration $systemConfiguration): Response diff --git a/src/EventSubscriber/Actions/InvoiceDocumentSubscriber.php b/src/EventSubscriber/Actions/InvoiceDocumentSubscriber.php index a654edaf..c7a319f6 100644 --- a/src/EventSubscriber/Actions/InvoiceDocumentSubscriber.php +++ b/src/EventSubscriber/Actions/InvoiceDocumentSubscriber.php @@ -21,17 +21,34 @@ final class InvoiceDocumentSubscriber extends AbstractActionsSubscriber public function onActions(PageActionsEvent $event): void { + /** @var array $payload */ $payload = $event->getPayload(); + if (!\is_array($payload)) { + return; + } /** @var InvoiceDocument|null $document */ - $document = $payload['document']; + $document = \array_key_exists('document', $payload) ? $payload['document'] : null; if ($document === null) { return; } - if ($this->isGranted('manage_invoice_template')) { - $event->addDelete($this->path('invoice_document_delete', ['id' => $document->getId(), 'token' => $payload['token']]), false); + if (!$this->isGranted('manage_invoice_template')) { + return; + } + + /** @var bool $inUse */ + $inUse = \array_key_exists('in_use', $payload) ? $payload['in_use'] : false; + /** @var string $token */ + $token = \array_key_exists('token', $payload) ? $payload['token'] : null; + + if (!$inUse) { + $event->addDelete($this->path('invoice_document_delete', ['id' => $document->getId(), 'token' => $token]), false); + } + + if ($document->isTwig()) { + $event->addAction('Reload', ['url' => $this->path('admin_invoice_document_reload', ['document' => $document->getId()])]); } } } diff --git a/src/Model/InvoiceDocument.php b/src/Model/InvoiceDocument.php index 0f04a454..36b67536 100644 --- a/src/Model/InvoiceDocument.php +++ b/src/Model/InvoiceDocument.php @@ -37,6 +37,11 @@ final class InvoiceDocument return $path; } + public function isTwig(): bool + { + return $this->getFileExtension() === 'twig'; + } + public function getFileExtension(): string { return $this->file->getExtension(); diff --git a/templates/invoice/actions.html.twig b/templates/invoice/actions.html.twig index 609ceb4d..17335f1f 100644 --- a/templates/invoice/actions.html.twig +++ b/templates/invoice/actions.html.twig @@ -11,8 +11,8 @@ {{ widgets.table_actions(event.actions) }} {% endmacro %} -{% macro invoice_document(document, view) %} +{% macro invoice_document(document, inUse, view) %} {% import "macros/widgets.html.twig" as widgets %} - {% set event = actions(app.user, 'invoice_document', view, {'document': document, 'token': csrf_token('invoice.delete_document')}) %} + {% set event = actions(app.user, 'invoice_document', view, {'document': document, 'in_use': inUse, 'token': csrf_token('invoice.delete_document')}) %} {{ widgets.table_actions(event.actions) }} {% endmacro %} diff --git a/templates/invoice/document_upload.html.twig b/templates/invoice/document_upload.html.twig index 41baa79a..eeb138d2 100644 --- a/templates/invoice/document_upload.html.twig +++ b/templates/invoice/document_upload.html.twig @@ -1,6 +1,11 @@ {% extends 'base.html.twig' %} {% import "macros/widgets.html.twig" as widgets %} +{% block status %} + {% from "macros/status.html.twig" import status_count %} + {{ status_count(documents|length) }} +{% endblock %} + {% block main %} {% if can_upload and form is not null %} {% embed '@theme/embeds/card.html.twig' %} @@ -60,9 +65,7 @@ {% endif %} - {% if not config.used %} - {{ actions.invoice_document(document, 'index') }} - {% endif %} + {{ actions.invoice_document(document, config.used, 'index') }} {% endfor %}