Check if a custom Twig function exists and then call it

后端 未结 1 635
春和景丽
春和景丽 2021-01-25 02:29

I test if a custom Twig function exists:

{% if methodExist(\'sg_datatables_render\') %}
    {{ sg_datatables_render(datatable) }}
 {% else %}
    {{ datatable_re         


        
相关标签:
1条回答
  • 2021-01-25 03:19

    I tried to replicate this, and indeed, {{ sg_datatables_render(datatable) }} seems to always cause a Twig_Error_Syntax exception when sg_datatables_render has not been registered as a Twig function.

    I then tried something like this. It's ugly, but I wanted to know if it works. The idea is that a non-existing function will be created to avoid the exception being thrown:

    $twig->addFunction(new Twig_Function('methodExist', function(Twig_Environment $twig, $name) {
        $hasFunction = $twig->getFunction($name) !== false;
    
        if (!$hasFunction) {
            // The callback function defaults to null so I have omitted it here
            return $twig->addFunction(new Twig_Function($name));
        }
    
        return $hasFunction;
    }, ['needs_environment' => true]));
    

    But it didn't work. I also tried to add a simple callback function to the new function with no success.

    I tried the same trick with filters, i.e.:

    {% if filterExists('sg_datatables_render') %}
        {{ datatable|sg_datatables_render }}
     {% else %}
        {{ datatable|datatable_render }}
    {% endif %}
    

    It didn't work either.


    Solution 1: {{ renderDatatable(datatable) }}

    Something like this does work (yay!):

    $twig->addFunction(new Twig_Function('renderDatatable', function(Twig_Environment $twig, $datatable) {
        $sgFunction = $twig->getFunction('sg_datatables_render');
    
        if ($sgFunction !== false) {
            return $sgFunction->getCallable()($datatable);
        }
    
        return $twig->getFunction('datatable_render')->getCallable()($datatable);
    }, ['needs_environment' => true]));
    

    And then in Twig:

    {{ renderDatatable(datatable) }}
    

    The renderDatatable function is specific to rendering datatables, i.e. it's not a general/multipurpose function like your methodExist is, but it works. You can of course try to create a more general implementation yourself.


    Solution 2: {{ fn('sg_datatables_render', datatable) }}

    Here's a more general approach. Create an additional Twig function to accompany methodExist:

    $twig->addFunction(new Twig_Function('fn', function(Twig_Environment $twig, $name, ...$args) {
         $fn = $twig->getFunction($name);
    
         if ($fn === false) {
             return null;
         }
    
         // You could add some kind of error handling here
         return $fn->getCallable()(...$args);
     }, ['needs_environment' => true]));
    

    Then you could modify your original code to this:

    {% if methodExist('sg_datatables_render') %}
        {{ fn('sg_datatables_render', datatable) }}
     {% else %}
        {{ datatable_render((datatable)) }}
    {% endif %}
    

    Or even use the ternary operator:

    {{ methodExist('sg_datatables_render') ? fn('sg_datatables_render', datatable) : datatable_render(datatable) }}
    

    PS

    Here's how I'd write the methodExist function:

    $twig->addFunction(new Twig_Function('methodExists', function(Twig_Environment $twig, $name) {
         return $twig->getFunction($name) !== false;
     }, ['needs_environment' => true]));
    
    1. I added s to the end of the function's name because the function checks whether a method/function exists.
    2. I added ['needs_environment' => true] so I can use $twig instead of $this->container->get('twig'). (Kudos to yceruto for this tip.)
    3. getFunction returns false if the function doesn't exist (see the docs), so I simplified the function body to a single-line return statement.
    0 讨论(0)
提交回复
热议问题