Find attached a patch file for this.

Thanks,
Tony

On 6/7/2007 1:07 PM, Tony Ford wrote:
Zend_Cache seemed very elegant to me at first, until I tried to make a customization.

I have some apps that will be using memcached for objects. Thing is, some of my server farms will have multiple sites and networks, all using the same pool of memcached servers. Of course all the networks will cache similar named objects, like 'acl' for instance. So, to avoid namespace trampling, or rather to "create" namespaces, I thought it'd be very useful to have cache id prefixes. Now, instead of setting keys in memecached just called 'obj_name' they'd be 'uniquenetwork_obj_name'. This allows me to have an acl object for Network1 (network1_acl) and an acl object for network2 (network2_acl).

I could just go ahead and setup a constant and pass it in along with the ids into every load(), save(), remove(), etc calls, but that seems like a lot of unnecessary crap. Instead, it makes a lot more sense to me to create a new backend option for my "cache id prefix", then have each one of those methods concat the prefix on to the front of ids automatically just before the real memcache calls are made.

So, I went about this, and its a real mess. First of all, all options are hardcoded into the classes and get explicitly checked at object instantiation. OK, well, I extended Zend_Cache_Backend_Memcached and did this:

   public function __construct($options = array())
   {
       // add cache id prefix as an allowed option, default nothing
       $this->_options['cache_id_prefix'] = null;
       // Call parent constructor
       parent::__construct($options);
   }

Then each one of those methods now look basically like this:

   public function load($id, $doNotTestCacheValidity = false)
   {
       $id = $this->_options['cache_id_prefix'] . $id;
       parent::load($id, $doNotTestCacheValidity);
   }

Overall, I didn't think that was too big of a deal, but then I realized that the backends are hardcoded and checked in Zend_Cache, just like the options, so I'd have to do the same thing for that. What's worse though, is only the name of the backend is passed in, and then class names are created and called with a hardcoded 'Zend_Cache_Backend' . $backend. Now I can't even call my class something different. Now I'd have to create my class file specifically in the /Zend/Cache/Backend directory, and call it something like CustomMemcached.

Anyway, overall Zend_Cache is a very nice component with lots of options, and I appreciate all of them, its just that its very closed. Maybe that was the intention, and if so, maybe you would accept a patch file from me to officially add this feature to the memcache backend.

Thanks in advance for reading,
Tony
Index: Memcached.php
===================================================================
--- Memcached.php       (revision 264)
+++ Memcached.php       (working copy)
@@ -64,6 +64,9 @@
      * =====> (boolean) compression :
      * true if you want to use on-the-fly compression
      * 
+     * =====> (string) cache_id_prefix :
+     * prefix for cache ids
+     * 
      * @var array available options
      */
     protected $_options = array(
@@ -72,7 +75,8 @@
             'port' => Zend_Cache_Backend_Memcached::DEFAULT_PORT,
             'persistent' => Zend_Cache_Backend_Memcached::DEFAULT_PERSISTENT
         )),
-        'compression' => false
+        'compression' => false,
+        'cache_id_prefix' => null
     );
      
     /**
@@ -98,6 +102,11 @@
             Zend_Cache::throwException('The memcache extension must be loaded 
for using this backend !');
         }
         parent::__construct($options);
+        if (isset($this->_options['cache_id_prefix'])) { // particular case 
for this option
+            if (!preg_match('~^[\w]+$~', $this->_options['cache_id_prefix'])) {
+                Zend_Cache::throwException('Invalid cache_id_prefix : must use 
only [a-zA-A0-9_]');
+            }
+        }
         if (isset($this->_options['servers'])) {
             $value= $this->_options['servers'];
             if (isset($value['host'])) {
@@ -131,7 +140,7 @@
         if ($doNotTestCacheValidity) {
             $this->_log("Zend_Cache_Backend_Memcached::load() : 
\$doNotTestCacheValidity=true is unsupported by the Memcached backend");
         }
-        $tmp = $this->_memcache->get($id);
+        $tmp = $this->_memcache->get($this->_id($id));
         if (is_array($tmp)) {
             return $tmp[0];
         }
@@ -146,7 +155,7 @@
      */
     public function test($id)
     {
-        $tmp = $this->_memcache->get($id);
+        $tmp = $this->_memcache->get($this->_id($id));
         if (is_array($tmp)) {
             return $tmp[1];
         }
@@ -173,7 +182,7 @@
         } else {
             $flag = 0;
         }
-        $result = $this->_memcache->set($id, array($data, time()), $flag, 
$lifetime);
+        $result = $this->_memcache->set($this->_id($id), array($data, time()), 
$flag, $lifetime);
         if (count($tags) > 0) {
             $this->_log("Zend_Cache_Backend_Memcached::save() : tags are 
unsupported by the Memcached backend");
         }
@@ -188,7 +197,7 @@
      */
     public function remove($id) 
     {
-        return $this->_memcache->delete($id);
+        return $this->_memcache->delete($this->_id($id));
     }
     
     /**
@@ -221,5 +230,21 @@
             $this->_log("Zend_Cache_Backend_Memcached::clean() : tags are 
unsupported by the Memcached backend");
         }
     }
+
+    /**
+     * Make and return a cache id
+     *
+     * Checks 'cache_id_prefix' and returns new id with prefix or simply the 
id if null
+     *
+     * @param string $id cache id
+     * @return string cache id (with or without prefix)
+     */  
+    private function _id($id)
+    {
+        if (isset($this->_options['cache_id_prefix'])) {
+            return $this->_options['cache_id_prefix'] . $id; // return with 
prefix
+        }
+        return $id; // no prefix, just return the $id passed
+    }
         
 }

Reply via email to