From 14dcfa6a3201e337774065f13c574d43f890c256 Mon Sep 17 00:00:00 2001 From: seb-jean Date: Sun, 2 Mar 2025 14:25:12 +0100 Subject: [PATCH] Add Twig Extensions for page refreshes --- src/Turbo/CHANGELOG.md | 4 ++ src/Turbo/doc/index.rst | 68 ++++++++++++++++++ src/Turbo/src/Twig/TwigExtension.php | 103 +++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) diff --git a/src/Turbo/CHANGELOG.md b/src/Turbo/CHANGELOG.md index 5a0f7d0f4f5..9bf757acdb0 100644 --- a/src/Turbo/CHANGELOG.md +++ b/src/Turbo/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.24.0 + +- Add Twig Extensions for `meta` tags + ## 2.22.0 - Add `` component diff --git a/src/Turbo/doc/index.rst b/src/Turbo/doc/index.rst index 509e96dc8db..9c7ff7b9b45 100644 --- a/src/Turbo/doc/index.rst +++ b/src/Turbo/doc/index.rst @@ -1046,6 +1046,74 @@ because these classes implement the ``BroadcasterInterface`` and ``TurboStreamListenRendererInterface`` interfaces, the related services will be. +Meta Tags +~~~~~~~~~ + +turbo_exempts_page_from_cache +............................. + +.. code-block:: twig + + {{ turbo_exempts_page_from_cache() }} + +Generates a tag to disable caching of a page. + +turbo_exempts_page_from_preview +............................... + +.. code-block:: twig + + {{ turbo_exempts_page_from_preview() }} + +Generates a tag to specify cached version of the page should not be shown as a preview on regular navigation visits. + +turbo_page_requires_reload +.......................... + +.. code-block:: twig + + {{ turbo_page_requires_reload() }} + +Generates a tag to force a full page reload. + +turbo_refreshes_with +.................... + +.. code-block:: twig + + {{ turbo_refreshes_with(method: 'replace', scroll: 'reset') }} + +``method`` *(optional)* + **type**: ``string`` **default**: ``replace`` **allowed values**: ``replace`` or ``morph`` +``scroll`` *(optional)* + **type**: ``string`` **default**: ``reset`` **allowed values**: ``reset`` or ``preserve`` + +Generates tags to configure both the refresh method and scroll behavior for page refreshes. + +turbo_refresh_method +.................... + +.. code-block:: twig + + {{ turbo_refresh_method(method: 'replace') }} + +``method`` *(optional)* + **type**: ``string`` **default**: ``replace`` **allowed values**: ``replace`` or ``morph`` + +Generates a tag to configure the refresh method for page refreshes. + +turbo_refresh_scroll +.................... + +.. code-block:: twig + + {{ turbo_refresh_scroll(scroll: 'reset') }} + +``scroll`` *(optional)* + **type**: ``string`` **default**: ``reset`` **allowed values**: ``reset`` or ``preserve`` + +Generates a tag to configure the scroll behavior for page refreshes. + Backward Compatibility promise ------------------------------ diff --git a/src/Turbo/src/Twig/TwigExtension.php b/src/Turbo/src/Twig/TwigExtension.php index b44d993139f..eb7aedfe806 100644 --- a/src/Turbo/src/Twig/TwigExtension.php +++ b/src/Turbo/src/Twig/TwigExtension.php @@ -22,6 +22,12 @@ */ final class TwigExtension extends AbstractExtension { + private const REFRESH_METHOD_REPLACE = 'replace'; + private const REFRESH_METHOD_MORPH = 'morph'; + + private const REFRESH_SCROLL_RESET = 'reset'; + private const REFRESH_SCROLL_PRESERVE = 'preserve'; + public function __construct( private ContainerInterface $turboStreamListenRenderers, private string $default, @@ -32,6 +38,12 @@ public function getFunctions(): array { return [ new TwigFunction('turbo_stream_listen', $this->turboStreamListen(...), ['needs_environment' => true, 'is_safe' => ['html']]), + new TwigFunction('turbo_exempts_page_from_cache', $this->turboExemptsPageFromCache(...), ['is_safe' => ['html']]), + new TwigFunction('turbo_exempts_page_from_preview', $this->turboExemptsPageFromPreview(...), ['is_safe' => ['html']]), + new TwigFunction('turbo_page_requires_reload', $this->turboPageRequiresReload(...), ['is_safe' => ['html']]), + new TwigFunction('turbo_refreshes_with', $this->turboRefreshesWith(...), ['is_safe' => ['html']]), + new TwigFunction('turbo_refresh_method', $this->turboRefreshMethod(...), ['is_safe' => ['html']]), + new TwigFunction('turbo_refresh_scroll', $this->turboRefreshScroll(...), ['is_safe' => ['html']]), ]; } @@ -52,4 +64,95 @@ public function turboStreamListen(Environment $env, $topic, ?string $transport = return $this->turboStreamListenRenderers->get($transport)->renderTurboStreamListen($env, $topic); } + + /** + * Generates a tag to disable caching of a page. + * + * Inspired by Turbo Rails + * ({@see https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/drive_helper.rb}). + */ + public function turboExemptsPageFromCache(): string + { + return ''; + } + + /** + * Generates a tag to specify cached version of the page should not be shown as a preview on regular navigation visits. + * + * Inspired by Turbo Rails + * ({@see https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/drive_helper.rb}). + */ + public function turboExemptsPageFromPreview(): string + { + return ''; + } + + /** + * Generates a tag to force a full page reload. + * + * Inspired by Turbo Rails + * ({@see https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/drive_helper.rb}). + */ + public function turboPageRequiresReload(): string + { + return ''; + } + + /** + * Generates tags to configure both the refresh method and scroll behavior for page refreshes. + * + * Inspired by Turbo Rails + * ({@see https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/drive_helper.rb}). + * + * @param string $method The refresh method. Must be either 'replace' or 'morph'. + * @param string $scroll The scroll behavior. Must be either 'reset' or 'preserve'. + * + * @return string The tags for the specified refresh method and scroll behavior + */ + public function turboRefreshesWith(string $method = self::REFRESH_METHOD_REPLACE, string $scroll = self::REFRESH_SCROLL_RESET): string + { + return $this->turboRefreshMethod($method).$this->turboRefreshScroll($scroll); + } + + /** + * Generates a tag to configure the refresh method for page refreshes. + * + * Inspired by Turbo Rails + * ({@see https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/drive_helper.rb}). + * + * @param string $method The refresh method. Must be either 'replace' or 'morph'. + * + * @return string The tag for the specified refresh method + * + * @throws \InvalidArgumentException If an invalid refresh method is provided + */ + public function turboRefreshMethod(string $method = self::REFRESH_METHOD_REPLACE): string + { + if (!\in_array($method, [self::REFRESH_METHOD_REPLACE, self::REFRESH_METHOD_MORPH], true)) { + throw new \InvalidArgumentException(\sprintf('Invalid refresh option "%s".', $method)); + } + + return \sprintf('', $method); + } + + /** + * Generates a tag to configure the scroll behavior for page refreshes. + * + * Inspired by Turbo Rails + * ({@see https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/drive_helper.rb}). + * + * @param string $scroll The scroll behavior. Must be either 'reset' or 'preserve'. + * + * @return string The tag for the specified scroll behavior + * + * @throws \InvalidArgumentException If an invalid scroll behavior is provided + */ + public function turboRefreshScroll(string $scroll = self::REFRESH_SCROLL_RESET): string + { + if (!\in_array($scroll, [self::REFRESH_SCROLL_RESET, self::REFRESH_SCROLL_PRESERVE], true)) { + throw new \InvalidArgumentException(\sprintf('Invalid scroll option "%s".', $scroll)); + } + + return \sprintf('', $scroll); + } }