如何在Symfony2 Twig模板中调用静态函数

时间:2015-10-03 07:49:25

标签: php symfony static twig

如何在不通过控制器的情况下在树枝模板中调用我的静态函数?

例如:

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

我的静态课程:

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

    public static function getData() {
        ...

        return $data;
    }
}

3 个答案:

答案 0 :(得分:7)

不是编写Twig扩展,而是更简单/更少膨胀的解决方案有时可以简单地使用静态方法将类的新实例传递给twig。

例如

struct NullType { };

template<class T, class U>
struct OptionsList
{
  typedef T Head;
  typedef U Tail;
};

template<class T, class... U>
struct OptionsList2
{
  typedef T Head;
  typedef typename std::conditional<sizeof...(U) == 0, NullType, OptionsList2<U...>>::type Tail;
};

template<int n, typename N>
struct Option
{
  enum {
    int_mapping = n
  };
  typedef N MappedType;
};

template<int, int> struct CheckMappedInt;

template<int n>
struct CheckMappedInt<n, n>
{
  enum { is_the_same = 1};
};

template<int n, int m>
struct CheckMappedInt
{
  enum { is_the_same = 0};
};

template<typename OLT, int n> struct FindTypeForMapping;

template<int n>
struct FindTypeForMapping<NullType, n>
{
  typedef NullType mapped_type;
};


template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList<OP, Tail>, n>
{
 private:
  enum {temp  = CheckMappedInt<OP::int_mapping, n>::is_the_same };
  typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
 public:
  typedef typename std::conditional<
          temp == 1,
          typename OP::MappedType,
          temp_type>::type mapped_type;
};

// Added this after SoryTellers comment
template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList2<OP, Tail>, n>
{
 private:
  enum {temp  = CheckMappedInt<OP::int_mapping, n>::is_the_same };
  typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
 public:
  typedef typename std::conditional<
          temp == 1,
          typename OP::MappedType,
          temp_type>::type mapped_type;
};

#define OPTION_LIST_1(op1)                                          OptionsList<op1, NullType>
#define OPTION_LIST_2(op1, op2)                                     OptionsList<op1, OPTION_LIST_1(op2)>
#define OPTION_LIST_3(op1, op2, op3)                                OptionsList<op1, OPTION_LIST_2(op2, op3)>
#define OPTION_LIST_4(op1, op2, op3, op4)                           OptionsList<op1, OPTION_LIST_3(op2, op3, op4)>
#define OPTION_LIST_5(op1, op2, op3, op4, op5)                      OptionsList<op1, OPTION_LIST_4(op2, op3, op4, op5)>
#define OPTION_LIST_6(op1, op2, op3, op4, op5, op6)                 OptionsList<op1, OPTION_LIST_5(op2, op3, op4, op5, op6)>
#define OPTION_LIST_7(op1, op2, op3, op4, op5, op6, op7)            OptionsList<op1, OPTION_LIST_6(op2, op3, op4, op5, op6, op7)>
#define OPTION_LIST_8(op1, op2, op3, op4, op5, op6, op7, op8, op9)  OptionsList<op1, OPTION_LIST_7(op2, op3, op4, op5, op6, op7, op8)>
#define OPTION_LIST_9(op1, op2, op3, op4, op5, op6, op7, op8, op9)  OptionsList<op1, OPTION_LIST_8(op2, op3, op4, op5, op6, op7, op8, op9)>


int main(int argc, char* argv[])
{
  typedef Option<1, char> o1;
  typedef Option<2, int> o2;

  // Works
  typedef OPTION_LIST_2(o1, o2) ol;
  typedef typename FindTypeForMapping<ol, 1>::mapped_type ResolvedType; // Works

  typedef OptionsList2<o1, o2> ol2;
  typedef typename FindTypeForMapping<ol2, 1>::mapped_type ResolvedType2;
  /*
 error: invalid use of incomplete type ‘struct FindTypeForMapping<Option<2, int>, 1>’
   typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
  */    
}

并在树枝上:

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

答案 1 :(得分:6)

您无法在树枝模板中直接调用PHP。您需要创建一个过滤器或函数来执行您正在查找的内容。

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

然后在你的树枝模板中做:

{{ MyStaticClass('getData') }}

当然,上面的例子假设MyStaticClass在你的任何地方的范围内。

Symfony示例

您必须创建树枝扩展。示例如下:

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 "?";
        }
    }
}

这是我创建的一个扩展示例,用于将货币从一种货币转换为另一种货币。

要实现它,您需要在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 ]

然后如上所述,在树枝内我可以使用{{ convertCurrency(55505, 'CAD', 'USD) }}

调用该类和函数

答案 2 :(得分:1)

一种通用方法是注册一个名为engine.Runtime.IO.RedirectToConsole(); TextWriter _writer = TextWriter.Synchronized(new TextBoxWriter(textBox1)); Console.SetOut(_writer); 的Twig帮助程序函数以进行调用。

callstatic

这种方法的主要优点是它可以与任何类和方法组合一起使用。

用法:

$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);
}));

它还支持参数:

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