diff --git a/UPGRADING-3.md b/UPGRADING-3.md index 29a1e970f..d09871b2b 100644 --- a/UPGRADING-3.md +++ b/UPGRADING-3.md @@ -30,3 +30,6 @@ Do not use method chaining: all fluent interface, especially in Entities, are no - Removed and renamed translations, most important `action.edit` => `edit`, `my.profile` => `user_profile` - Removed `User::isExportDecimal()` - Use duration format `HH:mm` in default PDF exports +- Replace Twig `AppVariable` with custom implementation + - Replace `app.request.locale` with `app.locale` + - Replace `app.request.attributes.get('_route')` with `app.current_route` diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 72961c8e1..2f4254eef 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -5,6 +5,8 @@ twig: paths: '%kernel.project_dir%/templates/bundles/TablerBundle': theme '%kernel.project_dir%/vendor/kevinpapst/tabler-bundle/templates': theme + globals: + app: '@App\Twig\AppVariable' when@test: twig: diff --git a/config/services.yaml b/config/services.yaml index a66c0e174..0e21c7606 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -243,3 +243,7 @@ services: App\Validator\Constraints\QuickEntryTimesheetValidator: arguments: ['%kimai.validator_timesheet%'] + + App\Twig\AppVariable: + tags: + - {name: twig.global, alias: app} diff --git a/src/Controller/Reporting/ProjectDateRangeController.php b/src/Controller/Reporting/ProjectDateRangeController.php index 1e5fd17f1..c4bb9de8c 100644 --- a/src/Controller/Reporting/ProjectDateRangeController.php +++ b/src/Controller/Reporting/ProjectDateRangeController.php @@ -60,6 +60,7 @@ final class ProjectDateRangeController extends AbstractController } return $this->render('reporting/project/daterange.html.twig', [ + 'expand_projects' => $request->query->get('view', '1') === '1', 'report_title' => 'report_project_daterange', 'entries' => $byCustomer, 'form' => $form->createView(), diff --git a/src/Twig/AppVariable.php b/src/Twig/AppVariable.php new file mode 100644 index 000000000..c7ce782bf --- /dev/null +++ b/src/Twig/AppVariable.php @@ -0,0 +1,76 @@ +requestStack->getMainRequest()?->getLocale() ?? 'en'; + } + + public function getUser(): ?UserInterface + { + return $this->tokenStorage->getToken()?->getUser(); + } + + public function getCurrent_route(): ?string + { + return $this->requestStack->getCurrentRequest()->attributes->get('_route'); + } + + public function getFlashes(): array + { + $session = $this->getSession2(); + + if (!$session instanceof FlashBagAwareSessionInterface) { + return []; + } + + return $session->getFlashBag()->all(); + } + + private function getSession2(): ?SessionInterface + { + try { + if (null !== $session = $this->requestStack->getSession()) { + return $session; + } + } catch (\RuntimeException) { + } + + return null; + } + + /** + * The request should not be exposed under any circumstance to the frontend. + * This here is added as fallback for old customer templates still using this object. + */ + public function getRequest(): array + { + return [ + 'locale' => $this->getLocale(), + 'pathinfo' => $this->requestStack->getCurrentRequest()?->getPathInfo(), + ]; + } +} diff --git a/src/Twig/DatatableExtensions.php b/src/Twig/Runtime/DatatableExtensions.php similarity index 87% rename from src/Twig/DatatableExtensions.php rename to src/Twig/Runtime/DatatableExtensions.php index 94e2583ec..d7fb91946 100644 --- a/src/Twig/DatatableExtensions.php +++ b/src/Twig/Runtime/DatatableExtensions.php @@ -7,17 +7,16 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Runtime; use App\Entity\Bookmark; use App\Entity\User; use App\Repository\BookmarkRepository; use App\Utils\ProfileManager; -use Symfony\Component\HttpFoundation\Session\Session; -use Twig\Extension\AbstractExtension; -use Twig\TwigFunction; +use Symfony\Component\HttpFoundation\RequestStack; +use Twig\Extension\RuntimeExtensionInterface; -final class DatatableExtensions extends AbstractExtension +final class DatatableExtensions implements RuntimeExtensionInterface { /** * @var array>> @@ -26,18 +25,14 @@ final class DatatableExtensions extends AbstractExtension private array $tableNames = []; private ?string $prefix = null; - public function __construct(private BookmarkRepository $bookmarkRepository, private ProfileManager $profileManager) + public function __construct( + private readonly BookmarkRepository $bookmarkRepository, + private readonly ProfileManager $profileManager, + private readonly RequestStack $requestStack, + ) { } - public function getFunctions(): array - { - return [ - new TwigFunction('initialize_datatable', [$this, 'initializeDatatable']), - new TwigFunction('datatable_column_class', [$this, 'getDatatableColumnClass']), - ]; - } - private function getDatatableName(string $dataTable): string { if (!\array_key_exists($dataTable, $this->tableNames)) { @@ -47,10 +42,10 @@ final class DatatableExtensions extends AbstractExtension return $this->tableNames[$dataTable]; } - public function initializeDatatable(User $user, Session $session, string $dataTable, array $defaultColumns): array + public function initializeDatatable(User $user, string $dataTable, array $defaultColumns): array { if ($this->prefix === null) { - $this->prefix = $this->profileManager->getProfileFromSession($session); + $this->prefix = $this->profileManager->getProfileFromSession($this->requestStack->getSession()); $dataTable = $this->getDatatableName($dataTable); } @@ -97,7 +92,10 @@ final class DatatableExtensions extends AbstractExtension $this->dataTables[$dataTable] = $columns; } - return $this->dataTables[$dataTable]; + return [ + 'columns' => $this->dataTables[$dataTable], + 'profile' => $this->prefix, + ]; } public function getDatatableColumnClass(string $dataTable, string $column): string diff --git a/src/Twig/RuntimeExtensions.php b/src/Twig/RuntimeExtensions.php index 210ce47b7..893f9e23d 100644 --- a/src/Twig/RuntimeExtensions.php +++ b/src/Twig/RuntimeExtensions.php @@ -9,6 +9,7 @@ namespace App\Twig; +use App\Twig\Runtime\DatatableExtensions; use App\Twig\Runtime\EncoreExtension; use App\Twig\Runtime\MarkdownExtension; use App\Twig\Runtime\MenuExtension; @@ -40,6 +41,8 @@ final class RuntimeExtensions extends AbstractExtension new TwigFunction('icon', [RuntimeExtension::class, 'createIcon'], ['is_safe' => ['html']]), new TwigFunction('qr_code_data_uri', [QrCodeExtension::class, 'qrCodeDataUriFunction']), new TwigFunction('user_shortcuts', [MenuExtension::class, 'getUserShortcuts']), + new TwigFunction('initialize_datatable', [DatatableExtensions::class, 'initializeDatatable']), + new TwigFunction('datatable_column_class', [DatatableExtensions::class, 'getDatatableColumnClass']), ]; } diff --git a/src/Utils/ProfileManager.php b/src/Utils/ProfileManager.php index 1bef12871..fbd256ba4 100644 --- a/src/Utils/ProfileManager.php +++ b/src/Utils/ProfileManager.php @@ -15,10 +15,10 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface; final class ProfileManager { - public const SESSION_PROFILE = 'datatable_profile'; - public const PROFILE_DESKTOP = 'desktop'; - public const PROFILE_MOBILE = 'mobile'; - public const COOKIE_PROFILE = 'K2P'; + public const string SESSION_PROFILE = 'datatable_profile'; + public const string PROFILE_DESKTOP = 'desktop'; + public const string PROFILE_MOBILE = 'mobile'; + public const string COOKIE_PROFILE = 'K2P'; public function __construct() { @@ -40,9 +40,6 @@ final class ProfileManager /** * Always returns a valid profile name (default: desktop). - * - * @param string $profile - * @return string */ public function getProfile(string $profile): string { @@ -64,9 +61,6 @@ final class ProfileManager /** * Always returns a valid profile name (default: desktop). - * - * @param Request $request - * @return string */ public function getProfileFromCookie(Request $request): string { @@ -77,9 +71,6 @@ final class ProfileManager /** * Always returns a valid profile name (default: desktop). - * - * @param Session $session - * @return string */ public function getProfileFromSession(Session $session): string { diff --git a/templates/base.html.twig b/templates/base.html.twig index 297ab5e0c..7b070ed6d 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -26,12 +26,13 @@ {% endblock %} {% block page_content_start %} - {% if app.session and app.session.started and app.session.flashbag.peekAll|length > 0 %} + {% set flashes = app.flashes %} + {% if flashes|length > 0 %} {% set domain = 'flashmessages' %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/dashboard/index.html.twig b/templates/dashboard/index.html.twig index 0b2df3943..a795f5b17 100644 --- a/templates/dashboard/index.html.twig +++ b/templates/dashboard/index.html.twig @@ -14,7 +14,7 @@ {% endblock %} {% block footer %} - {% if 'dashboard' in app.request.attributes.get('_route') %} + {% if 'dashboard' in app.current_route %} {{ parent() }} {% endif %} {% endblock %} diff --git a/templates/export/layout.html.twig b/templates/export/layout.html.twig index dba78ca47..4f942e238 100644 --- a/templates/export/layout.html.twig +++ b/templates/export/layout.html.twig @@ -1,5 +1,5 @@ - + diff --git a/templates/export/pdf-layout.html.twig b/templates/export/pdf-layout.html.twig index 9221e2805..f595488a1 100644 --- a/templates/export/pdf-layout.html.twig +++ b/templates/export/pdf-layout.html.twig @@ -35,7 +35,7 @@ {% endif %} {% set summaryColumns = summaryColumns|merge(['rate']) %} {% endif %} - + {% block document_title %}{{ 'export'|trans }}{% endblock %} {% block styles %} diff --git a/templates/export/renderer.pdf.twig b/templates/export/renderer.pdf.twig index 46e88e4f0..2c0fff7ca 100644 --- a/templates/export/renderer.pdf.twig +++ b/templates/export/renderer.pdf.twig @@ -1,4 +1,4 @@ - + {% set title = (template.options.name ?? 'export.document_title')|trans %} {# show the generation date of the PDF #} {% set now = create_date('now', app.user) %} diff --git a/templates/form.html.twig b/templates/form.html.twig index c8504ff36..42b2e7a28 100644 --- a/templates/form.html.twig +++ b/templates/form.html.twig @@ -1,5 +1,5 @@ - + {% block page_title %}{{- get_title() -}}{% endblock %} diff --git a/templates/macros/datatables.html.twig b/templates/macros/datatables.html.twig index 65dceae0b..b45a93a6c 100644 --- a/templates/macros/datatables.html.twig +++ b/templates/macros/datatables.html.twig @@ -77,7 +77,7 @@ {% endif %} {% if filterCount > 0 and not form.vars.data.isBookmarkSearch() %} - + {{ icon('cancel') }} {% endif %} @@ -90,7 +90,8 @@ {% endmacro %} {% macro data_table_column_modal(name, columns) %} -{% set visibility = initialize_datatable(app.user, app.session, name, columns) %} +{% set datatable = initialize_datatable(app.user, name, columns) %} +{% set is_desktop = datatable.profile != constant('\\App\\Utils\\ProfileManager::PROFILE_MOBILE') %}