2016-01-22 39 views
5

我正試圖執行一個位於樹枝模板上的數組內的閉包。下面你可以找到一個簡單的代碼片段,其中我想:在樹枝上執行封閉


//Symfony controller 
... 
$funcs = array(
    "conditional" => function($obj){ 
     return $obj->getFoo() === $obj::TRUE_FOO 
    } 
); 
$this->render('template_name', array('funcs' => $funcs)); 

{# Twig template #} 
{# obj var is set #} 
... 
{% if funcs.conditional(obj)%} 
<p>Got it</p> 
{% endif %} 

當嫩枝渲染模板,拋出一個異常抱怨數組字符串轉換

An exception has been thrown during the rendering of a template ("Notice: Array to string conversion") in "template_name.html.twig". 
500 Internal Server Error - Twig_Error_Runtime 
1 linked Exception: ContextErrorException » 

我會感謝您的幫助。

謝謝!

回答

1

您不能直接在您的Twig模板中執行閉包。但是,如果您需要在模板中調用一些PHP,則應該使用create a Twig Extension並將您的邏輯包含在內。

+0

謝謝!但是這個解決方案對我來說不起作用,因爲邏輯是可變的 – Carles

+0

你的意思是「邏輯是可變的」? – Terenoth

+0

它可能是許多不同的條件函數,具有不同的條件。我認爲將不同條件的分枝擴展放在一起效率不高,因爲它會導致模板呈現性能下降。 – Carles

1

枝條不允許直接做到這一點。你可以爲Twig添加一個簡單的函數來處理閉包的執行,或者將閉包封裝在類中以便能夠使用Twig的屬性函數(因爲直接調用attribute(_context, 'myclosure', args)會觸發致命錯誤,因爲Twig將直接返回閉包並且忽略給定的參數,因爲_context是一個數組)。


一個簡單的樹枝的擴展,實現這個目的應該是這樣的Symfony的2.8+。 (爲symfony1.2 4,看new documentation

// src/AppBundle/Twig/Extension/CoreExtensions.php 
namespace AppBundle\Twig\Extension; 

class CoreExtensions extends \Twig_Extension 
{ 
    public function getFunctions() 
    { 
     return [ 
      new \Twig_SimpleFunction('execute', [$this, 'executeClosure']) 
     ]; 
    } 

    public function executeClosure(\Closure $closure, $arguments) 
    { 
     return $closure(...$arguments); 
    } 

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

然後,在你的模板,你只需要調用execute:

{{ execute(closure, [argument1, argument2]) }} 

沒有延伸的樹枝,一個辦法來解決這個問題是使用一個類作爲封閉的包裝,並使用Twig的attribute函數,因爲它可用於調用對象的方法。

// src/AppBundle/Twig/ClosureWrapper.php 
namespace AppBundle\Twig; 

/** 
* Wrapper to get around the issue of not being able to use closures in Twig 
* Since it is possible to call a method of a given object in Twig via "attribute", 
* the only purpose of this class is to store the closure and give a method to execute it 
*/ 
class ClosureWrapper 
{ 
    private $closure; 

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

    public function execute() 
    { 
     return ($this->closure)(...func_get_args()); 
    } 
} 

然後,你只需要渲染的,而不是封閉自己的時候給一個ClosureWrapper實例模板:

use AppBundle\Twig\ClosureWrapper; 

class MyController extends Controller 
{ 
    public function myAction() 
    { 
     $localValue = 2; 
     $closure = new ClosureWrapper(function($param1, $param2) use ($localValue) { 
      return $localValue + $param1 + $param2; 
     }); 

     return $this->render('mytemplate.html.twig', ['closure' => $closure]); 
    } 

    ... 

最終,在你的模板,你需要使用attribute執行關閉你在控制器中定義:

// Displays 12 
{{ attribute(closure, 'execute', [4, 6]) }} 

然而,這是一個有點多餘的,internally,該Twig的10個函數也解包給定的參數。通過使用上面的代碼,對於每次調用,參數都會連續解壓縮,打包和解壓縮。