Skip to content

Commit

Permalink
Prepare for twig >=3.9.0 (pimcore#17444)
Browse files Browse the repository at this point in the history
* Prepare twig pimcore cache extension based on nodes

* Apply php-cs-fixer changes

* Small fixes

* Fix sonar cloud issues

* Apply php-cs-fixer changes

* Avoid duplication

* Docs + deprecations

* Apply php-cs-fixer changes

* Deprcate pimcore_placeholder captureStart()/captureEnd() and update docs

* Fix typo

Co-authored-by: Jacob Dreesen <[email protected]>

* Fix docs

* Deprecate pimcore_head_script captureStart()/captureEnd()

* Apply php-cs-fixer changes

* Improve type cast

* Apply php-cs-fixer changes

* Deprecate pimcore_head_style captureStart()/captureEnd()

* Simplify placeholder docs

* Simplify placeholder docs

* Deprecations

* Docs

* Docs

* Docs

* Code style

* Improve deprecations

* Implement feedback

* Apply php-cs-fixer changes

---------

Co-authored-by: markus-moser <[email protected]>
Co-authored-by: Jacob Dreesen <[email protected]>
Co-authored-by: mattamon <[email protected]>
  • Loading branch information
4 people authored Aug 29, 2024
1 parent df3a88c commit 123b8db
Show file tree
Hide file tree
Showing 13 changed files with 468 additions and 28 deletions.
1 change: 1 addition & 0 deletions bundles/CoreBundle/config/templating_twig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
Pimcore\Twig\Extension\DumpExtension: ~

Pimcore\Twig\Extension\CacheExtension: ~
Pimcore\Twig\Extension\CacheTagExtension: ~

Pimcore\Twig\Extension\Templating\PimcoreUrl:
arguments:
Expand Down
27 changes: 26 additions & 1 deletion doc/02_MVC/02_Template/02_Template_Extensions/00_Placeholder.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ the current setting is.
```

### Capture Content
### Capture Content (deprecated)
Occasionally you may have content for a placeholder in a view script that is easiest to template. The `Placeholder` extension allows you to capture arbitrary content for later rendering using the following API.

- `captureStart($type, $key)` begins capturing content.
Expand Down Expand Up @@ -91,3 +91,28 @@ list of current content in the placeholder. If `SET`, captured content is used a
{{ pimcore_placeholder('foo').data | raw }}
```

**Note:** The `captureStart()` and `captureEnd()` methods are deprecated as of Pimcore 11.4.0. Use a combination of `set` and `pimcore_placeholder` to achieve the same result.

```twig
{% set placeholderData %}
{% for datum in data %}
<div class="foo">
<h2>{{ datum.title }}</h2>
<p>{{ datum.content }}</p>
</div>
{% endfor %}
{% endset %}
{% do pimcore_placeholder('foo').set(placeholderData) %}
{{ pimcore_placeholder('foo') }}
```

```twig
{% set placeholderData %}
Test to append some additional content
{% endset %}
{% do pimcore_placeholder('foo').append(placeholderData) %}
{{ pimcore_placeholder('foo') }}
```
14 changes: 13 additions & 1 deletion doc/02_MVC/02_Template/02_Template_Extensions/03_HeadScript.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ When you're finally ready to output all scripts in your layout script, simply ec

`{{ pimcore_head_script() }}`

### Capturing Scripts Using the HeadScript Helper
### Capturing Scripts Using the HeadScript Helper (deprecated)

Sometimes you need to generate client-side scripts programmatically. While you could use string concatenation,
heredocs, and the like, often it's easier just to do so by creating the script and sprinkling in Twig tags.
Expand All @@ -111,6 +111,18 @@ pass it as the second argument to `captureStart()`.
If you wish to specify any additional attributes for the `<script>` tag, pass them in an array as the third
argument to `captureStart()`.

**Note:** The `captureStart()` and `captureEnd()` methods are deprecated as of Pimcore 11.4.0. Use a combination of `set` and `pimcore_head_script` to achieve the same result.

```twig
{% set inlineScript %}
var action = '{{ baseUrl }}';
$('#foo_form').attr("action", action);
{% endset %}
{% do pimcore_head_script().appendScript(inlineScript) %}
{# Example if you wish to specify additional attributes for the <script> tag #}
{% do pimcore_head_script().appendScript(inlineScript, "text/javascript", {"async": "async"}) %}
```

## HTTP/2 Push Support

Expand Down
14 changes: 14 additions & 0 deletions doc/02_MVC/02_Template/02_Template_Extensions/04_HeadStyle.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,17 @@ you will need to pass `SET` or `PREPEND`, respectively, as the first argument to

If you wish to specify any additional attributes for the `<style>` tag, pass them in an array as the second argument to
`captureStart()`.

**Note:** The `captureStart()` and `captureEnd()` methods are deprecated as of Pimcore 11.4.0. Use a combination of `set` and `pimcore_head_style` to achieve the same result.

```twig
{% set inlineStyle %}
body {
background-color: red
}
{% endset %}
{% do pimcore_head_style().appendStyle(inlineStyle) %}
{# Example if you wish to specify additional attributes for the <style> tag #}
{% do pimcore_head_style().appendStyle(inlineStyle, {"media": "screen"}) %}
```
78 changes: 55 additions & 23 deletions doc/02_MVC/02_Template/02_Template_Extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,26 @@ In addition to the standard Twig extensions, Pimcore adds some additional powerf

All Twig extension functions are described below in detail, the following tables give just a short overview of all available extensions.

| Extension | Description |
|------------------------------------------|-------------------------------------------------------------------|
| `pimcore_cache()` | Simple in-template caching functionality |
| `pimcore_device()` | Helps implementing adaptive designs |
| `pimcore_glossary` | Twig Filter: Apply filter on content to pass it to Glossary engine |
| `pimcore_placeholder()` | Adding and embedding custom placeholders, e.g. for special header tags, etc. |
| `pimcore_head_link()` | Embeding / managing referenced stylesheets (alternative to `assets()`) |
| `pimcore_head_meta()` | Managing your \<meta\> elements in your HTML document |
| `pimcore_head_script()` | Managing your \<scripts\> elements |
| `pimcore_head_style()` | Managing inline styles (pendant to `headLink()` for inline styles) |
| `pimcore_head_title()` | Create and store the HTML document's `<title>` for later retrieval and output |
| `pimcore_inc()` | Use this function to directly include a Pimcore document |
| `pimcore_inline_script` | Managing inline scripts (pendant to `headScript()` for inline scripts) |
| `pimcore_build_nav()`, `pimcore_render_nav()`, `pimcore_nav_renderer()` | Embed and build navigations based on the document structure |
| `pimcore_url()` | An alternative to `url()` and `path()` |
| `pimcore_website_config()`| Fetch website settings or specific setting (first param: key) for the current site |
| `pimcore_image_thumbnail()` | Returns a path to a given thumbnail on image |
| `pimcore_image_thumbnail_html()` | Returns html for displaying the thumbnail image |
| `pimcore_supported_locales()` | Use this function to get a list of supported locales |
| Extension | Description |
|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------|
| `pimcorecache` | Simple in-template caching functionality |
| `pimcore_cache()` (deprecated) | Simple in-template caching functionality (deprecated legacy version) |
| `pimcore_device()` | Helps implementing adaptive designs |
| `pimcore_glossary` | Twig Filter: Apply filter on content to pass it to Glossary engine |
| `pimcore_placeholder()` | Adding and embedding custom placeholders, e.g. for special header tags, etc. |
| `pimcore_head_link()` | Embeding / managing referenced stylesheets (alternative to `assets()`) |
| `pimcore_head_meta()` | Managing your \<meta\> elements in your HTML document |
| `pimcore_head_script()` | Managing your \<scripts\> elements |
| `pimcore_head_style()` | Managing inline styles (pendant to `headLink()` for inline styles) |
| `pimcore_head_title()` | Create and store the HTML document's `<title>` for later retrieval and output |
| `pimcore_inc()` | Use this function to directly include a Pimcore document |
| `pimcore_inline_script` | Managing inline scripts (pendant to `headScript()` for inline scripts) |
| `pimcore_build_nav()`, `pimcore_render_nav()`, `pimcore_nav_renderer()` | Embed and build navigations based on the document structure |
| `pimcore_url()` | An alternative to `url()` and `path()` |
| `pimcore_website_config()` | Fetch website settings or specific setting (first param: key) for the current site |
| `pimcore_image_thumbnail()` | Returns a path to a given thumbnail on image |
| `pimcore_image_thumbnail_html()` | Returns html for displaying the thumbnail image |
| `pimcore_supported_locales()` | Use this function to get a list of supported locales |

Pimcore also adds some Twig tests for evaluating boolean conditions e.g.
```twig
Expand Down Expand Up @@ -102,12 +103,43 @@ The following tests are only available if the [PimcoreNewsletterBundle](https://
You can also create your own custom Twig Extension to make certain functionalities available to your views.
Here you can find an example how to [create](https://symfony.com/doc/current/templating/twig_extension.html)
your own Twig Extension.

### `pimcore_cache`
This is an implementation of an in-template cache. You can use this to cache some parts directly in the template,
independent of the other global definable caching functionality. This can be useful for templates which need a lot

### `pimcorecache`

This is an implementation of an in-template cache. You can use this to cache some parts directly in the template,
independent of the other global definable caching functionality. This can be useful for templates which need a lot
of calculation or require a huge amount of objects (like navigations, ...).

`{% pimcorecache "cache_key" tags([...]) ttl(int) force(bool) %}`


| Name | Type | Description |
|-------------|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `cache_key` | string | Key/name of cache item |
| `tags` | string, string[] | One or multiple additional cache tags. The `in_template` cache tag is automatically added to all items. When no ttl is defined the `output` cache tag is additionally added. |
| `ttl` | int | Time to life - lifetime in seconds. If you define no ttl the behavior is like the output cache, so if you make any change in Pimcore, the cache will be flushed. When specifying a lifetime this is independent from changes in the CMS. |
| `force` | bool | Force caching, even when request is done within Pimcore admin interface |

##### Examples

```twig
{% pimcorecache "test_cache_key" ttl(60) %}
<h1>This is some cached microtime</h1>
{{ 'now'|date('U') }}
{% endpimcorecache %}
```

```twig
{# example with all options #}
{% pimcorecache "test_cache_key" ttl(60) tags(['custom_tag']) force(true) %}
<h1>This is some cached microtime</h1>
{{ 'now'|date('U') }}
{% endpimcorecache %}
```

### `pimcore_cache` (deprecated)
This is a deprecated alternative approach to the `pimcorecache` extension. Use `pimcorecache` instead.

`pimcore_cache( name, lifetime, force)`

| Name | Type | Description |
Expand Down
5 changes: 4 additions & 1 deletion doc/02_MVC/02_Template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,19 @@ See [Template Extensions](./02_Template_Extensions/README.md) for details.
The following extensions can directly be used on Twig. See [Template Extensions](./02_Template_Extensions/README.md) for a
detailed description of every helper:

**Functions:**
* `pimcore_head_link`
* `pimcore_head_meta`
* `pimcore_head_script`
* `pimcore_head_style`
* `pimcore_head_title`
* `pimcore_inline_script`
* `pimcore_placeholder`
* `pimcore_cache`
* `pimcore_url`
* `pimcore_cache` (deprecated)

**Tags:**
* `pimcorecache`

#### Block elements

Expand Down
8 changes: 8 additions & 0 deletions lib/Twig/Extension/CacheExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

/**
* @internal
*
* @deprecated
*/
class CacheExtension extends AbstractExtension
{
Expand Down Expand Up @@ -57,6 +59,12 @@ public function getFunctions(): array
*/
public function init(string $name, int $lifetime = null, bool $force = false): static
{
trigger_deprecation(
'pimcore/pimcore',
'11.4',
'"pimcore_cache" twig extension is deprecated. Use the "pimcorecache" tag instead.'
);

$this->key = 'pimcore_viewcache_' . $name;
$this->force = $force;

Expand Down
76 changes: 76 additions & 0 deletions lib/Twig/Extension/CacheTagExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Twig\Extension;

use Pimcore\Cache;
use Pimcore\Tool;
use Pimcore\Twig\TokenParser\CacheParser;
use Twig\Extension\AbstractExtension;
use function is_null;

/**
* @internal
*/
class CacheTagExtension extends AbstractExtension
{
private const CACHE_KEY_PREFIX = 'pimcore_twigcache_';

public function getTokenParsers(): array
{
return [
new CacheParser(),
];
}

public function getContentFromCache(string $key, bool $force): string|bool
{

if ($this->isCacheEnabled($force)) {
return Cache::load(self::CACHE_KEY_PREFIX . $key);
}

return false;
}

public function startBuffering(): void
{
ob_start();
}

public function endBuffering(string $key, array $tags, ?int $ttl, bool $force): string
{
$content = ob_get_contents();
ob_end_clean();

if ($this->isCacheEnabled($force)) {
$tags[] = 'in_template';
if (is_null($ttl)) {
$tags[] = 'output';
}
$tags = array_unique($tags);
Cache::save($content, self::CACHE_KEY_PREFIX . $key, $tags, $ttl, 996, true);
}

return $content;
}

private function isCacheEnabled(bool $force): bool
{
return !Tool::isFrontendRequestByAdmin() || $force;
}
}
16 changes: 15 additions & 1 deletion lib/Twig/Extension/Templating/HeadScript.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,16 @@ public function __invoke(string $mode = self::FILE, string $spec = null, string
* @param string $captureType
* @param string $type
*
* @deprecated Use twig set tag for output capturing instead.
*/
public function captureStart($captureType = Container::APPEND, $type = 'text/javascript', array $attrs = []): void
{
trigger_deprecation(
'pimcore/pimcore',
'11.4',
'Using "captureStart()" is deprecated. Use twig set tag for output capturing instead.'
);

if ($this->_captureLock) {
throw new Exception('Cannot nest headScript captures');
}
Expand All @@ -198,9 +205,16 @@ public function captureStart($captureType = Container::APPEND, $type = 'text/jav
/**
* End capture action and store
*
* @deprecated Use twig set tag for output capturing instead.
*/
public function captureEnd(): void
{
trigger_deprecation(
'pimcore/pimcore',
'11.4',
'Using "captureEnd()" is deprecated. Use twig set tag for output capturing instead.'
);

$content = ob_get_clean();
$type = $this->_captureScriptType;
$attrs = $this->_captureScriptAttrs;
Expand Down Expand Up @@ -261,7 +275,7 @@ public function __call(string $method, array $args): mixed
}
}

$content = $args[0];
$content = is_null($args[0]) ? null : (string) $args[0];

if (isset($args[1])) {
$type = (string) $args[1];
Expand Down
16 changes: 15 additions & 1 deletion lib/Twig/Extension/Templating/HeadStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public function __call(string $method, array $args): mixed
throw new Exception(sprintf('Method "%s" requires minimally content for the stylesheet', $method));
}

$content = $args[0];
$content = (string)$args[0];
$attrs = [];
if (isset($args[1])) {
$attrs = (array) $args[1];
Expand Down Expand Up @@ -261,9 +261,16 @@ public function set(mixed $value): void
* @param string $type
* @param array|null $attrs
*
* @deprecated Use twig set tag for output capturing instead.
*/
public function captureStart($type = Container::APPEND, $attrs = null): void
{
trigger_deprecation(
'pimcore/pimcore',
'11.4',
'Using "captureStart()" is deprecated. Use twig set tag for output capturing instead.'
);

if ($this->_captureLock) {
throw new Exception('Cannot nest headStyle captures');
}
Expand All @@ -277,9 +284,16 @@ public function captureStart($type = Container::APPEND, $attrs = null): void
/**
* End capture action and store
*
* @deprecated Use twig set tag for output capturing instead.
*/
public function captureEnd(): void
{
trigger_deprecation(
'pimcore/pimcore',
'11.4',
'Using "captureEnd()" is deprecated. Use twig set tag for output capturing instead.'
);

$content = ob_get_clean();
$attrs = $this->_captureAttrs;
$this->_captureAttrs = null;
Expand Down
Loading

0 comments on commit 123b8db

Please sign in to comment.