Dynamically "patching" templates
I have a little conception problem.
I created a View class that you use that way :
$view = new View('title');
$view->setTemplate('name_of_template');
$view->setVar('name', 'value');
$view->display();
The templates are simple PHP/HTML files that are included in the View class when display
is called.
Then I have "modules". They are objects which can be either activated or deactivated, and they should be allowed to change the behaviour of a page. However I don't want to change a script just because of a module : all the code belonging to it have to be in his class.
I already have some mechanisms. One of them is Events, a system similar to the classic listen/trigger pattern. You can specify parameters to be sent when an event is triggerred, and decide if some of them can be changed by the listening functions.
An event is triggered just before a page is sent to the client. Listeners can then change or add template variables.
However, I'd like modules to be able to add some elements in templates themselves, and I can't come up with a good way to do this. At the moment I have a method called in the templates where modules can add or change elements. Here's the prototype : patch($name, $replacement)
Let's say one of them wants to change a word into a link :
This is a <?=$this->patch('slot1', 'sentence')?> that can be "patched" by a module. <?=$this->patch('slot2', '')?> They can add elements between paragraphs.
The patch
calls can be "grabbed" by the module which can then change the word "sentence" into <a href="page.php">sentence</a>
, or add something in "slot2". If there isn't any module grabbing the call, the $replacement is displayed.
However I must add such calls in the templates every time a module needs to modify something. I'd prefer to leave the templates unchanged and program the "patc开发者_如何学运维h" in the module's class.
How would you do to allow modules to "patch" templates, knowing certain modules can be disabled and they shouldn't overwrite each other's changes ?
Edit : some more details.
- Most of the time modules' changes will be small additions or word changes.
- If I have to "mark" the templates in some way, I'd like to be able to do it once without having to add marks if a module needs it.
- The "patches" shouldn't rely on line numbers. They can rely on the contents to some extent, but as much as possible not on entire lines.
- I'd prefer a unified way for additions and modifications, but it's ok if I have two different methods.
- I'm already using output buffering (ob_start, etc) to include the chosen template into one global template.
- I'd prefer using str_replace over preg_replace which is slower, if I choose a system relying on these functions.
Your best bet in a case like that is to use a slimmer markup system. Something like:
This is a {link href="http://www.someurl.com/"}sentence{/link} that can be patched...
Capture the output of your templater using ob_start and ob_get_clean and then run your modules on that output by using a preg_match_all to get all instances of your shortened tags and parse them out. You can then loop through all the matches and replace each one with the rendered output from your modules.
In the example above, the parser would make a call to the "link" module and pass it a single parameter: an array in this format: array( 'href' => 'http://www.someurl.com/' )
That's your best bet to allow modules to overwrite template output without making numerous calls to preg functions. This would require a single preg function call to get all the tags. From there you can use string functions to replace data.
I would actually side with the comments above though and urge you to use a template engine like Smarty unless you have specific reasons for avoiding it. I use Smarty for many of my projects because it can be easily extended and provides excellent separation of PHP/Markup because of that.
精彩评论