I'm hoping someone can point me to the right direction in this.
Lets say I store Smarty template in database. It can look like this:
{currentusername UserID="5"}
The currentusername is a custom function to get the username. All displays correctly when used in a template. But what if I wanted to get the resolved currentusername function in my php code?
Basically I would get the template from the database, resolve it through smarty and then used the currentusername further in the code.
Is that possible?
Edit so it can be better understood. I have a this piece of code:
require('smarty/libs/Smarty.class.php');
$smarty = new Smarty;
$macro = '{currentusername UserID="5"}';
$resolvedmacro = ""; // this should contain the "Jerry";
function smarty_function_currentusername($params, &$smarty){
$UserID = $params["UserID"];
if ($UserID == 5){
return "Jerry";
}
else{
return "I dont know this guy";
}
}
Can I somehow resolve the $macro through smarty so the variable $resolvedmacro would contain the correct value?
Smarty can render a string as though it was a template using the string: or eval: "resource types" - see the documentation on String Template Resources for details.
You can then use $smarty->fetch() to get the output of that "template" into a normal PHP variable:
require('smarty/libs/Smarty.class.php');
$smarty = new Smarty;
$macro = '{currentusername UserID="5"}';
$resolvedmacro = $smarty->fetch('string:' . $macro);
There is a wider question of why you want to do this, and whether Smarty is the right tool for the job - for instance, if there are a limited number of callbacks possible, it might be over-complicating things to use Smarty to resolve them rather than just storing the name of the callback and its arguments and running it through a switch statement.
Note: The string: and eval: resource types were added in Smarty 3; if for some reason you need to use Smarty 2, you will need to write or find a resource plugin to do the same job. You could also write a resource plugin for either version which fetched a particular macro from the database and rendered it in one step; the docs for Smarty 3 are here.
Related
I have a plugin function which should be used to modify a given Smarty variable which is an array.
After reading the docs, it looks like this should be the way to do it:
$var = &$smarty->getTemplateVars($params['var']);
$var['blah'] = 'aaa';
... but it doesn't work. The array, as seen by other template code after the call to this plugin function, sees the array unmodified.
So, how can a plugin function modify a template variable?
Unless someone figures out a solution, it looks like it cannot be done in a "function" plugin type. It can be done in a "modifier", though.
I’ve been building an application with Kohana 3.3, and recently switched development from Coda 2 — a text editor — to PhpStorm 6 — an IDE.
PhpStorm 6 has been very handy in pointing out potential code smells; it prompted me to move from attaching data to views with the __set($key, $value) magic method to instead using the bind($key, $value) method.
Another thing that PhpStorm 6 is complaining about, is that I’m declaring fields dynamically.
I have subclassed Controller_Template, and I’m attaching my view to my template like this:
public function action_index() {
# Create the view
$view = View::factory('project/list');
# Attach the view to the template
$this->template->content = $view;
}
Apparently, content is declared dynamically. I’ve been checking up the class heirarchy, and I can't find the content property declared anywhere (hence why it’s dynamic, I suppose). Is this a code smell? Is dynamic declaration bad? Can I explicitly declare the content property somewhere?
As it is, the code works. I just want to understand why PhpStorm is giving me a notice, and whether or not I’m going about things the right way.
The advantage and disadvantage of PHP is dynamic typing. Its convenient in some cases, but irritating in another. You shown here irritating example. You know, that the $view is object which inherit from View (for example), so you know which functions you can use. If you don't mess anything, there will be View type object always.
Phpstorm don't have this information and thats why you see warning. He wants you also to be careful with this code but in this case you cannot do nothing. You cannot also cast $view to View like in Java:
$this->template->content = (View)$view; //impossible :(
$view and $this->template->content are dynamic typing variables and you cannot change it. Just take care to not assign another type to your variable and everything should work fine.
I wanted to add some info to the answer Kasyx is giving. Everything he says is correct but there is an alternative to set variables in kohana if you hate dynamic typing or like some clarity in what your views are doing. (Template is just another view ;) )
You can also set variables in views with the set() function (docs) eg:
$view->set('foo', 'my value');
I'm using this code in a views field template (in this case views-view-field--all-members--uid.tpl.php):
<?php
$users_friends = flag_friend_get_friends($user->uid);
$users_friends_ids = array();
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
?>
It basically gets the user ids of friends and puts them in an array so I can check if the field matches any of the user ids.
So my problem is that I don't want to have this within this template (for a few reasons), but if I don't I can't access the array. How can I make this array globally accessible?
Without knowing your "few reasons", I can't say if this is the answer for sure. My own reasons would probably be that I don't want the same code executing a bunch of times, and I'd rather not have the same exact code in multiple places.
I would then create a function with a static variable to hold the friends array.
function mymodule_get_friends_ids() {
// pull in the current global user variable
global $user;
// call up the static variable
static $users_friends_ids;
// return if this static var has already been set
if (is_array($users_friends_ids)) {
return $users_friends_ids;
}
// if we hit here, then this function has not been
// run yet for this page load.
// init array
$users_friends_ids = array();
// if user is anon, no need to go on
if (user_is_anonymous()) {
return $users_friends_ids;
}
// get friends array
$users_friends = flag_friend_get_friends($user->uid);
// build ids array
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
return $users_friends_ids;
}
Now in your templates, you can call mymodule_get_friends_ids() in as many places as you want, and the working code below the first return will only get executed the first time it is called.
Coder1's advice is very good - it keeps you from populating your global variable namespace with a lot of junk. It's probably the most "elegant." It might not be the easiest to use if you are rather new to PHP (which I'm guessing might be the case if it's hard to get your head around returning arrays, but that's ok).
However, if this is really a priority, you probably don't care about having one extra global variable.
I suppose I may be stating the obvious here - but you can, at pretty much any point in execution (provided the information you need has already been generated - e.g., the $user variable has been populated), do this:
$GLOBALS['users_friends_ids'] = /* your code goes here */
Then in your template, you access this by ...
$friendsArray = $GLOBALS['users_friends_ids'];
Or you can simply use the construct
global $user_friends_ids;
when you want to initialize the variable, or access it inside a function or class (which is the case for your template files - they are called inside functions, so you need to globalize or use the $GLOBALS array, which is "automagically" all of the variables active in the global namespace).
The most "logical" place to do this would be inside a module using one of the many hooks available, to execute this code only once. hook_init() might do it for you, if the user object is already loaded at this point (not sure, you'll have to test). But you might not want to figure out making Drupal modules (it's not that difficult).
If you are doing this inside a template (and though it's not good practice, many Drupal site owners with a beginning knowledge of PHP put everything in templates), you'll want to know which template code is being executed when. Node template code tends to be executed before page template code - which is logical, since otherwise the variables for node content in the page template wouldn't be populated.
If you have listings of nodes, they'll be calling this code multiple times, so you'll end up doing something similar to what Coder1 is describing. If you don't want to create your own small module, you could put the function declaration he's written in your theme's template.php file, since it's called only once. You don't want to put function declarations in the tpl.php files, since they are sometimes called more than once (and you aren't allowed to declare functions more than once).
If you have a hard time understanding the function and the return, you can always do something like this in your code (which is very, very inelegant - but it's better to have inelegant code that you do understand, than elegant code that's you don't).
if(!isset($GLOBALS['users_friends_ids'])) {
$GLOBALS['users_friends_ids'] = /* your code here */
}
I'm creating my own script using the CodeIgniter MVC framework. Now, i want users to easily modify the site functionality and adding their own without modifying the code which i've already written.
How do i make my site pluginable ?
EDIT: The users would be the site admins. Not the end user. Basically just like drupal or joomla. Want the admin to be able to create/add plugins to extend site functionality.
There may be a better way that's specific to CodeIgniter, but this is what I would do:
First, create functions for various "hook points" in your code. Say, a function named PreArticle that you call in your code, before an article is displayed.
Allow the user to write code like this:
addHook_PreArticle('funcToCall');
function funcToCall( &$articleText ) {
$articleText = str_replace('Hello', 'World', $articleText);
}
addHook_PreArticle is a function you've defined, which would add the passed string to some internal list. Then when the PreArticle function is called, each of those functions are executed, passing in any appropriate parameters that you define.
Many CMS's Like Joomla and Blogs like Wordpress use variable function names:
$function="phpinfo";
$function();
You could load this into an array to create a list of functions that can be overridden.
That's a perfect case to use the Observer Pattern.
http://devzone.zend.com/article/5
I'm using CodeIgniter, and will likely use their template library as I want to keep things extremely simple to use. The content for the template variables will come from the database, but I want the business admins to know what content areas are available. Basically the names of the parameters when they choose a specific template. For instance, Joomla uses an extra XML file that defines each area, whereas Wordpress uses comments within a page template to inform the system that the PHP file is a template. I like the Joomla approach because you don't have to parse the PHP file to find the areas, but I like the Wordpress approach because you don't have an extra XML file associated with every template. Are there other approaches that I'm missing?
I think the nicest way would be to add a small hack to the template parser class. The code looks quite readable and clean in system/libraries/Parser.php. You could insert a hook in that class that can be used to keep track of the variables. I don't know, if it works, but here's a snippet:
class CI_Parser {
var $varCallback;
function setVarCallback($callbackFunction) {
$this->varCallback = $callbackFunction;
}
...
function _parse_single(...) {
$callback = $this->varCallback;
$callback($key);
}
...
//Somewhere in your code
function storeVarName($variableName) {
// Persist the variable name wherever you want here
}
$this->parser->setVarCallback('storeVarName');
You could do this directly in the controller:
// in the controller
print_r($data);
$this->load->view("main", $data);
Or a little more rudimentary, but you could pass to the template a PHP array of variables (or an object):
// in the controller
$data = array();
$data["namespace"] = array(
"title" => "My website",
"posts" => array("hi", "something else")
);
$this->load->view("main", $data);
And then in the view, have a flag to print_r the namespace to show all the vars available, so that business admins know exactly what to use.
// in the view
if(isset($namespace["showAllVars"])) print_r($namespace);
One option would be to call token_get_all on the PHP file (only when your business admins are loading it up), and parse the output of that.
The best approach, in my opinion, is to keep the variable definitions in another place (such as a database table, or a separate file). This will help with testing (i.e., a programmer can't just remove a tag and it's gone) and making sure things are still working as you move on with the application development in time.
Another advantage is that your application logic will be independent from the templating engine.
On a side note, if you expect a lot of traffic, you may consider using smarty instead. We have done extensive testing with most of the templating engines around and smarty is the fastest.