Can twig macros return values?

Viewed 6682

I'm trying to write a template in Twig. Inside it I would like it to perform some manipulations on the string data that comes from the controller. In particular, there's a common manipulation (convert from underscore_case to CamelCase) that I'd like to bring out into a separate function. Then later I can use it repeatedly like {% set x = magic(a) ~ magic(b) %}. However I cannot find how to make such a reusable function inside the template itself. There are macros, but those don't seem to be able to return values. Filters are another option that seem to fit the bill, but I can only define those on PHP side.

Can this be done? Or should I do all the advanced string manipulation controller-side? It kinda feels like I'm pulling parts of display logic in there; things that should be in the view.

3 Answers

Twig is for outputting data. If you need to "transform" the data you need to do that before you send it to twig or you need to extend twig

Ideally, all the data you send to twig is just variables and arrays that needs the least amount of manipulation on their own.

When you're actually "in" twig, the data processing can be assumed to be "done" and only needs to be outputted in the appropriate places with minimal logic to decide user interface styles.

So revisit your logic and prepare your data better before sending it to twig.

An example for extending a toolkit class that contains our magic methods to do real wizardry.

class CustomToolkit 
{
    public function magic_a($a) 
    {
        return strtolower($a);    }

    public function magic_b($b) 
    {
        return camel_case($b);
    }

    public function magic_tidle($a, $b) 
    {
        return $this->magic_a($a) ~ $this->magic_b($b);
    }
}

Then you add this to your twig instance. I added here a complete instantiation loop. if you have a service provider you can just grab the instance from there and add it to that one.

$twig = new Twig_Environment(new Twig_Loader_Array([
                                                      'html' => $contents
                                                   ]),[
                                                      'auto_reload' => true,
                                                      'debug' => false,
                                                   ]);
$twig->addExtension('toolkit', new CustomToolkit ());
echo $twig->render('html', $values);

Then in your twig code you should be able to do something along the lines of

{% set x = toolkit.magic_tidle("value","value_b") %} 

You are right, macros do not have return values and you cannot really make them have any. All they do is outputting strings.

Still, you are able to capture string output using set: https://twig.symfony.com/doc/2.x/tags/set.html
The syntax looks similar to this:

{% set var %}
    {{ call.macro() }}
{% endset %}

The output of the macro call is then stored inside var. You may want to strip the whitespace though.

But then, consider rethinking what you are doing. Is this still presentation logic, or is your controller simply "too lazy" to transform the strings prior to passing them to twig? If it's really presentation logic, simply adding a twig filter by extending twig surely is worth the hassle. Not only because your code becomes testable.

Can this be done?

Yes! However, Twig templates are not the ideal places to run logic. At least, we should do our best to avoid it. Instead, Controller should return what Twig template needs. Logic should run in Service, Utility, Helper (you name it) etc. and Controller returns it to Twig. Twig then just displays it.

Can twig macros return values?

Yes! Look at this example. It accepts parameters and returns (not a real "return" thing but you get the idea) something back.

Example:

Assuming that the data you are trying to manipulate is something simple.

use Doctrine\Common\Inflector\Inflector;

Controller
{
   action() {
      $data = Inflector::camelize('hello_world'); // This will become helloWorld

      return ....;
   }
}

Look into Inflector class. It has useful stuff.

Related