Issues

ZF-3190: Zend_Cache_Frontend_Output::start() to return data for success

Description

Currently, there is no way to replace place-holder text in an output-cached page's content. The start() method just outputs the data and returns true for cache-hit. We need a way to replace any place-holders in the content before outputting it:



Line: 55
-   public function start($id, $doNotTestCacheValidity = false)
+   public function start($id, $doNotTestCacheValidity = false, $echoData = true)

Line: 59
+   if ( $echoData )
    {
       echo ($data);
       return true;         // Since data is already output, there is no use with the returned data
    }
+   else
+      return ($data);      // Developer's responsibility to echo it later

The above changes are backwards-compatible with a 3rd argument that has a default value. Further, returning a valid data evaluates to true and so existing code will still work without any changes.

However, I'm not quite sure off the top of my head if this $echoData argument and returning $data is to be implemented in the start() method or the end() method or both the methods.

If the above is unclear, all I want to do is save data along with placeholders to cache but just before outputting data, I intend to replace the placeholders inside the data with custom content (such as: Hello Fabien!, Hello Guest!, etc)

Thanks!

Comments

Here is what I figured out as changes needed to the start() and end() methods for the placeholder logic to work:


    public function start($id, $doNotTestCacheValidity = false, $echo = true)
    {
        $data = $this->load($id, $doNotTestCacheValidity);
        //
        if ($data !== false)
        {
            if ($echo)
            echo($data);
            //
            return $data;
        }
        //
        ob_start();
        ob_implicit_flush(false);
        //
        return false;
    }

    public function end($tags = array(), $specificLifetime = false, $data = '')
    {
        $echo = 0;
        //
        if ( ! $data )
        {
            $echo = 1;
            $data = ob_get_contents();
            ob_end_clean();
        }
        //
        $this->save($data, null, $tags, $specificLifetime);
        //
        if ( $echo )
            echo($data);
    }

Hope this helps...

ok for next minor release

on your last comment, what about sending $data to the browser (in the end() method) in any cases ($data = '', $data != '') ?

Have you have a real example for this particular point ?

I just commited it into SVN trunk. Can you try it ?

Hi Fabien,

In the end() method, the developer can pass an arbitrary/pre-captured $data argument which means he/she has already captured the data and needs to do some pre-processing/placeholder-replacements with it before echoing it to the browser. In this case where the $data is not null, its the developer's responsibility to echo the output to the browser. However, the save() logic is still delegated to the end() method - saving $data to cache "before" any placeholder-replacements are made (in raw form). I have two issues using the new code you proposed in the end() method:

  1. Placeholders are not displaying when the page is generated - they are displaying only when the page is loaded from cache which means users will miss out on placeholder data when the page is generated. This is kind of a chicken-n-egg situation but fortunately, not impossible to work around.

  2. Output is displayed twice because I need to output it too before invoking end(). I can control this by sending the output to the browser only if it is not an output-cached page but point # 1 above is still an issue ;(

  3. In the start() method, we need the $data to be returned if $data !== false (this value is in raw form that was saved to cache earlier without any placeholder replacements) so that we can do post-processing/placeholder-replacements on it before sending it to the browser.

Well, how about this revised script with soft-coded arguments for a fine-grained control (while maintaining the default functionality) and more options for developers which means they can control start/end logic in whatever way they want:



    public function start($id, $doNotTestCacheValidity = false, $echo = true)
    {
        $data = $this->load($id, $doNotTestCacheValidity);
        //
        if ($data !== false)
        {
            if ($echo)
            echo($data);
            //
            return $data;            // Return the $data for post-processing
        }
        //
        ob_start();
        ob_implicit_flush(false);
        //
        return false;
    }

    public function end($tags = array(), $specificLifetime = false, $data = null, $echo = true)
    {
        if ( is_null( $data ))
        {
            $data = ob_get_contents();
            ob_end_clean();
        }
        //
        $this->save($data, null, $tags, $specificLifetime);
        //
        if ( $echo )
            echo($data);
    }

Hope this is clear... The above code works like a treat for me!

Thanks much for a quick turnaround of this task!!

An addition to point # 3 I mentioned above on start() method:

3.1) The developer would pass $echo = false, get the $data returned, do placeholder-replacements on it and echo it himself.

(PS: this is an exotic behavior taking the echo functionality out of start/end methods but the default behavior of cache-output-frontend is unchanged).

The same logic applies to end() method:

The developer passes $echo = false along with raw $data but only after echoing the post-processed $data.

I just commited a new version (svn/trunk/9527). Can you try it ?

Note: in the start() method, when $echo=true (default), I must return a boolean and not $data (to avoid an API break)

I have tested these fixes and they seem to be working as expected now. Thanks for the brilliant workaround.

Thanks,

Output.php Line 92



-            $data = $forcedDatas;
+           $data =& $forcedDatas;         // Assign by reference and avoid duplicate copy in memory

Since output could be a long string of HTML, it could hog the server's memory if duplicated even for a short duration.

Updating for the 1.6.0 release.