Johannes Staehlin
Johannes Staehlin

Reputation: 3720

fetch templates from database/string

I store my templates as files, and would like to have the opportunity to store them also in a MySql db.

My template System

//function of Template class, where $file is a path to a file 
function fetch() {
    ob_start();
    if (is_array($this->vars)) extract($this->vars);
    include($file);
    $contents = ob_get_contents();
    ob_end_clean();
    return $contents;
}

function set($name, $value) {
    $this->vars[$name] = is_object($value) ? $value->fetch() : $value;
}

usage:

$tpl    = & new Template('path/to/template');
$tpl->set('titel', $titel);

Template example:

<h1><?=titel?></h1>
<p>Lorem ipsum...</p>

My approach

  1. Selecting the the template from the database as a String
  2. what i got is like $tpl = "<h1><?=$titel? >...";
  3. Now I would like to pass it to the template system, so I extended my constructor and the fetch function:

function fetch() {

if (is_array($this->vars)) extract($this->vars);
ob_start();
if(is_file($file)){
    include($file);
}else{
        //first idea: eval ($file);
    //second idea: print $file;
}
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}

'eval' gives me an Parsing exception, because it interprets the whole String as php, not just the php part. 'print' is really strange: It doesn't print the staff between , but I can see it in the source code of the page. php function are beeing ignored.

So what should I try instead?

Upvotes: 0

Views: 903

Answers (3)

smassey
smassey

Reputation: 5931

I would do pretty much the same thing as tweber except I would prefer depending on the local file timestamps rather than the DB.

Something like this: Each file has a TTL ( expiration time ) of lets say 60 seconds. The real reason is to avoid hitting the DB too hard/often needlessly, you'll quickly realize just how much faster filesystem access is compared to network and mysql especially if the mysql instance is running on a remote server.

# implement a function that gets the contents of the file ( key here is the filename )
# from DB and saves them to disk.
function fectchFreshCopy( $filename ) {
    # mysql_connect(); ...
}


if (is_array($this->vars)) extract($this->vars);
ob_start();
# first check if the file exists already
if( file_exits($file) ) {
    # now check the timestamp of the files creation to know if it has expired:
    $mod_timestamp = filemtime( $file );
    if ( ( time() - $mod_timestamp ) >= 60 ) {
        # then the file has expired, lets fetch a fresh copy from DB
        # and save it to disk..
        fetchFreshCopy();
    }
}else{
    # the file doesnt exist at all, fetch and save it!
    fetchFreshCopy();
}

include( $file );
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}

Cheers, hope thats useful

Upvotes: 1

rodneyrehm
rodneyrehm

Reputation: 13557

If you prepend '?>' to your eval, it should work.

<?php
$string = 'hello <?php echo $variable; ?>';
$variable = "world";
eval('?>' . $string);

But you should know that eval() is a rather slow thing. Its resulting op-code cannot be cached in APC (or similar). You should find a way to cache your templates on disk. For one you wouldn't have to pull them from the database every time they're needed. And you could make use of regular op-code caching (done transparently by APC).

Every time I see some half-baked home-grown "template engine", I ask myself why the author did not rely on one of the many existing template engines out there? Most of them have already solved most of the problems you could possible have. Smarty (and Twig, phpTAL, …) make it a real charme to pull template sources from wherever you like (while trying to maintain optimal performance). Do you have any special reasons for not using one of these?

Upvotes: 1

towe75
towe75

Reputation: 1470

Maybe not the best solution, but its simple and it should work:

  1. fetch your template from the db
  2. write a file with the template
  3. include this file
  4. (optional: delete the file)

If you add a Timestamp column to your template table, you can use the filesystem as a cache. Just compare the timestamps of the file and the database to decide if its sufficient to reuse the file.

Upvotes: 1

Related Questions