Skip to content

Twig ​

Functions ​

ems_html ​

Will return a instance of EmsHtml which is an extension of Twig\Markup. You can easyly replace text, remove html tags, printUrls.

Example

This example is usefull for generating pdf's.

  • This wil replace 'example' by 'EXAMPLE' and 'searchX' by 'replaceX'
  • Remove all a tags if the attribute text contains 'mywebsite.com' and will keep the content
  • Print urls will transform the a tags based on the format (default: ':content (:href)')
twig
{% set description = ems_html(page.description) %}
{% do description
    .replace({ 'example': 'EXAMPLE', 'searchX': 'replaceX' })
    .removeTag('a', ".*?mywebsite.com.*?", true)
    .printUrls(':content (<i><u>:href</u></i>)')
%}
{{ description|emsch_routing_config(emschRoutingConfig) }}

Search all choices of a nested field, and this function will runtime cache the result.

Arguments

  • alias: name of the elasticsearch alias
  • contentTypeNames: string or array of contentType names
  • nestedFieldName: namem of the nestedField
  • search: key/value array, key is nested property name, value is search value

Example

The following example will build 3 variables by using the ems_nested_search, the choices will only build once and cached.

twig
{% set example1 = ems_nested_search('my_alias', 'structure', 'documents', {'id': 'd2214354-a946-4e60-8e1a-921a643df3ad'}) %}
{% set example2 = ems_nested_search('my_alias', 'structure', 'documents', {'id': '9d501b0f-13c1-42e1-a4ae-242650dc6dbd'}) %}
{% set example3 = ems_nested_search('my_alias', 'structure', 'documents', {'id': '0186c0ac-4d8f-4755-a8f0-afa9fb86d599'}) %}

ems_image_info ​

Retrieve information (size, resolution, mime type and extension) about an image, based on its hash. If the hash can not be recognized as an image or does not exist, null is returned. If the file supports EXIF, EXIF's meta information will be also retrieved.

Arguments

  • hash: hash(sha1) of the image

Where '4ef5796bb14ce4b711737dc44aa20bff82193cf5' is the hash of a jpg

twig
{{ ems_image_info('4ef5796bb14ce4b711737dc44aa20bff82193cf5') }}

// will return

{
    'width': 300,
    'height': 300,
    'mimeType': 'image/jpeg',
    'extension': 'jpeg',
    'FileName': 'test_350dpi.jpg',
    'FileDateTime': 1708511136,
    'FileSize': 6935,
    'FileType': 2,
    'MimeType': 'image/jpeg',
    'SectionsFound': 'COMMENT',
    'COMPUTED': [
        'html': 'width="300" height="300"',
        'Width': 300,
        'Height': 300,
        'IsColor': 1,
    ],
    'COMMENT': ['Created with GIMP'],
    'widthResolution': 350,
    'heightResolution': 350
}

ems_uuid ​

Generate a version 4 (random) UUID. More info.

twig
{{ ems_uuid() }}

ems_store_read ​

Retrieve, or initialize, an associative array (a.k.a. store data) for a given key from the first Store Data Services where the key is available. See the Stora Data documentation for more details.

twig
{% set data = ems_store_read('forum') %}
<form method="post" action="{{ path('emsch_update_store') }}">
    <textarea name="data" cols="10">{{ data.get('[data]') }}</textarea>
    <input name="submit" type="submit" value="Submit">
</form>

ems_store_save ​

Update a store data in all store data services. This function must be called in a non-safe request (i.e. POST or PUT). See the Stora Data documentation for more details.

yaml
emsch_update_store:
    config:
        path: '/post-data'
        controller: 'emsch.controller.router::redirect'
        method: [POST]
    template_static: template/redirects/post-data.json.twig
twig
{%- block request %}
{% apply spaceless %}
  {% set data = ems_store_read('forum') %}
  {% do data.set('[data]', app.request.get('data')) %}
  {% do ems_store_save(data) %}

  {{ {
    url: path('home'),
  }|json_encode|raw }}
{% endapply %}
{% endblock request -%}

ems_store_delete ​

Delete a store data in all store data services. This function must be called in a non-safe request (i.e. POST or PUT). See the Stora Data documentation for more details.

yaml
emsch_delete_store:
    config:
        path: '/delete-post-data'
        controller: 'emsch.controller.router::redirect'
        method: [POST]
    template_static: template/redirects/delete-post-data.json.twig
twig
{%- block request %}
{% apply spaceless %}
  {% do ems_store_delete('forum') %}

  {{ {
    url: path('home'),
  }|json_encode|raw }}
{% endapply %}
{% endblock request -%}

ems_flash ​

Add a flash to the symfony request flash bag.

twig
{% do ems_flash('error', 'error.default'|trans) %}

You can use the following template for displaying the flashes (bootstrap5).

twig
{%- set alertTypes = {
    'success': 'alert-success',
    'error': 'alert-danger',
    'warning': 'alert-warning',
    'info': 'alert-info'
} -%}

{%- for type, class in alertTypes -%}
    {%- for message in app.session.flashBag.get(type) -%}
        <div class="alert {{ class }} alert-dismissible fade show" role="alert">
            {{ message }}
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
        </div>
    {%- endfor -%}
{%- endfor -%}

ems_file_reader_data ​

Use the FileReader to get CSV or MS Excel fil content.

twig
<pre>{{ ems_file_reader_data('57bcba09d6f5e06852b83b2b2ba545529f862a87', {'all_sheets': true})|json_encode(constant('JSON_PRETTY_PRINT')) }}</pre>

Options:

  • delimiter (string): For CSV file
  • encoding (string): file's charset
  • all_sheets (boolean): Extract only the active sheet (false, default) or all sheets (true)

ems_file_reader_cells ​

Returns a cells iterator

twig
<pre>{% set cellsIterator = ems_file_reader_cells('57bcba09d6f5e06852b83b2b2ba545529f862a87', {'exclude_rows': [0]}) }}</pre>

Options:

  • mime_type (string): File mimetype
  • delimiter (string): CSV delimiter
  • encoding (string): file's charset
  • exclude_rows (int[]): skip those rows
  • limit (int): limit to the first rows

ems_check_ip ​

Checks if an IPv4 or IPv6 address is contained in the list of given IPs or subnets. In order to avoid HTTP cache issues, this function must be called in a non-safe request (i.e. POST or PUT).

twig
{% set clientIp = app.request.headers.get('X-FORWARDED-FOR')|default('192.168.0.5') %}
{% set ranges =  [
    '192.168.0.0/24',
    '10.0.0.0/8',
    '203.0.113.5',
    '172.16.0.0/255.240.0.0',
    '2001:db8::/32',
    'fd00::/8',
    '2a02:26f0:10::5',
] %}

{% if ems_check_ip(clientIp, ranges) %}
 {# display sensitive contents here #}
{% endif %}

Response headers ​

ResponseHeaderExtension exposes functions for configuring HTTP response headers from Twig. The headers are stored in the current request context and are added to the response when it is sent.

ems_http_header ​

Add or replace a response header. Header names are normalized automatically.

twig
{% do ems_http_header('Cache-Control', 'no-store') %}
{% do ems_http_header('X-Robots-Tag', 'noindex') %}

The header value must be valid for an HTTP header. Values containing control characters, including carriage returns and line feeds, are rejected.

ems_remove_http_header ​

Remove one response header from the context. This can remove both a default header and a header previously added with ems_http_header.

twig
{% do ems_remove_http_header('Permissions-Policy') %}
{% do ems_remove_http_header('X-Robots-Tag') %}

ems_clear_http_headers ​

Remove all regular response headers from the context. This does not clear the CSP configuration.

twig
{% do ems_clear_http_headers() %}

ems_csp_source ​

Add a source to a Content-Security-Policy directive. The default policy contains:

text
default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

Note: Adding a source for a directive replaces that directive's default value. Remember to include the default sources you still need. For example, adding script-src with only https://cdn.example.com removes the default 'self' source:

twig
{%- do ems_csp_source('script-src', "'self'")  -%}
{%- do ems_csp_source('script-src', 'https://cdn.example.com')  -%}

Adding a source replaces only the matching default directive; unrelated directives remain enabled.

twig
{% do ems_csp_source('script-src', 'https://cdn.example.com') %}
{% do ems_csp_source('img-src', 'https://images.example.com') %}

In debug mode, style-src 'self' 'unsafe-inline' is added to allow inline styles used by the Symfony Web Debug Toolbar.

ems_nonce ​

Generate a nonce and add it to the selected CSP directive. The nonce is stable for the current request and must be added to the corresponding inline element.

Supported directives are script-src, script-src-elem, style-src, and style-src-elem.

twig
{% set scriptNonce = ems_nonce('script-src') %}
<script nonce="{{ scriptNonce }}">
    // Inline JavaScript
</script>

Do not combine a nonce with unsafe-inline when strict inline protection is required: browsers ignore unsafe-inline when a nonce or hash is present in the same directive.

ems_csp_script and ems_csp_style ​

These filters render an inline <script> or <style> element and add its SHA-256 hash to the corresponding CSP directive. They are useful for inline code that can be cached and reused, while ems_nonce is useful when the content changes for every response.

Note: these filters add a hash to script-src or style-src, so they also replace that directive's default value. Add the self source explicitly when it is needed, using the examples above.

The filter returns safe HTML, so it must be used directly as output. The optional second argument is an array of HTML attributes. Boolean true renders a valueless attribute; false and null are omitted, and other values are HTML-escaped.

twig
{% set imageStyle -%}
    img.landing-logo {
        border-width: 0;
    }
{%- endset %}
{{ imageStyle|ems_csp_style }}

{% set helloScript -%}
    console.log('Hello elasticMS');
{%- endset %}
{{ helloScript|ems_csp_script({'type': 'application/javascript'}) }}

The hash is calculated from the content after CRLF and CR line endings have been normalized to LF. The generated tag must therefore not be modified after applying the filter. The content must not contain a closing </script> or </style> tag. For safety, event-handler attributes (on*), src, nonce, and integrity are not accepted; external resources and nonces should be configured explicitly with the appropriate CSP function.

Twig filters ​

ems_anti_spam ​

For obfuscation of pii on your website when the user agent is a robot.

Implementation details are based on http://www.wbwip.com/wbw/emailencoder.html using ems_html_encode. The following data can be obfuscated (even inside a wysiwyg field):

  • emailadress no_reply@example.com
twig
{{- 'no_reply@example.com'|ems_anti_spam -}}
  • phone number in <a href="tel:____">
twig
{{- '<a href="tel:02/123.50.00">repeated here, the number will not be encoded</a>'|ems_anti_spam -}}
  • custom selection of pii using a span with class "pii"
twig
{{- '<span class="pii">02/123.50.00</span>'|ems_anti_spam -}}

See unit test for more examples.

Note: Phone numbers are only obfuscated if they are found inside "tel:" notation. When a phone is used outside an anchor, the custom selection of pii method should be used.

Note: When using custom selection of pii, make sure that no HTML tags are present inside the pii span.

Note: the custom selection pii span is only present in the backend. The obfuscation method removes the span tag from the code that is sent to the browser.

ems_html_encode ​

You can transform any text to its equivalent in html character encoding.

twig
{{- 'text and téxt'|ems_html_encode -}}

See unit test for more examples.

ems_markdown ​

Filter converting a Markdown text into an HTML text following the GitHub standards.

twig
{{ source.body|ems_markdown }}

ems_stringify ​

Filter converting any scalar value, array or object into a string.

twig
{{ someObject|ems_stringify }}
{{ someArray|ems_stringify }}

ems_asset_average_color ​

Filter returning the average color, in CSS rgb format, of a passed hash.

I.e.

twig
{{ 'ed266b89065e74483248da7ff71cb80e3cca40a5'|ems_asset_average_color}}

Will return #666666. It might be useful in order to define a background color:

twig
{{ ems_asset_path({
    filename: 'avatar.jpg',
    sha1: avatarHash,
    mimetype: 'image/jpeg',
}, {
    _config_type: 'image',
    _resize: 'fill',
    _background: avatarHash|ems_asset_average_color,
    _width: 400,
    _height: 600,
    _quality: 80,
    _get_file_path: localPath,
}) }}
twig
style="background-color: {{ avatarHash|ems_asset_average_color }}"

ems_replace_regex ​

Apply php preg_replace function on a text string. All possible exceptions are catched and logged as warning.

Example replace all ems links by a span tag.

twig
{% set text %}
    <h1>Example</h1>
    <p><a href="ems://object:page:dabc33113a53866fe1a1443b42a4c16d1f4bc138">Homepage</a></p>
    <p><a href="ems://object:page:7cc6310cc57818bb571e706ede0a4c10623b430c">News</a></p>
    <p>the end</p>
{% endset %}
{{ text|ems_replace_regex('/<a.*?href="ems:\\/\\/\\S+".*?>(.*?)<\\/a>', '<span>$1</span>')|raw }}

ems_html_decode ​

Convert HTML entities to their corresponding characters

The following example will generate a è :

twig
{{ '&grave;'|ems_html_decode|json_encode|raw }}

Other parameters:

ems_hash ​

Generate a hash value from the message. See the PHP hash function.

twig
{{ 'foobar'|ems_hash }}
{{ 'foobar'|ems_hash('sha1') }} {# outputs 8843d7f92416211de9ebb963ff4ce28125932878 #}

Other parameters:

ems_format_bytes ​

Useful to generate a human readable file size from an interger.

twig
{{ 21666|ems_format_bytes }} {# displays: 21.16 KB #}

A second 'precision' parameter can be defined:

twig
{{ 21666|ems_format_bytes(1) }} {# displays: 21.2 KB #}

ems_ascii_folding ​

Convert UTF-8 characters in string by their equivalent in the "old" ascii table:

twig
{{ 'Chemin d''accès: î$]&²'|ems_ascii_folding }} {# displays: Chemin d acces: i$]&² #}

It's useful if you want to sort an array regardless accented characters:

twig
{% set sortedArray = notSortedArray|sort((a, b) => a|ems_ascii_folding <=> b|ems_ascii_folding) %}

ems_template_exists ​

Test if a template exists or not. This function works with all kind of templates:

twig
{% if not ems_template_exists("@EMSCH/template/page/#{name}.html.twig") %}
  {% do emsch_http_error(404, 'Page not found') %}
{% endif %}

ems_analyze ​

Analyze an input string using the elasticsearch Analyze API:

twig
<p>{{ ems_analyze('― — – ‒ ‹ › ′ ‵ ‘ ’ ‚ ‛ ″ ‴ ‶ ‷ “ ” „ ‟ «  » ü Ü ß ẞ ä ö Ä Ö', {
  'filter': ['asciifolding'],
  'tokenizer': 'keyword'
}) }}</p>
{# ― - - - ' ' ' ' ' ' ' ' " ‴ " ‷ " " " ‟ " " u U ss SS a o A O #}

Arguments:

  • text: the text to analyze (string)
  • parameters: the Analyze API parameters (check the elasticsearch Analyze API documentation) (array)
  • index: an optional index name (string)

ems_json_decode ​

Call the PHP \json_decode method with those default values: public function jsonDecode(string $json, bool $assoc = true, int $depth = 512, int $options = 0)

twig
{% set config = 'con

ems_array_key ​

Use the value of the parameter identified by the given name as array index

twig
{% set paths = rawData.paths|default([])|filter(p => p.locale == locale)|ems_array_key('uid') %}

ems_ouuid ​

Extract a OUUID from an ElasticMS link

twig
    {%  set categories = emsch_search('category', {
        "size": 1000,
        "query": { "terms": { "_id": query.aggregations.categories.buckets|map(p => p.key|ems_ouuid) }},
        "sort": [
            {("title_#{locale}.alpha_order"): {"order": "asc"}}
        ],
        "_source": ["#{app.request.locale}.title"]
    }).hits.hits|default([])|ems_array_key('_id')|map(p => attribute(p._source, app.request.locale).title) %}

ems_md5 ​

Calculate the md5 hash of a string

twig
{{ app.user.email|lower|md5 }}

ems_luma ​

Calculate the luminance of a color(string)

twig
{% set luminance = '#FF56DD'|ems_luma %}

ems_contrast_ratio ​

Calculate the contrast ratio between 2 colors (string)

twig
{% if '#FF56DD'|ems_contrast_ratio('black') > '#FF56DD'|ems_contrast_ratio('white') %}#000000{% else %}#ffffff{% endif %}

ems_color ​

Convert a color (string) into a EMS\Helpers\Standard\Color

twig
{% set color = '#FF56DD'|ems_color %}

ems_slug ​

Convert a string into an url friendly string

twig
{{ 'How do you do ?'|ems_slug }}
{# how-do-you-do #}

Arguments:

  • locale: default value en
  • separator: default value -
  • lower: default value true
twig
{{ 'Wie fährst du deinen großen LKW ?'|ems_slug('de', '/', false) }}
{# Wie/faehrst/du/deinen/grossen/LKW #}

ems_file_from_archive ​

Returns a path to a temporary asset extracted from an archive (a zip file). Useful to get local path to an asset (e.g. in case of PDF generation)

twig
    {% set path = ems_file_from_archive('253b903b1fb3ac30975ae9844a0352a65cdcfa3d', 'img/logos/full-logo.svg') %}

This function also accept extra options:

  • extract: Specify that the function can not try to re-extract the archive if the searched path is missing. If disabled the function won't throw an error but null. Default value: true.
  • asTempFile: Returns a EMS\Helpers\File\TempFile object when activated, a path to the temporary file instead. A TempFile is useful to get file's contents with the member function getContents(). Default value false

Example:

twig
{% set tempFile = ems_file_from_archive(hash, "#{path}/index.php", {
    extract: false,
    asTempFile: true,
}) %}

ems_files_in_archive ​

Returns the list of files present in an archive (EMS archive or Zip file)

twig
{% set files = ems_files_in_archive(hash) %}

This method returns an array like this:

json
{
    "0693f7c7e26507b5d464a99f6a03b9309560abf3.json": {
        "filename": "0693f7c7e26507b5d464accf6a03b9309560abf3.json",
        "hash": "0693f7c7e26507b5d464accf6a03b9309560abf3",
        "type": "application/json",
        "size": 3561
    },
    "crm-export.xlsx": {
        "filename": "crm-export.xlsx",
        "hash": "dd2650a9d4537c5127b9907e83f1e508523d3c18",
        "type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "size": 167352
    },
    "2025-09 Facture Service 1113975398.PDF": {
        "filename": "2025-09 Facture Service 1113975398.PDF",
        "hash": "2ddf565c90bb89b0d860a538828f1dd7bb8b37a5",
        "type": "application/pdf",
        "size": 32640
    }
}

Return the EMSLink object

twig
{% set emsLink = 'page:064efcc7751ee8b0915416a717e2db46d15c77eb'|ems_link %}

ems_valid_mail ​

Returns true if the input is a valid email

twig
{%- if _source.email|ems_valid_mail -%}{% endif %}

ems_uuid filter ​

Generate a version 5 UUID from a value. More info.

twig
{{ 'my_unique_id_value'|ems_uuid }}

ems_date ​

Generate a \DateTimeImmutable object from a value.

twig
{% set date = '31/12/1998 0:00:00'|ems_date('j/m/Y H:i:s') %}

{{ date.format('d-m-Y') }}
{{ date.timezone }}

ems_int ​

Use php \intval function on input

twig
{% set size = app.request.query.get('size', 0)|ems_int %}

ems_clear_http_caches ​

Calls the configured reverse proxy services to invalidate part or all of their caches.

It accepts one optional argument:

  • URL or Tags (optional):
    • If it contains an empty array (default value), a full cache purge will be sent.
    • If it is a string starting with /, a cache clear by URL will be sent.
    • Otherwise, a cache clear by tags will be sent.

Example of a cache clear route ​

The URL is triggered by a clear-cache webhook event, at the endpoint //localhost/_clear_cache.

Depending on the event data:

  • If it contains a tags attribute (string or array of strings), a tag-based cache clear will be sent.
  • If it contains a url attribute (string), a URL-based cache clear will be sent.
  • Otherwise, a full cache purge will be sent.

The emsch_clear_cache route:

yaml
emsch_clear_cache:
    config:
        path: '/_clear_cache'
        method: [POST]
        host: 'localhost'
    template_static: template/admin/clear-cache.html.twig

The template/admin/clear-cache.html.twig twig:

twig
{%- set event = emsch_webhook_event() -%}
{%- if event.name == 'clear-cache' -%}
    {%- do ems_clear_http_caches(event.data.tags|default(event.data.url|default([]))) -%}
    {%- set success = true -%}
{%- endif -%}
{{- { success: success|default(false) }|json_encode|raw -}}

Twig tests ​

ems_translatable_message ​

Test that an object is a translatable message. Example:

twig
{%- if object is ems_translatable_message -%}
    {%- set object = object|trans -%}
{%- endif -%}