SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    SitePoint Guru
    Join Date
    Dec 2005
    Posts
    982
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thoughts on a "Micro-Template" System

    I'm designing an application where the user can log in to the backend and update message templates. In these message templates there's a big list of variables they can use that would be replaced at runtime. Right now the messages could look something like this:
    Thank you for placing order #{{order_number}}. Currently {{backorders}} of your items are on backorder with our suppliers. Your order will ship out via {{carrier_company}} within 24 hours. ...
    When displaying the message I simply go through and replace any {{$x}} with $array[$x]. It's pretty barbaric, so I was curious if anyone knows of anything better out there? I'm not looking for anything full blown like smarty because these messages very short and are going to be updated by non-programmers. I would love to be able to add some conditionals into the mix (check for backorders before telling them they have 0, etc.), but that isn't really required.
    MySQL v5.1.58
    PHP v5.3.6

  2. #2
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The intl extension could be a starting point.

    PHP Code:
    echo msgfmt_format_message('en_GB''Price {0,number,currency} ordered on {1,date,full} {1,time,full}', array(10.50time()))); 
    Will output (in UTF-8)

    Code:
    Price 10.50 ordered on Wednesday, 19 November 2008 18:02:54 GMT
    May not want to present the ICU message format to the users, but if got a list of variables, their types, and how they should be formatted, then converting from a friendlier string to the ICU version shouldn't be difficult.

  3. #3
    SitePoint Addict SirAdrian's Avatar
    Join Date
    Jul 2005
    Location
    Kelowna, BC
    Posts
    289
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    All you really need is an array of variables and one str_replace call.
    Adrian Schneider - Web Developer

  4. #4
    SitePoint Guru
    Join Date
    Dec 2005
    Posts
    982
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ren, although that looks like it may have possibilities because it would seem that I could make default values easily, I don't understand the syntax and the manual doesn't seem to have much info about it. It just refers you to umsg_autoQuoteApostrophe. Do you maybe have more information?

    SirAdrian, that's basically what I'm diong now. I'm not overly impressed with this strategy because it just seems lacking. Here's a snippet of the current code:
    PHP Code:
    if (preg_match_all('/\{\{([a-z0-9_]+)\}\}/is'$message$matches)) {
        foreach (
    $matches[1] as $var) {
            
    $message str_replace('{{' $var '}}', ((isset($translations[$var])) ? $translations[$var] : ''), $message); //if the translation was not given, {{var}} is at least removed
        
    }

    MySQL v5.1.58
    PHP v5.3.6

  5. #5
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

  6. #6
    Theoretical Physics Student bronze trophy Jake Arkinstall's Avatar
    Join Date
    May 2006
    Location
    Lancaster University, UK
    Posts
    7,062
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    You could do this instead of your previous code, for cleaner code:
    PHP Code:
    <?php
    function getMessage($matches){
        global 
    $translations;
        
    $match $matches[1];
        return (
    array_key_exists($match$translations)) ? $translations[$match] : null;
    }
    preg_replace_callback('/\{\{([a-z0-9_]+)\}\}/is''getMessage'$message);
    Jake Arkinstall
    "Sometimes you don't need to reinvent the wheel;
    Sometimes its enough to make that wheel more rounded"-Molona

  7. #7
    SitePoint Zealot
    Join Date
    May 2008
    Location
    Montreal
    Posts
    155
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    In my previous template engines I had variables as {$var_name}, route variables as {/folder/controller/action/} (this returns a URL with the specific route appended to it), and finally translatable text as {@hello world}.

    within a variable there could be: {$var_name.hello}. If, in PHP, $var = $scope->getVar('var_name');, then the .hello part would be found in either $var->hello or $var['hello'], depending on the type of $var.

    Another option was filters on variables, e.g.: {$var_name|filter_function}. If we go back to using $var, then {$var_name|filter_function} becomes, in PHP, filter_function($var);. This is extended to function composition, where: {$var_name|filter_a|filter_b} becomes filter_b(filter_a($var)).

    Finally, variables could be put into route variables, e.g.:

    {/path/to/$action/} and all possibilities were available, e.g.: {/path/to/$action.hello|filter/}

    Also, {//} == {/} == current URL. This implies that the above complex path can be decomposed into: {/path/to/}{$action.hello|filter}/ and further into: {/}path/to/{$action.hello|filter}/

    Although all routes can thus be written as {/}..., putting the entire route into the route variable adds more meaning than simply using {/} everywhere to represent the URL.

  8. #8
    SitePoint Addict SirAdrian's Avatar
    Join Date
    Jul 2005
    Location
    Kelowna, BC
    Posts
    289
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Basic example
    PHP Code:
    <?php

    $template 
    '{{name}} has {{posts}} posts.';

    $data = array(
        
    'name'  => 'Adrian',
        
    'posts' => 266
    );

    $find $replace = array();

    foreach (
    $data as $variable => $value)
    {
        
    $find[] = '{{' $variable '}}';
        
    $replace[] = $value;
    }

    print 
    str_replace($find$replace$template);
    Why do you want something more advanced? You're not really giving us any ideas of features you want or ways that your current system is not working.

    If you want conditions in it, then I'd just suggest one of the popular engines because they will give you way more flexibility, even if you don't use all the features.
    Adrian Schneider - Web Developer

  9. #9
    SitePoint Zealot
    Join Date
    May 2008
    Location
    Montreal
    Posts
    155
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's usually easiest, as arkinstall showed, to either do a preg_replace or preg_replace_callback. Usually what I do is compile templates to PHP. So, I might do the following:

    PHP Code:
    <?php
    $compiled 
    preg_replace(
        
    "~\{\$[a-z0-9_-]+(\.[a-z0-9_-]+)*(\|[a-z0-9_]+)*\}~i"
        
    '<?=$scope->getVar("\\1", "\\2", "\\3")?>'
        
    $source
    );
    And then I either include the file if it's compiled or eval it if I just compiled it. The convenience with either compilation (or just getting variables by function call) is that you can make what's supported in variables more robust and you can also create your own lexical scopes.

    This is also an obvious use case for regular expressions. Although it's clear that a str_replace() with a large array of elements does work, it is horribly inefficient. The likely implementation in C is just an independent search & replace for each element in the array. Regular expressions allow you to generalize your solution so that a single pass over the text is necessary, instead of N passes where N = count($data).

  10. #10
    SitePoint Guru
    Join Date
    Dec 2005
    Posts
    982
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I admire your template system Peter. I wish I had a system that actually used the MVC model so that I could try to implement what you showed, but that is still a topic I haven't had time to grasp.

    So what I did do, was something I said I didn't want to in the first post. I went with Smarty templates and extended a new resource called text so that I could just pass the template as a string opposed to an actual tpl file (my templates are small and stored in the database). I appreciate the help and I still welcome feedback.
    MySQL v5.1.58
    PHP v5.3.6

  11. #11
    SitePoint Zealot
    Join Date
    May 2008
    Location
    Montreal
    Posts
    155
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    BrandonK, the template system is independent of MVC.

    If you find that Smarty meets your needs then good!


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •