tags:

views:

122

answers:

6

Currently I have a the following way of retrieving data from my DB:

$school->get('studentCount');

I required a shortcut to access these fields within the page and so came up with a format like this:

<p>Blah blah blah [[studentCount]]</p>

I have output buffering turned on but just need an easy way of replacing that key ('[[field-name]]') with its corresponding data from the DB.

If it was just one field I could do a str_replace on the output like this:

str_replace($output, '[[studentCount]]', $school->get('studentCount'))

Unfortunately that's not suitable. My ideal solution would grab whatever is between '[[' and ']]' and then run the 'get' method and replace the entire key ('[[...]]') with whatever is returned.

A: 

You need to write a parser to look through the $output to find what is between your delimiters and then call a function if it is defined. I assume you want to do it this way to save the calls until they are needed. I wrote a template parser that effectively worked this way. Unfortunately it wasn't in PHP.

jqs
+1  A: 

You will need to use regex to find things inside of two [[ and ]] and take that an insert what is in between into your ->get() function.

Function would be preg_replace

http://us2.php.net/preg-replace

jdhartley
Dependent on the size of the output, wouldn't preg-replace become expensive to use?
jqs
Yes--depending on how large each page is, it would eventually seriously bog down the server. He will need to find a replacement to this type of replacement. He could look into a better parse method, as you suggested. (or caching?)
jdhartley
+2  A: 

Well you could create two arrays, one with the field-name strings [[field-name]] and one with the responses $school->get('field-name'). Then throw those in str_replace as it supports arrays.

Example from PHP Manual:

$phrase  = "You should eat fruits, vegetables, and fiber every day.";
$healthy = array("fruits", "vegetables", "fiber");
$yummy   = array("pizza", "beer", "ice cream");
$newphrase = str_replace($healthy, $yummy, $phrase);
// Resulting String: "You should eat pizza, beer, and ice cream every day."

If you still wanted to implement your suggestion (finding all [[]]s and replacing them), I'll try to write up a quick function.

Edit: Here are two methods of doing it via your request:

$html = "Hello, [[FirstName]]!  Welcome to [[SiteName]].";
$count = preg_match_all("/\[\[([\w]+)\]\]/", $html, $matches);
for ($x = 0; $x < $count; $x++)
  $html = str_replace($matches[0][$x], $school->get($matches[1][$x]), $html);

Or using arrays:

$html = "Hello, [[FirstName]]!  Welcome to [[SiteName]].";
$count = preg_match_all("/\[\[([\w]+)\]\]/", $html, $matches);
for ($x = 0; $x < $count; $x++)
  $matches[1][$x] = $school->get($matches[1][$x]);
$html = str_replace($matches[0], $matches[1], $html);
St. John Johnson
A: 

Thanks for the responses so far. I did think about using str/preg _replace with arrays but I wanted the key ('[[...]]') to directly tie in with the 'get' method, so it's fully expandable. I don't want to have to add to two different arrays every time a new field is added to the DB.

In JavaScript, for example, I would achieve it like this: (JavaScript allows you to pass an anonymous function as the 'replacement' parameter in its equivalent of preg_replace):

('this is the output blah blah [[studentCount]]').replace(/\[{2}([^\[]+)\]{2}/g, function($0, $1) {
    get($1);
})
J-P
+1  A: 

Assuming you can cache the result, a regex and file cache is a great method to do this. First you convert the file:

function cache_it($filename, $tablvar) {
    $tmplt = file_get_contents($filename);
    $tmplt = preg_replace('/\[\[(.+)\]\]/', 
             '<?php echo $' . $tablevar . '->get(\1);?>',
             $tmplt);
    file_put_contents($filename . '.php', $tmplt);
}

Then whenever you need to access the file.

function print_it($filename, $tablevar, $table) {
    $_GLOBAL[$tablevar] = $table;
    include $filename . '.php';
    unset($_GLOBAL[$tablevar]);
}

You probably want to check that the cached file's create date is greater than the last modify date of the source file. Wrapping that and the two functions above in class helps avoid a lot of little pitfalls. But the general idea is sound. There are also some security issues with the cache file being a .php file that you would need to address.

I added this style template caching to the OSS CMS I work on. By caching the regex results, we sped up the original code by over 50%. The real benefit is the templates are PHP files. So anything that speeds the interpreting of PHP files (APC, eAccelerator, etc) speeds up your templates too.

jmucchiello
+1  A: 

I'm pretty sure this will work. :)


<?php
// $output contains the string

preg_match_all('/\[{2}([^\[]+)\]{2}/', $output, $matches);
$replaces = $matches['1'];

foreach($replaces as $replace) $str = str_replace('[['.$replace.']]', $school->get($replace), $output);
?>