PHP - Passing PHP functions within TWIG templates - php

I'm trying to figure out a way that I can pass PHP code directly within the templates in TWIG without having to create separate extensions for each function. Basically a simple function that could parse out the PHP and run the code in the template.
Example:
$function = new Twig_SimpleFunction('php_parse_function', function () {
//parse php code here
});
$twig->addFunction($function);
Use-case Example:
{{ php_parse_function | php code }}
The problem with doing something like this is that I would have to include an entire code-block in a string, which is to print html encapsulated in another string, which will have class/other-attributes in another layer of quotes.
Example:
{{php_parse_function | "echo '<section class=\'Yo\' id=\'2\'>'</section>" }}
So is there a workaround for something like this?

EDIT (after question edit)
No, It's not possible to execute php code directly from Twig. You can create filters or functions and pass strings as arg.
How? This way (orginal answer):
Anywhere inside the controller you're loading Twig:
// ...
$twig = new Twig_Environment($loader, $params); // load Twig env
$tsf = new Twig_SimpleFunction('fooTwig', function ($str) {
return eval($str);
});
$twig->addFunction($tsf);
// ...
Then:
{{ fooTwig('echo "Hello, World! What kind of sorcery is this? F in hex is "; echo hexdec("F");') }}
And remember you can use filters too!
Controller:
// ...
$twig = new Twig_Environment($loader, $params); // load Twig env
$tsf = new Twig_SimpleFilter('fooTwig', function ($str, $fn) {
$args = array_merge(array($str), array_slice(func_get_args(), 2));
return call_user_func_array($fn, $args);
});
$twig->addFilter($tsf);
// ...
Then:
{{ 'F'|fooTwig('hexdec') }}
If you are using Symfony2 or any other framework, is the same logic. You should just investigate where to add the Twig simple function/filter.

Related

Can we edit a mustache template in runtime?

Can I add new nodes to mustache template at run-time in PHP? Let's say below is a code where ProductDetails will contain few single products:
{{#ProductDetails}}
{{#SingleProduct}}
{{OldDetail}}
{{/SingleProduct}}
{{/ProductDetails}}
I want to add a new node like {{NewDetail}} just after {{OldDetail}} through some function in run-time(i.e just before I am compiling the template as these templates have been shipped to customers in such a way that only code to compile can be changed but not the template)? I don't want to do string manipulation(customers created few new templates with above parameters present at least but the spacing may change & few new entries can be added by them around nodes). Does mustache library provide any functions for that?
If I were you, I will try Lambdas.
Template.mustache will be like this:
{{#ProductDetails}}
{{#SingleProduct}}
{{OldDetail}}
{{/SingleProduct}}
{{/ProductDetails}}
And codes will be like:
$Mustache = new Mustache_Engine(['loader' => new Mustache_Loader_FilesystemLoader($YOUR_TEMPLATE_FOLDER),]);
$Template = $Mustache->loadTemplate('Template');
$OriginalOldDetail = '<h1>this is old detail</h1>';
echo $Template->Render([
'ProductDetails' => true,
'SingleProduct' => true,
'OldDetail' => function($text, Mustache_LambdaHelper $helper){
// Render your original view first.
$result = $helper->render($text);
// Now you got your oldDetail, let's make your new detail.
#do somthing and get $NewDetail;
$NewDetail = $YourStuff;
// If your NewDetail is some mustache format content and need to be render first.
$result .= $help->render($NewDetail);
// If is some content which not need to be render ? just apend on it.
$result .= $NewDetail;
return $result;
}
]);
Hope that will help.
(English is not my first language so hope you can understand what I'm talking about.)

Laravel blade hardcode variable on compile

I'm moving some of my view strings to config because I want to use the same code for similar sites, and I'm wondering if there's a way to avoid a call to Config:: or Lang:: on every runtime.
<h1>{{ Config::get('siteName') }}</h1>
blade makes in into
<h1><?php echo Config::get('siteName'); ?></h1>
But I want it to be just plain HTML like
<h1>MySite</h1>
My approach is trying to make this when Blade compiles the views into plain PHP / HTML , is there any built-in way to do this? I've tried with some Blade methods like #string with no results
Thanks
On your controller do this
$siteName = Config::get('app.siteName');
View::make('xxx', array('siteName' => $siteName))
for example
And you will be able to retrieve te variable siteName on your view with only
{{$siteName}}
Hope this will help (Or maybe I doesn't understand the problem)
OK solved it by extending Blade
I created a blade tag such as
#hardcodeConfig('siteName')
And in my blade_extensions I did this:
Blade::extend(function($view, $compiler)
{
$pattern = $compiler->createMatcher('hardcodeConfig');
$matches = [];
preg_match_all($pattern, $view, $matches);
foreach($matches[2] as $index => $key){
$key = str_replace([ "('", "')" ], '', $key);
$configValue = \Config::get( $key );
$view = str_ireplace($matches[0][$index], $configValue, $view);
}
return $view;
});
This does exactly was I was looking for, I created one for Config and another for Lang

Allowing users to make template- Scan code for functions

I am currently creating a web app and I would like to allow my users to create a template. I would only allow them to use HTML and some functions to get some values, so I have some functions like
getDescription(); but since its PHP I also have other function (e.g. phpinfo();) which I don't want them to use.
Is it possible to set a filter (like in_array) to check if functions other than declared are used?
Or is there an Template engine or something else which does that.
I am very new to templating and I couldn't find anything.
If they are only creating HTML templates, you could allow them to put for example;
<div>
[PHP]getDescriptions()[PHP]
</div>
<div>
[PHP]phpinfo()[/PHP]
</div>
Then in your parsing file when they save or whatever, you could have
$allowedFunctions = array('getDescriptions');
$input = '';//html from the template
foreach($allowedFunctions as $key => $value){
$myVal = $value();
$input = str_replace('[PHP]'.$value.'()[/PHP]',$myVal,$input);
}
This would replace [PHP]getDescriptions()[/PHP] with whatever is returned from getDescriptions()...
and phpinfo() wouldnt change.
you can check if a function exists with function_exists. If you want them to use the functions you defined for that purpose only you could prefix those function with something like 'tpl_*". like this:
function tpl_getDescription() {/*code here*/}
and then when you user tries to implement a function like getDescription you add "tpl_" to it and check if that function exists with function_exists().
if(function_exists('tpl_' . $userFuncName))
{
call_user_func('tpl_' . $userFuncName)
}
that way even if the user tries to evoke a native php function tpl_ will be prefixed and if will return false.
Yes, you could easily make a script that enumerates all user functions in an external file. Lets say you have this "template", template.php :
<?
function getDescription() {
}
function userFunc() {
}
function anotherFunction() {
}
?>
then you could get a list of all functions in template.php this way :
<?
include('template.php');
$functions = get_defined_functions();
echo '<pre>';
print_r($functions['user']);
echo '</pre>';
?>
would output :
Array
(
[0] => getdescription
[1] => userfunc
[2] => anotherfunction
)
I would call this script through AJAX, like getfunctions.php?file=template.php which returned a JSON with all user functions inside template.php.

How to change mustache template data dynamically

I have just started working with Mustache template engine. I am currently using PHP implementation of it (https://github.com/bobthecow/mustache.php/wiki). I am using helpers to manipulate the way data is rendered.
$data = array("name" => "abhilash");
$template = "Hello {{name}}, {{#bold}}Welcome{{/bold}}";
$m = new Mustache_Engine(array(
"helpers" => array(
"bold" => function($content) {
return "<b>$content</b&gt";
})));
$html = $m->render($template, $data);
With the help of this I am able to render 'Welcome' with bold font. I would like to know if it is possible to manipulate $data with the help of helper function. For example if the template is like below and I have a helper function registered as dataSource, I would like to use it to collect some data (say key-value pair) from datasource_func_name() and append it to $data.
{{#dataSource}}datasource_func_name{{/dataSource}}
Hi {{name}}
That's normally not how you would use helpers. However, Mustache basically expects a data souce, so why not inject it directly?
$html = $m->render($template, $dataSource);

Mustache php gettext()

I am experimenting with kostache, "mustache for kohana framework".
Is there any way I can use simple PHP functions in mustache template files.
I know logic and therefore methods are against logic-less design principle, but I'm talking about very simple functionality.
For example:
gettext('some text') or __('some text')
get the base url; in kohana -> Url::site('controller/action')
Bobthecow is working on an experimental feature that will allow you to call a function as a callback.
Check out the higher-order-sections branch of the repository and the ticket to go with it.
You could use "ICanHaz" http://icanhazjs.com/
and then you can declare your mustache templates as
<script id="welcome" type="text/html">
<p>Welcome, {{<?php echo __('some text') ?>}}! </p>
</script>
Well, you can do this now with Bobthecow's implementation of Mustache Engine. We need anonymous functions here, which are passed to the Template Object along with other data.
Have a look at the following example:
<?php
$mustache = new Mustache_Engine;
# setting data for our template
$template_data = [
'fullname' => 'HULK',
'bold_it' => function($text){
return "<b>{$text}</b>";
}
];
# preparing and outputting
echo $mustache->render("{{#bold_it}}{{fullname}}{{/bold_it}} !", $template_data);
In the above example, 'bold_it' points to our function which is pasalong withwith other data to our template. The value of 'fullname' is being passed as a parameter to this function.
Please note that passing parameters is not mandatory in Mustache. You can even call the php function wothout any parameters, as follows:
<?php
# setting data for our template
$template_data = [
'my_name' => function(){
return 'Joe';
}
];
# preparing and outputting
echo $mustache->render("{{my_name}} is a great guy!", $template_data); # outputs: Joe is a great guy!
Credits: http://dwellupper.io/post/24/calling-php-functions-for-data-in-mustache-php

Categories