<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title><![CDATA[Content with Style - Comments on A caching pattern for models]]></title>
    <link>http://www.contentwithstyle.co.uk/feeds/rss/comments/251</link>
    <description><![CDATA[]]></description>
    <pubDate>Fri, 10 Sep 2010 00:17:39 -0400</pubDate>
    <generator>Zend_Feed</generator>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <item>
      <title><![CDATA[Content with Style - Comment #1 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5838</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5838</guid>
      <description><![CDATA[That's a great idea. Have to try that myself.]]></description>
      <content:encoded><![CDATA[That's a great idea. Have to try that myself.]]></content:encoded>
      <pubDate>Mon, 06 Apr 2009 16:18:21 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #2 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5845</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5845</guid>
      <description><![CDATA[<p>The main idea behind the concept is that the site this is used in is split up into lots of different, independent applications, and against my MVC preferences the main logic takes place in the controllers.</p>
<p>This meant 2 things for me:</p>
<ul><li>The solution needed to be able to take on existing models with minimum effort, and a strong convention</li>
<li>I wanted to see in the controller if I was caching or not, and have an easy way of of toggling between the two in debugging.</li></ul>

<p>If you were to build an application from scratch, and you knew exactly which data sources to cache, you might want to integrate the caching into your model, but in my case I'm iterating over the code base over and over again, refactoring and improving in small steps on a constant basis, and this is where I feel the approach was perfect.</p>]]></description>
      <content:encoded><![CDATA[<p>The main idea behind the concept is that the site this is used in is split up into lots of different, independent applications, and against my MVC preferences the main logic takes place in the controllers.</p>
<p>This meant 2 things for me:</p>
<ul><li>The solution needed to be able to take on existing models with minimum effort, and a strong convention</li>
<li>I wanted to see in the controller if I was caching or not, and have an easy way of of toggling between the two in debugging.</li></ul>

<p>If you were to build an application from scratch, and you knew exactly which data sources to cache, you might want to integrate the caching into your model, but in my case I'm iterating over the code base over and over again, refactoring and improving in small steps on a constant basis, and this is where I feel the approach was perfect.</p>]]></content:encoded>
      <pubDate>Wed, 08 Apr 2009 10:27:27 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #3 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5876</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5876</guid>
      <description><![CDATA[<p>
Hi Pascal,
<br />
<br />
here is a little optimization of your code:
</p>
<pre><code>
class BaseModelCache {
  private $object = null;
  private $cache = null;
  private $__objectMethods = null;
  
  public function __construct($object) {
    $backendName = 'File';
    $frontendName = 'Class';

    $frontendOptions = array(
      'lifetime' =&gt; 1800,
    );

    $backendOptions = array(
      'cache_dir' =&gt; '/my/cache/dir/',
    );

    $this-&gt;object = $object;
    // for initialization you can call $this-&gt;_getObjectMethods() here

    $frontendOptions['cached_entity'] = $object;

    try {
      Zend_Loader::loadClass('Zend_Cache');
      $this-&gt;cache = Zend_Cache::factory($frontendName, $backendName, $frontendOptions, $backendOptions);     
    } catch(Exception $e) {
      throw($e);
    }
  }
  
  public function __call($method, $args) {
    $class_methods = $this-&gt;_getObjectMethods();

    if(in_array($method , $class_methods)) {
        $caller = Array($this-&gt;cache, $method);
        return call_user_func_array($caller, $args);
    }

    throw new Exception( " Method " . $method . " does not exist in this class " . get_class($class ) . "." );
  }

  /**
   * returns object methods
   * @return array
   */
  protected function _getObjectMethods()
  {
    if ($this-&gt;__objectMethods === null &amp;&amp; $this-&gt;object !== null)
    {
      $class = get_class($this-&gt;object);
      $this-&gt;__objectMethods = get_class_methods($class);
    }
    return $this-&gt;__objectMethods;
  }
}
</code></pre>
<p>
So you do not have to call the same methods again and again, because the information about the existing class methods never change within the runtime. But if so (maybe you have a dynamic linking plugin object, you can return the get_class_methods() result instead of setting the internal $__objectMethods - maybe per param flag for the method.
</p>
<p>
A really nice solution, but not applicable in my projects.</p>]]></description>
      <content:encoded><![CDATA[<p>
Hi Pascal,
<br />
<br />
here is a little optimization of your code:
</p>
<pre><code>
class BaseModelCache {
  private $object = null;
  private $cache = null;
  private $__objectMethods = null;
  
  public function __construct($object) {
    $backendName = 'File';
    $frontendName = 'Class';

    $frontendOptions = array(
      'lifetime' =&gt; 1800,
    );

    $backendOptions = array(
      'cache_dir' =&gt; '/my/cache/dir/',
    );

    $this-&gt;object = $object;
    // for initialization you can call $this-&gt;_getObjectMethods() here

    $frontendOptions['cached_entity'] = $object;

    try {
      Zend_Loader::loadClass('Zend_Cache');
      $this-&gt;cache = Zend_Cache::factory($frontendName, $backendName, $frontendOptions, $backendOptions);     
    } catch(Exception $e) {
      throw($e);
    }
  }
  
  public function __call($method, $args) {
    $class_methods = $this-&gt;_getObjectMethods();

    if(in_array($method , $class_methods)) {
        $caller = Array($this-&gt;cache, $method);
        return call_user_func_array($caller, $args);
    }

    throw new Exception( " Method " . $method . " does not exist in this class " . get_class($class ) . "." );
  }

  /**
   * returns object methods
   * @return array
   */
  protected function _getObjectMethods()
  {
    if ($this-&gt;__objectMethods === null &amp;&amp; $this-&gt;object !== null)
    {
      $class = get_class($this-&gt;object);
      $this-&gt;__objectMethods = get_class_methods($class);
    }
    return $this-&gt;__objectMethods;
  }
}
</code></pre>
<p>
So you do not have to call the same methods again and again, because the information about the existing class methods never change within the runtime. But if so (maybe you have a dynamic linking plugin object, you can return the get_class_methods() result instead of setting the internal $__objectMethods - maybe per param flag for the method.
</p>
<p>
A really nice solution, but not applicable in my projects.</p>]]></content:encoded>
      <pubDate>Fri, 17 Apr 2009 07:50:37 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #4 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5878</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5878</guid>
      <description><![CDATA[A very good idea, thanks for that Robert.]]></description>
      <content:encoded><![CDATA[A very good idea, thanks for that Robert.]]></content:encoded>
      <pubDate>Fri, 17 Apr 2009 07:53:03 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #5 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5879</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5879</guid>
      <description><![CDATA[Really nice and elegant solution. 

Just an idea (haven't thought this through): if you use lazy initialization for the BaseModelCache instance instead of creating it immediately on __construct(), you could theoretically build this in standard in any project without (much) overhead in you choose not to use it.

That way this solution would always be available to deal with the kind of real world scenarios Matthias described, even when you prefer to implement a "better" way of caching inside the model for that particular project.]]></description>
      <content:encoded><![CDATA[Really nice and elegant solution. 

Just an idea (haven't thought this through): if you use lazy initialization for the BaseModelCache instance instead of creating it immediately on __construct(), you could theoretically build this in standard in any project without (much) overhead in you choose not to use it.

That way this solution would always be available to deal with the kind of real world scenarios Matthias described, even when you prefer to implement a "better" way of caching inside the model for that particular project.]]></content:encoded>
      <pubDate>Fri, 17 Apr 2009 10:05:20 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #6 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5889</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5889</guid>
      <description><![CDATA[This looks good but how do you deal with expiring cached records?

If my database row is modified, then I'd like to refresh the data.

The ZF cache components look great but in practice I've only really managed to implement simple data caching so far - and it looks like the real advantages come from function/class/page level caching.]]></description>
      <content:encoded><![CDATA[This looks good but how do you deal with expiring cached records?

If my database row is modified, then I'd like to refresh the data.

The ZF cache components look great but in practice I've only really managed to implement simple data caching so far - and it looks like the real advantages come from function/class/page level caching.]]></content:encoded>
      <pubDate>Sat, 18 Apr 2009 21:47:56 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #7 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5892</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5892</guid>
      <description><![CDATA[<p>One solution for invalidating the cache is deleting it on model updates and writes. You could just incorporate a clear function, so that from within the model you could do $this->cache->clear().
</p>

<p>
If you're looking to create a more granular caching/uncaching, that gives you control over what you delete record by record, you might want to have a look into the use of tags. Zend_Cache_Class has a function called setTagsArray(), and the clear() also takes tags as an optional parameter.</p>]]></description>
      <content:encoded><![CDATA[<p>One solution for invalidating the cache is deleting it on model updates and writes. You could just incorporate a clear function, so that from within the model you could do $this->cache->clear().
</p>

<p>
If you're looking to create a more granular caching/uncaching, that gives you control over what you delete record by record, you might want to have a look into the use of tags. Zend_Cache_Class has a function called setTagsArray(), and the clear() also takes tags as an optional parameter.</p>]]></content:encoded>
      <pubDate>Sun, 19 Apr 2009 06:54:13 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #8 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5933</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5933</guid>
      <description><![CDATA[<p>I see the following problem:</p>
<pre><code>
class Test extends BaseModel
{
    private $_hoho = NULL;

    public function __construct($hoho)
    {
        $this-&gt;_hoho = $hoho;
        parent::__construct();
    }

    public function foo($bar)
    {
        return $this-&gt;_hoho . '_' . $bar;
    }
}

$test = new Test('test1');
echo $test->cache->foo('teststring');

$test = new Test('test2');
echo $test->cache->foo('teststring');

-----

will return:
_teststring
_teststring

and not:
test1_teststring
test2_teststring
</code></pre>

<p>
I can work around, when setting cachedEntityLabel by myself, but this property of the Zend_Cache_Frontend_Class is set to private.
So how would you cache objects with different constructor params?</p>]]></description>
      <content:encoded><![CDATA[<p>I see the following problem:</p>
<pre><code>
class Test extends BaseModel
{
    private $_hoho = NULL;

    public function __construct($hoho)
    {
        $this-&gt;_hoho = $hoho;
        parent::__construct();
    }

    public function foo($bar)
    {
        return $this-&gt;_hoho . '_' . $bar;
    }
}

$test = new Test('test1');
echo $test->cache->foo('teststring');

$test = new Test('test2');
echo $test->cache->foo('teststring');

-----

will return:
_teststring
_teststring

and not:
test1_teststring
test2_teststring
</code></pre>

<p>
I can work around, when setting cachedEntityLabel by myself, but this property of the Zend_Cache_Frontend_Class is set to private.
So how would you cache objects with different constructor params?</p>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 10:13:45 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #9 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5934</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5934</guid>
      <description><![CDATA[<p>I didn't try objects with different constructor parameters, but i *assumed* that passing the object itself as cached entity would take care of this. Will need to have a think, and read the code for Zend_Cache_Frontend_Class.</p>]]></description>
      <content:encoded><![CDATA[<p>I didn't try objects with different constructor parameters, but i *assumed* that passing the object itself as cached entity would take care of this. Will need to have a think, and read the code for Zend_Cache_Frontend_Class.</p>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 10:19:06 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #10 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5935</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5935</guid>
      <description><![CDATA[<p>Hi Pascal,</p>

<p>here is my proposal, 
I got already some properties from my config object.
this will work, but i didn't wrote any unit tests, yet.
please feel free to contact me:</p>

<pre><code>abstract class BaseModel
{
    public $cache;

    public function __construct($frontendOptions = array(), $backendOptions = array())
    {
        $this-&gt;cache = new BaseModelCache($this, $frontendOptions, $backendOptions);
    }

    public function setCacheSuffix($suffix)
    {
        $this-&gt;cache-&gt;setCacheSuffix($suffix);
    }

    public function clean($mode = 'all', $tags = array())
    {
        $this-&gt;cache-&gt;clean($mode, $tags);
    }

    public function setTagsArray($tags = array())
    {
        $this-&gt;cache-&gt;setTagsArray($tags);
    }

    public function setPriority($priority)
    {
        $this-&gt;cache-&gt;setPriority($priority);
    }

    public function setLifetime($lifetime = false)
    {
        $this-&gt;cache-&gt;setLifetime($lifetime);
    }

}

class BaseModelCache
{
    protected $_object = null;
    protected $_cache = null;

    protected $_cacheByDefault = NULL;
    protected $_objectMethods = null;
    protected $_frontendOptions = array();
    protected $_backendOptions = array();
    protected $_backendName = NULL;
    protected $_defaultCacheIdPrefix = '';
    protected $_lifetime = NULL;

    /**
     * the constructor
     *
     * @param mixed $object
     */
    public function __construct ($object, $frontendOptions = array(), $backendOptios = array())
    {
        if (!Zend_Registry::isRegistered('Zend_Config'))
        {
            throw new Project_Exception('Zend_Config is not registered in Zend_Registry.');
        }

        $this-&gt;_object = $object;

        $this-&gt;_cacheByDefault = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;cache_by_default;
        $this-&gt;_defaultCacheIdPrefix = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;default_cache_id_prefix;
        $this-&gt;_lifetime = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;lifetime;
        $this-&gt;_backendName = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;backendName;

        $this-&gt;setFrontendOptions($frontendOptions)
             -&gt;setBackendOptions($backendOptios);

        try
        {
            $this-&gt;_cache = Zend_Cache::factory('Class', $this-&gt;_backendName, $this-&gt;_frontendOptions, $this-&gt;_backendOptions);
        }
        catch (Zend_Cache_Exception $e)
        {
            throw ($e);
        }
        return $this;
    }

    /**
     * the main method, calls the models from cache
     *
     * @param $method
     * @param $args
     * @return unknown
     */
    public function __call ($method, $args)
    {
        $class_methods = $this-&gt;_getObjectMethods();
        if (in_array($method, $class_methods))
        {
            $caller = array($this-&gt;_cache , $method);
            return call_user_func_array($caller, $args);
        }
        throw new Exception("Method " . $method . " does not exist in this class " . get_class($class) . ".");
    }

    /**
     * returns object methods
     * @return array
     */
    protected function _getObjectMethods ()
    {
        if ($this-&gt;_objectMethods === null &amp;&amp; $this-&gt;_object !== null)
        {
            $class = get_class($this-&gt;_object);
            $this-&gt;_objectMethods = get_class_methods($class);
        }
        return $this-&gt;_objectMethods;
    }


    /**
     * sets the FrontendOptions for the Cache Frontend
     *
     * @param array $frontendOptions
     * @return BaseModelCache
     */
    protected function setFrontendOptions($frontendOptions)
    {
        if (is_array($frontendOptions))
        {
            if (!isset($frontendOptions['cache_id_prefix']))
            {
                $frontendOptions['cache_id_prefix'] = $this-&gt;_defaultCacheIdPrefix;
            }
            if (!isset($frontendOptions['lifetime']))
            {
                $frontendOptions['lifetime'] = $this-&gt;_lifetime;
            }
            if (!isset($frontendOptions['cached_entity']))
            {
                $frontendOptions['cached_entity'] = $this-&gt;_object;
            }
            $this-&gt;_frontendOptions = $frontendOptions;
        }
        else
        {
            throw new Zend_Cache_Exception('frontendOptions must be an array.');
        }
        return $this;

    }

    /**
     * sets the BackendOptions for the Cache Backend
     *
     * @param array $backendOptions
     * @return BaseModelCache
     */
    protected function setBackendOptions($backendOptions)
    {
        if (is_array($backendOptions))
        {
            if (!in_array('cache_dir', $backendOptions) &amp;&amp; $this-&gt;_backendName = 'File')
            {
                $backendOptions['cache_dir'] = APP_PATH . Zend_Registry::get('Zend_Config')-&gt;caching-&gt;cache_dir;
            }
            $this-&gt;_backendOptions = $backendOptions;
        }
        else
        {
            throw new Zend_Cache_Exception('backendOptions must be an array.');
        }
        return $this;
    }

    public function setCacheSuffix($suffix)
    {
        if (!is_string($suffix))
        {
            throw new Exception('Cache Suffix must be a string');
        }
        $cachePrefix = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;default_cache_id_prefix;
        $this-&gt;_cache-&gt;setOption('cache_id_prefix', $cachePrefix . $suffix . '_');
    }

    public function clean($mode = 'all', $tags = array())
    {
        $this-&gt;_cache-&gt;clean($mode, $tags);
    }

    public function setTagsArray($tags = array())
    {
        $this-&gt;_cache-&gt;setTagsArray($tags);
    }

    public function setPriority($priority)
    {
        $this-&gt;_cache-&gt;setPriority($priority);
    }

    public function setLifetime($lifetime = false)
    {
        $this-&gt;_cache-&gt;setLifetime($lifetime);
    }
}

class Test extends BaseModel
{

    private $_hoho = NULL;

    public function __construct($hoho)
    {
        $this-&gt;_hoho = $hoho;
        parent::__construct();

    }

    public function foo($bar)
    {
        for ($i = 0; $i &lt; 1000000; $i++)
        {
        }
        return $this-&gt;_hoho . '_' . $bar;
    }
}

$a = new Test('hey');
$a-&gt;setCacheSuffix('hey');
echo 'non-cached: '.$a-&gt;foo('hh') . '';
echo 'cached: '.$a-&gt;cache-&gt;foo('hh') .'';

$b = new aTest('wiki');
$b-&gt;setCacheSuffix('wiki');
echo 'non-cached: '.$b-&gt;foo('hh'). '';
echo 'cached: '.$b-&gt;cache-&gt;foo('hh'). '';</code></pre>]]></description>
      <content:encoded><![CDATA[<p>Hi Pascal,</p>

<p>here is my proposal, 
I got already some properties from my config object.
this will work, but i didn't wrote any unit tests, yet.
please feel free to contact me:</p>

<pre><code>abstract class BaseModel
{
    public $cache;

    public function __construct($frontendOptions = array(), $backendOptions = array())
    {
        $this-&gt;cache = new BaseModelCache($this, $frontendOptions, $backendOptions);
    }

    public function setCacheSuffix($suffix)
    {
        $this-&gt;cache-&gt;setCacheSuffix($suffix);
    }

    public function clean($mode = 'all', $tags = array())
    {
        $this-&gt;cache-&gt;clean($mode, $tags);
    }

    public function setTagsArray($tags = array())
    {
        $this-&gt;cache-&gt;setTagsArray($tags);
    }

    public function setPriority($priority)
    {
        $this-&gt;cache-&gt;setPriority($priority);
    }

    public function setLifetime($lifetime = false)
    {
        $this-&gt;cache-&gt;setLifetime($lifetime);
    }

}

class BaseModelCache
{
    protected $_object = null;
    protected $_cache = null;

    protected $_cacheByDefault = NULL;
    protected $_objectMethods = null;
    protected $_frontendOptions = array();
    protected $_backendOptions = array();
    protected $_backendName = NULL;
    protected $_defaultCacheIdPrefix = '';
    protected $_lifetime = NULL;

    /**
     * the constructor
     *
     * @param mixed $object
     */
    public function __construct ($object, $frontendOptions = array(), $backendOptios = array())
    {
        if (!Zend_Registry::isRegistered('Zend_Config'))
        {
            throw new Project_Exception('Zend_Config is not registered in Zend_Registry.');
        }

        $this-&gt;_object = $object;

        $this-&gt;_cacheByDefault = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;cache_by_default;
        $this-&gt;_defaultCacheIdPrefix = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;default_cache_id_prefix;
        $this-&gt;_lifetime = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;lifetime;
        $this-&gt;_backendName = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;backendName;

        $this-&gt;setFrontendOptions($frontendOptions)
             -&gt;setBackendOptions($backendOptios);

        try
        {
            $this-&gt;_cache = Zend_Cache::factory('Class', $this-&gt;_backendName, $this-&gt;_frontendOptions, $this-&gt;_backendOptions);
        }
        catch (Zend_Cache_Exception $e)
        {
            throw ($e);
        }
        return $this;
    }

    /**
     * the main method, calls the models from cache
     *
     * @param $method
     * @param $args
     * @return unknown
     */
    public function __call ($method, $args)
    {
        $class_methods = $this-&gt;_getObjectMethods();
        if (in_array($method, $class_methods))
        {
            $caller = array($this-&gt;_cache , $method);
            return call_user_func_array($caller, $args);
        }
        throw new Exception("Method " . $method . " does not exist in this class " . get_class($class) . ".");
    }

    /**
     * returns object methods
     * @return array
     */
    protected function _getObjectMethods ()
    {
        if ($this-&gt;_objectMethods === null &amp;&amp; $this-&gt;_object !== null)
        {
            $class = get_class($this-&gt;_object);
            $this-&gt;_objectMethods = get_class_methods($class);
        }
        return $this-&gt;_objectMethods;
    }


    /**
     * sets the FrontendOptions for the Cache Frontend
     *
     * @param array $frontendOptions
     * @return BaseModelCache
     */
    protected function setFrontendOptions($frontendOptions)
    {
        if (is_array($frontendOptions))
        {
            if (!isset($frontendOptions['cache_id_prefix']))
            {
                $frontendOptions['cache_id_prefix'] = $this-&gt;_defaultCacheIdPrefix;
            }
            if (!isset($frontendOptions['lifetime']))
            {
                $frontendOptions['lifetime'] = $this-&gt;_lifetime;
            }
            if (!isset($frontendOptions['cached_entity']))
            {
                $frontendOptions['cached_entity'] = $this-&gt;_object;
            }
            $this-&gt;_frontendOptions = $frontendOptions;
        }
        else
        {
            throw new Zend_Cache_Exception('frontendOptions must be an array.');
        }
        return $this;

    }

    /**
     * sets the BackendOptions for the Cache Backend
     *
     * @param array $backendOptions
     * @return BaseModelCache
     */
    protected function setBackendOptions($backendOptions)
    {
        if (is_array($backendOptions))
        {
            if (!in_array('cache_dir', $backendOptions) &amp;&amp; $this-&gt;_backendName = 'File')
            {
                $backendOptions['cache_dir'] = APP_PATH . Zend_Registry::get('Zend_Config')-&gt;caching-&gt;cache_dir;
            }
            $this-&gt;_backendOptions = $backendOptions;
        }
        else
        {
            throw new Zend_Cache_Exception('backendOptions must be an array.');
        }
        return $this;
    }

    public function setCacheSuffix($suffix)
    {
        if (!is_string($suffix))
        {
            throw new Exception('Cache Suffix must be a string');
        }
        $cachePrefix = Zend_Registry::get('Zend_Config')-&gt;caching-&gt;default_cache_id_prefix;
        $this-&gt;_cache-&gt;setOption('cache_id_prefix', $cachePrefix . $suffix . '_');
    }

    public function clean($mode = 'all', $tags = array())
    {
        $this-&gt;_cache-&gt;clean($mode, $tags);
    }

    public function setTagsArray($tags = array())
    {
        $this-&gt;_cache-&gt;setTagsArray($tags);
    }

    public function setPriority($priority)
    {
        $this-&gt;_cache-&gt;setPriority($priority);
    }

    public function setLifetime($lifetime = false)
    {
        $this-&gt;_cache-&gt;setLifetime($lifetime);
    }
}

class Test extends BaseModel
{

    private $_hoho = NULL;

    public function __construct($hoho)
    {
        $this-&gt;_hoho = $hoho;
        parent::__construct();

    }

    public function foo($bar)
    {
        for ($i = 0; $i &lt; 1000000; $i++)
        {
        }
        return $this-&gt;_hoho . '_' . $bar;
    }
}

$a = new Test('hey');
$a-&gt;setCacheSuffix('hey');
echo 'non-cached: '.$a-&gt;foo('hh') . '';
echo 'cached: '.$a-&gt;cache-&gt;foo('hh') .'';

$b = new aTest('wiki');
$b-&gt;setCacheSuffix('wiki');
echo 'non-cached: '.$b-&gt;foo('hh'). '';
echo 'cached: '.$b-&gt;cache-&gt;foo('hh'). '';</code></pre>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 11:25:23 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #11 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5936</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5936</guid>
      <description><![CDATA[<p>Great. I wonder whether the cache suffix could be dynamically created from the passed params. I'll have a look into it.</p>]]></description>
      <content:encoded><![CDATA[<p>Great. I wonder whether the cache suffix could be dynamically created from the passed params. I'll have a look into it.</p>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 11:30:54 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #12 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5938</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5938</guid>
      <description><![CDATA[<p>Hi Pascal,</p>
<p>
you can create the suffix dynamically, but i would prefer not to do so. The Problem is that sometimes you give an object to the constructor and then you have to serialize the whole object to create a cache suffix, and that is too much, i guess. It seems to be better, when you create the suffix manually.</p>

<p>By the way, I made a mistake in the code above. the BaseModel.php won't need the setCacheSuffix, clean, setTagsArray, setPriority &amp; setLifetime methods, because the cache property is public, so you can call it like this:</p>

<pre><code>$a = new Test('foo');
$a-&gt;cache-&gt;setCacheSuffix('foo');
$a-&gt;cache-&gt;foo('teststring');</code></pre>]]></description>
      <content:encoded><![CDATA[<p>Hi Pascal,</p>
<p>
you can create the suffix dynamically, but i would prefer not to do so. The Problem is that sometimes you give an object to the constructor and then you have to serialize the whole object to create a cache suffix, and that is too much, i guess. It seems to be better, when you create the suffix manually.</p>

<p>By the way, I made a mistake in the code above. the BaseModel.php won't need the setCacheSuffix, clean, setTagsArray, setPriority &amp; setLifetime methods, because the cache property is public, so you can call it like this:</p>

<pre><code>$a = new Test('foo');
$a-&gt;cache-&gt;setCacheSuffix('foo');
$a-&gt;cache-&gt;foo('teststring');</code></pre>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 12:24:06 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #13 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5939</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5939</guid>
      <description><![CDATA[<p>
What about serialize, then md5 it?
</p>]]></description>
      <content:encoded><![CDATA[<p>
What about serialize, then md5 it?
</p>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 12:25:28 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #14 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5940</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-5940</guid>
      <description><![CDATA[<p>Hi Pascal,</p>
<p>
this will work, but serializing big and heavy objects like Zend_Date f.e. will take a lot of time.</p>

<p>But, if you like, you can use this:</p>

<pre><code>class aTest extends BaseModel
{
   public function __construct($hoho)
   {
       $this-&gt;_hoho = $hoho;
       $args = func_get_args();
       parent::__construct(array(), array(), $args);
   }
}

abstract class BaseModel
{
    public $cache;

    public function __construct($frontendOptions = array(), $backendOptions = array(), $childParams = array())
    {
        $this-&gt;cache = new BaseModelCache($this, $frontendOptions, $backendOptions);
        $this-&gt;cache-&gt;setCacheSuffix(md5(serialize($childParams)));
    }

}</code></pre>]]></description>
      <content:encoded><![CDATA[<p>Hi Pascal,</p>
<p>
this will work, but serializing big and heavy objects like Zend_Date f.e. will take a lot of time.</p>

<p>But, if you like, you can use this:</p>

<pre><code>class aTest extends BaseModel
{
   public function __construct($hoho)
   {
       $this-&gt;_hoho = $hoho;
       $args = func_get_args();
       parent::__construct(array(), array(), $args);
   }
}

abstract class BaseModel
{
    public $cache;

    public function __construct($frontendOptions = array(), $backendOptions = array(), $childParams = array())
    {
        $this-&gt;cache = new BaseModelCache($this, $frontendOptions, $backendOptions);
        $this-&gt;cache-&gt;setCacheSuffix(md5(serialize($childParams)));
    }

}</code></pre>]]></content:encoded>
      <pubDate>Thu, 23 Apr 2009 12:35:30 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #15 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6047</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6047</guid>
      <description><![CDATA[<p>I think the 'extends' solution isn't very flexible. In the real world the model objects usually extend a base model object, which requires the BaseModelCache to be embedded in it or something similar.</p>
<p>
Adding public function 'cache' to an existing model wolud be much simpler than extending.
</p>
<pre><code>
class MyModel extend aBaseModelObject
{
  public function doSomething()
  {
    return 'resultFromComplexDatabaseQuery';
  }
	
  public function cache()
  {
    return new BaseModelCache($this);
  }
}</code></pre>]]></description>
      <content:encoded><![CDATA[<p>I think the 'extends' solution isn't very flexible. In the real world the model objects usually extend a base model object, which requires the BaseModelCache to be embedded in it or something similar.</p>
<p>
Adding public function 'cache' to an existing model wolud be much simpler than extending.
</p>
<pre><code>
class MyModel extend aBaseModelObject
{
  public function doSomething()
  {
    return 'resultFromComplexDatabaseQuery';
  }
	
  public function cache()
  {
    return new BaseModelCache($this);
  }
}</code></pre>]]></content:encoded>
      <pubDate>Tue, 12 May 2009 09:32:03 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #16 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6084</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6084</guid>
      <description><![CDATA[<p>Hi,</p>

<p>Just played around with this the last couple hours.</p>

<p>Its nice but not perfekt.
eg. you cant use findParentRow or getDependentRowset when the Zend_Db_Table_Row is cached.</p>

<p>You can get around this by using a own Zend_Db_Table_Row class which overrides setTable. (you can not just set "setTable" couse you loose the _tableClass property, and this is checked in setTable.</p>

<p>If you got around this you fall into your next problem. The ID which is generated by "Zend_Cache_Frontend_Class::_makeId" dont take the contents of the object in account. so if you loop through a rowset and use findDependentRowset in this loop, it will always return the same contents, because the ID generated for it is always the same.</p>

<p>
For replication here are the classes I used:</p>

<pre><code>
class Cwd_Db_Cache {
 // see comment by Robert Kummer 
 // http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models#comment-5876
}
</code></pre>
]]></description>
      <content:encoded><![CDATA[<p>Hi,</p>

<p>Just played around with this the last couple hours.</p>

<p>Its nice but not perfekt.
eg. you cant use findParentRow or getDependentRowset when the Zend_Db_Table_Row is cached.</p>

<p>You can get around this by using a own Zend_Db_Table_Row class which overrides setTable. (you can not just set "setTable" couse you loose the _tableClass property, and this is checked in setTable.</p>

<p>If you got around this you fall into your next problem. The ID which is generated by "Zend_Cache_Frontend_Class::_makeId" dont take the contents of the object in account. so if you loop through a rowset and use findDependentRowset in this loop, it will always return the same contents, because the ID generated for it is always the same.</p>

<p>
For replication here are the classes I used:</p>

<pre><code>
class Cwd_Db_Cache {
 // see comment by Robert Kummer 
 // http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models#comment-5876
}
</code></pre>
]]></content:encoded>
      <pubDate>Sun, 17 May 2009 08:25:03 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #17 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6085</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6085</guid>
      <description><![CDATA[<p>Hi again,</p>
<p>
forgot to add the (quick &amp; dirty) test case:
The setTable call is neccessary if the row object cames from cache. (trying to figure out a way to do this automaticly)</p>

<pre><code>
$m_event = new EventModel();
$events = $m_event-&gt;cache-&gt;fetchAll(array("status='1'","deleted='0'"),'createdate desc',10,0);
echo "&lt;ul&gt;";
foreach($events as $event){
	echo "&lt;li&gt;".$event-&gt;event_id."&lt;/li&gt;";	    			
	$event-&gt;setTable($m_event);    			
	$acts = $event-&gt;cache-&gt;findDependentRowset('ActModel');
	echo "&lt;ul&gt;";
	foreach($acts as $act){
		echo "&lt;li&gt;".$act-&gt;act_id."&lt;/li&gt;";
	}	    		
	echo "&lt;/ul&gt;";	    		
}
echo "&lt;/ul&gt;";     
</code></pre>]]></description>
      <content:encoded><![CDATA[<p>Hi again,</p>
<p>
forgot to add the (quick &amp; dirty) test case:
The setTable call is neccessary if the row object cames from cache. (trying to figure out a way to do this automaticly)</p>

<pre><code>
$m_event = new EventModel();
$events = $m_event-&gt;cache-&gt;fetchAll(array("status='1'","deleted='0'"),'createdate desc',10,0);
echo "&lt;ul&gt;";
foreach($events as $event){
	echo "&lt;li&gt;".$event-&gt;event_id."&lt;/li&gt;";	    			
	$event-&gt;setTable($m_event);    			
	$acts = $event-&gt;cache-&gt;findDependentRowset('ActModel');
	echo "&lt;ul&gt;";
	foreach($acts as $act){
		echo "&lt;li&gt;".$act-&gt;act_id."&lt;/li&gt;";
	}	    		
	echo "&lt;/ul&gt;";	    		
}
echo "&lt;/ul&gt;";     
</code></pre>]]></content:encoded>
      <pubDate>Sun, 17 May 2009 08:21:41 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #18 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6088</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6088</guid>
      <description><![CDATA[<p>Hi Ludwig. When we developed this our models where based on web services. Also, I never really used Zend_Db_Table_Row, but instead create an instance of Zend_DB in my model and use it from within the methods. Always disliked the active record approach to be honest.</p>

<p>Is the ID problem similar to what Sascha-Oliver described? Maybe when I have spare time, I will have a ponder and see what I can come up with ...</p>]]></description>
      <content:encoded><![CDATA[<p>Hi Ludwig. When we developed this our models where based on web services. Also, I never really used Zend_Db_Table_Row, but instead create an instance of Zend_DB in my model and use it from within the methods. Always disliked the active record approach to be honest.</p>

<p>Is the ID problem similar to what Sascha-Oliver described? Maybe when I have spare time, I will have a ponder and see what I can come up with ...</p>]]></content:encoded>
      <pubDate>Sun, 17 May 2009 10:15:11 -0400</pubDate>
    </item>
    <item>
      <title><![CDATA[Content with Style - Comment #19 on A caching pattern for models]]></title>
      <link>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6089</link>
      <guid>http://www.contentwithstyle.co.uk/content/a-caching-pattern-for-models/#comment-6089</guid>
      <description><![CDATA[<p>Hi,</p>
<p>
With the version of Sascha-Oliver i was able to get around this. but its not a very beautiful solution.</p>
<p>
The nice thing about it, it doesnt matter whats in the cache and what is fetched from the db. all combinations are working.</p>

<pre><code>
$m_event = new EventModel();
$m_act = new ActModel();
$events = $m_event-&gt;cache-&gt;fetchAll(array("status='1'","deleted='0'"),'createdate desc',10,0);
echo "&lt;ul&gt;";
foreach($events as $event){
	echo "&lt;li&gt;".$event-&gt;event_id."&lt;/li&gt;";	    			
	$event-&gt;setTable($m_event);
	$event-&gt;cache-&gt;setCacheSuffix('eventid_'.$event-&gt;event_id);
	
	$acts = $event-&gt;cache-&gt;findDependentRowset('ActModel');
	echo "&lt;ul&gt;";
	foreach($acts as $act){	    			
		$act-&gt;setTable($m_act);
		$act-&gt;cache-&gt;setCacheSuffix('actid_'.$act-&gt;act_id);
		$foo = $act-&gt;cache-&gt;findParentRow('EventModel');
		echo "&lt;li&gt;".$act-&gt;act_id." (".$foo-&gt;event_id.")&lt;/li&gt;";
	}	    		
	echo "&lt;/ul&gt;"; 	    		
}
echo "&lt;/ul&gt;";
</code></pre>

<p>You can find the classes at http://svn.cwd.at/cwd/trunk/Cwd/</p>

]]></description>
      <content:encoded><![CDATA[<p>Hi,</p>
<p>
With the version of Sascha-Oliver i was able to get around this. but its not a very beautiful solution.</p>
<p>
The nice thing about it, it doesnt matter whats in the cache and what is fetched from the db. all combinations are working.</p>

<pre><code>
$m_event = new EventModel();
$m_act = new ActModel();
$events = $m_event-&gt;cache-&gt;fetchAll(array("status='1'","deleted='0'"),'createdate desc',10,0);
echo "&lt;ul&gt;";
foreach($events as $event){
	echo "&lt;li&gt;".$event-&gt;event_id."&lt;/li&gt;";	    			
	$event-&gt;setTable($m_event);
	$event-&gt;cache-&gt;setCacheSuffix('eventid_'.$event-&gt;event_id);
	
	$acts = $event-&gt;cache-&gt;findDependentRowset('ActModel');
	echo "&lt;ul&gt;";
	foreach($acts as $act){	    			
		$act-&gt;setTable($m_act);
		$act-&gt;cache-&gt;setCacheSuffix('actid_'.$act-&gt;act_id);
		$foo = $act-&gt;cache-&gt;findParentRow('EventModel');
		echo "&lt;li&gt;".$act-&gt;act_id." (".$foo-&gt;event_id.")&lt;/li&gt;";
	}	    		
	echo "&lt;/ul&gt;"; 	    		
}
echo "&lt;/ul&gt;";
</code></pre>

<p>You can find the classes at http://svn.cwd.at/cwd/trunk/Cwd/</p>

]]></content:encoded>
      <pubDate>Sun, 17 May 2009 09:45:54 -0400</pubDate>
    </item>
  </channel>
</rss>
