interface PHPTAL_Trigger

The phptal:id attribute was added into the PHPTAL for the PHP5 version to replace the old PHPTAL_Cache interface and to abstract it a little more.

When a phptal:id is reached, PHPTAL will look in its triggers list for a matching id and will invoke the trigger start() and end() methods before entering the element, and just after it.

If the PHPTAL_Trigger::start() method returns PHPTAL_Trigger::SKIPTAG, PHPTAL will ignore the element and its content (start() may echo something to replace it).

If your trigger wants the element and its content to be executed, you'll have to return PHPTAL_Trigger::PROCEED.

The PHPTAL_Trigger::end() will be called after the element (whether it has been executed or not). This allows you to build cache systems using ob_start() in start() and ob_get_contents(), ob_end_clean() in end().

<html><div>
    …
    foo bar baz <span tal:replace="id"/> foo bar baz
    …
  </div></html>

For some reason we decide the <div> block requires to be cached. We introduce a phptal:id into the template:

<html><div phptal:id="somePossiblyUniqueKeyword">
    …
    foo bar baz <span tal:replace="id"/> foo bar baz
    …
  </div></html>

Then we write our trigger which will cache the <div> content:

<?php
require_once 'PHPTAL.php';
require_once 'PHPTAL/Trigger.php';

class CacheTrigger implements PHPTAL_Trigger
{
    public function start($phptalid, $tpl)
    {
        // this cache depends on 'id' which must appears in
        // the template execution context
        $this->_cachePath = 'cache.' . $tpl->getContext()->id;

        // if already cached, read the cache and tell PHPTAL to
        // ignore the tag content
        if (file_exists($this->_cachePath)){
            $this->_usedCache = true;
            readfile($this->_cachePath);
            return self::SKIPTAG;
        }

        // no cache found, we start an output buffer and tell
        // PHPTAL to proceed (ie: execute the tag content)
        $this->_usedCache = false;
        ob_start();
        return self::PROCEED;
    }

    // Invoked after tag execution
    public function end($phptalid, $tpl)
    {
        // end of tag, if cached file used, do nothing
        if ($this->_usedCache){
            return;
        }

        // otherwise, get the content of the output buffer
        // and write it into the cache file for later usage
        $content = ob_get_contents();
        ob_end_clean();
        echo $content;

        $f = fopen($this->_cachePath, 'w');
        fwrite($f, $content);
        fclose($f);
    }

    private $_cachePath;
    private $_usedCache;
}
?>

The key here is to return from start() with either SKIPTAG or PROCEED.

When SKIPTAG is returned, PHPTAL will just ignore the tag and call end(). This usually means that the trigger takes the hand in deciding what to show there.

When PROCEED is returned, PHPTAL will execute the tag and its content as usual, then call end(). This allows our cache class to play with output buffers to execute the tag once and to store the result in a file which will be used in later calls.

To install our trigger we use:

<?php
require_once 'PHPTAL.php';
require_once 'CacheTrigger.php'; // our custom trigger

$trigger = new CacheTrigger();

$tpl = new PHPTAL('test.xhtml');

// this trigger will only be called for phptal:id="triggerId"
$tpl->addTrigger('somePossiblyUniqueKeyword', $trigger);

$tpl->id = 1;

echo $tpl->execute();

?>

You can add as many triggers as you like to your templates. A generic cache trigger may also handle more than one phptal:id… etc…