12

How to call my static function in twig template without passing through controller?

For example:

...
{{ MyStaticClass::getData() }}
...

My Static Class:

class MyStaticClass {
    const v1 = 'Value1';
    const v2 = 'Value2';
    ...

    public static function getData() {
        ...

        return $data;
    }
}

3 Answers 3

20

Instead of writing a Twig extension an easier / less bloated solution can sometimes be to simply pass a new instance of the class with the static methods to twig.

eg

// ...
$viewVars['MyStaticClass'] = new MyStaticClass();
// ...
$html = $twig->render('myTemplate.html.twig', $viewVars);

and in twig:

{{ MyStaticClass.getData() }}
Sign up to request clarification or add additional context in comments.

Comments

16

You cannot directly call PHP in a twig template. You'll need to create a filter or function to do what you're looking.

$twig         = new Twig_Environment($loader, $params);
$twigFunction = new Twig_SimpleFunction('MyStaticClass', function($method) {
    MyStaticClass::$method
});
$twig->addFunction($twigFunction);

Then in your twig template just do:

{{ MyStaticClass('getData') }}

Of course the above example assumes MyStaticClass is within the scope of wherever you're twig.

Symfony Example

You must create a twig extentions. Example below:

namespace PurpleNeve\Web\PNWebBundle\Extensions;

use PurpleNeve\Web\PNWebBundle\DependencyInjection\CurrencyConverter;

class TwigCurrency extends \Twig_Extension
{
    private $converter;

    public function __construct(CurrencyConverter $converter)
    {
      $this->converter = $converter;
    }

    public function getName()
    {
        return 'currency';
    }

    public function getFilters()
    {
        return array(
            'convertCurrency' => new \Twig_Filter_Method($this, 'getConversionBetween')
        );
    }

    public function getConversionBetween($amount, $isoFrom, $isoTo="USD")
    {
        try {
          $value = $this->converter->convertAmount($amount, $isoFrom, $isoTo);
          return round($value,2);
        } catch(\Exception $e) {
          return "?";
        }
    }
}

This is an example of an extension I created to convert currency from one currency to another in twig.

To implement it, you need to create a service object for it in your services.yml

parameters:
    currency_converter.class: PurpleNeve\Web\PNWebBundle\DependencyInjection\CurrencyConverter

services:
    currency_converter:
        class: "%currency_converter.class%"
        arguments : [@doctrine.orm.entity_manager]

    twig.extension.currency:
        class: PurpleNeve\Web\PNWebBundle\Extensions\TwigCurrency
        tags:
            - { name: 'twig.extension' }
        arguments : [ @currency_converter ]

Then as above, within twig I can call that class and function using {{ convertCurrency(55505, 'CAD', 'USD) }}

8 Comments

I see, where to add the above code? What is "within the scope of wherever you're twig" that you referring?
Whatever file is rendering your twig template. Add that code in just before the render.
Within scope means, that your class is reachable/callable from where you declare the code above.
You mean my controller just right before I call render?
I've added an example of an extension I had to write for twig in one of my projects to convert currencies.
|
14

A generic approach is to register a Twig helper function named callstatic to make the call.

$twig->addFunction(new \Twig_SimpleFunction('callstatic', function ($class, $method, ...$args) {
    if (!class_exists($class)) {
        throw new \Exception("Cannot call static method $method on Class $class: Invalid Class");
    }

    if (!method_exists($class, $method)) {
        throw new \Exception("Cannot call static method $method on Class $class: Invalid method");
    }

    return forward_static_call_array([$class, $method], $args);
}));

The main advantage of this approach is that it will work with any class and method combination.

Usage:

{# This will call \Mynamespace\Mypackage\Myclass::getStuff(); #}
{% set result = callstatic('\\Mynamespace\\Mypackage\\Myclass', 'getStuff') %}

It also supports arguments:

{# This will call \Mynamespace\Mypackage\Myclass::getStuff('arg1', 'arg2'); #}
{% set result = callstatic('\\Mynamespace\\Mypackage\\Myclass', 'getStuff', 'arg1', 'arg2') %}

1 Comment

Quite the elegant solution! +1 for teaching me about forward_static_call_array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.