1

Edit: Maybe I should make this part clear. A user is writing the template. So I want the syntax to be simple, and I can't trust them with powerful template engines.

So, I need a template engine that will be used to write emails, using tokens (easy) with conditional logic (less easy).

Example: Hello{if first_name} dear {first_name}{endif}, blah blah blah.

If first_name is not available, it should read: Hello, blah blah blah.

I was able to get it working using eval... but we all know eval is evil.

$body = preg_replace('/{if ([^{\|}]+)}/i', '<?php if(isset(\$tokens[\'$1\'])):?>', $body);
$body = preg_replace('/{endif}/i', '<?php endif;?>', $body);

Can anyone point me towards a tutorial on this one? I can't seem to find anything beyond simple token replacement.

Farzher
  • 13,934
  • 21
  • 69
  • 100
  • 5
    Any reasons for reinventing the wheel instead of using the established solutions? – raina77ow Jul 07 '12 at 16:57
  • Like @raina77ow said, why would you re-invent the wheel? Specially when you want not so simple features. – André Catita Jul 07 '12 at 17:00
  • [Swift Mailer](http://swiftmailer.org/) is an email sender library containing their own email template engine. – Mihai Stancu Jul 07 '12 at 17:00
  • I've written my own templating engine, but I am an experienced programmer and did this as an exercise to meet very specific requirements. They are difficult to implement efficiently without introducing bugs and vulnerabilities into your application. I would also recommend that you stick a standard one – TerryE Jul 07 '12 at 17:04
  • I'm fine with using a standard one. The only thing I found was Smarty, but it didn't work how I wanted it to. I also need tokens to have a default value if they're not available. Something like `{first_name|buddy}`. What can do this? – Farzher Jul 07 '12 at 17:14
  • I also don't want them to have to power of most template engines. Just token replace, and conditional logic. – Farzher Jul 07 '12 at 17:33
  • 1
    Take a look at Twig. http://twig.sensiolabs.org/ – ceejayoz Jul 07 '12 at 17:50
  • I would recommend [mustache](http://mustache.github.com/). This is a logicless language. Your example would be implemented as: `Hello {{#first_name}}dear {{firstname}} {{/first_name}}bla bla bla`. So you only have implicit if statements through the section tags. – Ikke Jul 07 '12 at 18:41
  • `mustache` looks awesome. It doesn't look like you can do `if,else` though... /: – Farzher Jul 07 '12 at 19:39
  • With Smarty, you could do something like `{first_name|default:"buddy"}`. Just write a customer `default` modifier. Any full featured template language will allow for such things. – Matthew Jul 07 '12 at 21:06
  • Is there like a safe mode for Smarty? The problem with these template engines is they're too powerful. I can't allow people to use the `{php}` tags... haha – Farzher Jul 08 '12 at 01:49
  • One could just use PHP.. – Ben Jul 09 '12 at 13:21

2 Answers2

0

As suggested above, I would use Mustache.js for this, it should accomplish everything you need. If all you want is "token replace and conditional logic," Mustache can be used to provide both:

Token Replace

Hello {{first_name}}

Conditional Logic

All though Mustache.js bills itself as "logic-less",

We call it "logic-less" because there are no if statements, else clauses, or for loops.

you can make logic-based decisions in your controllers, then pass those decisions to views--see How do I accomplish an if/else in mustache.js?. So, in your case something like this should work:

function( view ){

   if ( logged_in ) {
     var user = {
       first_name: "Jane",
       last_name: "Doe"
     };
   } else {
     var user = {
       first_name: "Buddy"
     };
   }

   // more template stuff...

}
Community
  • 1
  • 1
jbnunn
  • 6,161
  • 4
  • 40
  • 65
  • 1
    The php implementation of it would be more appropriate for the question asked.. https://github.com/bobthecow/mustache.php/ – Ben Jul 09 '12 at 13:25
  • Hey this isn't bad. Only problem is that the default value needs to be specified in the template! With this preferred syntax `{{first_name|buddy}}` If first_name is not set, just use the string `buddy` – Farzher Jul 09 '12 at 16:08
  • I suppose I could first parse the string myself, find the default values, remove them from the string, store them in that template function you showed me. Then finally run the string through mustache? Does that make sense? – Farzher Jul 09 '12 at 16:16
  • So what string are you talking about parsing first? (PS edited the code to use "Buddy" as a default) – jbnunn Jul 09 '12 at 16:19
  • Parsing this string `Hello {{first_name|buddy}}, blah blah.` A user is tying that into a textarea, they're the one defining the default value; It's not always the same default value. See the problem? – Farzher Jul 09 '12 at 16:44
  • Yeah I do now. Well, Mustache may not be the best choice for you then--if you're allowing your users to define the variables. I've built something similar before--but it used a lot of preg_match and str_replace, and had a standard "library" of acceptable placeholders. Smarty might get you there, but for the versatility you're looking for you may need to go homegrown. – jbnunn Jul 09 '12 at 22:10
  • I'm thinking I'll use Smarty or Mustache, but to get the syntax I want, I'll use preg_replace to find `{{first_name|buddy}}` and replace with the Smarty or Mustache version. Something like `{{if isset($first_name)}}{$first_name}{else}buddy{/if}`. Does this sound reasonable? – Farzher Jul 10 '12 at 13:50
  • Yes that should get you there – jbnunn Jul 10 '12 at 14:14
0

Using the comments from everyone, I was able to figure out how to quickly make my own secure template engine with custom syntax.

Let's say I want to make {first_name|buddy} be the first_name variable if it's set, but if it's not set use the string "buddy" as default.

Use a powerful template engine, like Smarty. Smarty has support for this, but I don't like the syntax {$first_name|default:"buddy"}

Replace all occurrences of your custom syntax with the correct syntax

preg_replace('/{([\w\s]+)\|([\w\s]+)}/', '{\$$1|default:"$2"}', $content);

Then just run it through Smarty. This is essentially the same as using eval, but secure. Thanks guys.

Farzher
  • 13,934
  • 21
  • 69
  • 100