Search code examples
twiggrav

"Illegal offset type in isset or empty" when using a Twig macro


Using Grav v1.3.8 (running on PHP 5.6.30), I'm currently getting a Server error ("Illegal offset type in isset or empty") when trying to render a Twig template that is using a macro.

What's interesting is that this only happens when I use the macro by itself. As soon as I append a filter, like trim, everything works as expected.

The (shortened) macro file, helpers.twig:

{% macro ascii(str) %}
{% spaceless %}
    {{ str|replace({
        'Á': 'A',
        'À': 'A',
        'Â': 'A',
        'Ã': 'A',
        ....
        'ƒ': 'f'
      })
    }}
{% endspaceless %}
{% endmacro ascii %}

The template (MCVE):

{% import 'macros/helpers.twig' as helpers %}

{% set img = helpers.ascii('günter-berger.jpg') %}
{% if page.media[img] is defined %}
    <img src="{{ page.media[img].url }}">
{% endif %}

This will produce the error. I narrowed it down to the if line. Apparently, the macro is working fine, but the condition will throw an error if fed the output of it, unfiltered. Adding any filter, like trim or lower, will get it to work again.

In other words, these work:

  • {% if page.media['günter-berger.jpg'] is defined %}
  • {% if page.media[helpers.ascii('günter-berger.jpg')|trim] is defined %}

But this will throw an error:

  • {% if page.media[helpers.ascii('günter-berger.jpg')] is defined %}

However, trying the same thing on twigfiddle, all three seem to work there.
Maybe an issue with Grav? Can someone point out any possible causes?


Solution

  • I forgot this, but a macro does not return a string but instead returns an instance of a Twig_Markup

    {% set test = macro.ascii('Ghünter.jpg') %}
    {{ dump(test) }}
    

    Output : object(Twig_Markup)#10679 (2) { ["content":protected]=> string(11) "Ghunter.jpg" ["charset":protected]=> string(5) "UTF-8" }

    Because the return type is an object you get this notification as you can't use objects as index. By using a filter on this instance, the magic method __toString method will be called, causing it to return a string, thus making it useable as index for an array

    The only was to bypass this, would be writing a filter instead of a macro