Twig non consente di farlo direttamente. È possibile aggiungere una semplice funzione a Twig per gestire l'esecuzione di chiusure o avvolgere la chiusura in una classe per poter utilizzare la funzione di attributo di Twig (poiché chiamando direttamente attribute(_context, 'myclosure', args)
si attiverà un errore irreversibile in quanto Twig restituirà la chiusura direttamente e ignorare gli argomenti dati poiché _context
è un array).
Una semplice estensione Twig che raggiunge questo scopo sarebbe simile a Symfony 2.8+. (Per Symfony 4, vedere la 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';
}
}
Poi, nei modelli, è sufficiente chiamare eseguire:
{{ execute(closure, [argument1, argument2]) }}
senza estendere Ramoscello, un modo per aggirare questo problema è utilizzare una classe che funge da wrapper per la chiusura e utilizzare la funzione attribute
di Twig in quanto può essere utilizzata per chiamare un metodo di un oggetto.
// 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());
}
}
Poi, è sufficiente dare un esempio ClosureWrapper al modello durante il rendering al posto della chiusura stessa:
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]);
}
...
Alla fine, nel modello, è necessario utilizzare attribute
per eseguire la chiusura si è definito nel controller:
// Displays 12
{{ attribute(closure, 'execute', [4, 6]) }}
Tuttavia, questo è un po 'ridondante, internally, ilLa funzione 10 di Twig decomprime anche gli argomenti dati. Usando il codice precedente, per ogni chiamata, gli argomenti vengono successivamente decompressi, imballati e decompressi di nuovo.
Grazie! Ma questa soluzione non funziona per me dal momento che la logica è variabile – Carles
Cosa intendi con "la logica è variabile"? – Terenoth
Potrebbe essere molte diverse funzioni condizionali, con condizioni diverse. Considero che non è efficiente mettere tante estensioni ramoscello come condizionali diversi perché ucciderebbe le prestazioni sul rendering dei template. – Carles