A simpler NamespaceFile engine for CakePHP 1.2

Using Cake, once you start working with a large number of data cache files, you see the limitation of storing them all in a single directory (which is the default FileEngine behavior). In my case I have a hierarchical Tree behavior on a model and rather than traverse the tree to find its path each time (which incurs a bunch of DB queries), I simply cache the array of its “branch” to save the work. But this means I have a cache file for each node in the tree, and rapidly that gets to be a big number of files in app/tmp.

Frank de Graaf wrote an excellent drop-in upgrade of FileEngine that lets you name the cache keys as namespaces, which get stored in different directories. So you can, for example, delete a group of keys at once by deleting their directory. He doesn’t recommend it for replacing your default FileEngine cache, but for specialized instances (like mine) it works great. One change I did make to his class was to make it extend FileEngine rather than reimplement it like he does – this results in a very compact class that seems to work just as well, as far as I can tell.

To use it, I chose to activate it at runtime, just where I needed it, then switch back to the default. E.g.,

...
	function function_that_needs_this_cache_engine()
	{
		// Use NamespaceFile cache engine, only for this
		App::import('Vendor', 'NamespaceFile'); 
		Cache::config('app', array( 
			'engine' => 'NamespaceFile', 
			'duration'=> '+1 year', 
			'prefix' => 'data.' 
			)); 
 
		Cache::write('namespace.cachename', 'cache_value', "+1 year");
                echo Cache::read('namespace.cachename');
 
		// revert to the normal cache engine
		Cache::config('default', array(
			'engine' => 'File', 
			'path'	=>	ROOT . DS . APP_DIR .  DS . 'tmp'
			));
	}

The class is here; put it in app/vendors/namespace_file.php:

  1. <?php 
  2. /** 
  3.  * Partial reimplementation of Cake's original FileEngine. This 
  4.  * engine supports namespaces similar to: 
  5.  * 
  6.  * Cache::write('app.pictures.recent', $recentPictures, 'app'); 
  7.  * Cache::write('app.pictures.top', $topPictures, 'app'); 
  8.  * 
  9.  * This namespacing allows deletion of parent namespaces like: 
  10.  * 
  11.  * Cache::delete('app.pictures', 'app'); 
  12.  * 
  13.  * The settings for this cache should be 
  14.  * defined at the bottom of /config/bootstrap.php like the following: 
  15.  * 
  16.  * App::import('Vendor', 'NamespaceFile'); 
  17.  * Cache::config('app', array('engine' => 'NamespaceFile', 'duration'=> '+1 hour', 'prefix' => 'cake.'));
  18.  * 
  19.  * Place this file in APP/vendors/. 
  20.  * 
  21.  * WARNING: DO NOT USE AS YOUR APP'S DEFAULT CACHE! 
  22.  * 
  23.  * @author Frank de Graaf (Phally) 
  24.  * @link http://www.frankdegraaf.net 
  25.  * @license MIT license 
  26.  * 
  27.  * // Modified 9/4/10 by echothis - Changed to extend FileEngine, resulting in a much simpler class
  28.  */ 
  29. class NamespaceFileEngine extends FileEngine { 
  30.  
  31. 	/** 
  32. 	 * Write data for key into cache 
  33. 	 * 
  34. 	 * @param string $key Identifier for the data 
  35. 	 * @param mixed $data Data to be cached 
  36. 	 * @param mixed $duration How long to cache the data, in seconds 
  37. 	 * @return boolean True if the data was succesfully cached, false on failure 
  38. 	 * @access public 
  39. 	 */ 
  40. 	function write($key, &$data, $duration) { 
  41. 		$writable =& $this->__setKey($key); 
  42. 		if (!is_a($writable, 'File') || !$this->__init || $data === '') { 
  43. 			return false; 
  44. 		} 
  45.  
  46. 		if (!$writable->exists()) { 
  47. 			$writable->Folder->create($this->__getFolderPath($key)); 
  48. 			$writable->create(); 
  49. 		} 
  50. 		parent::write($key, &$data, $duration);
  51. 	}
  52. 	/** 
  53. 	 * Get absolute file for a given key 
  54. 	 * 
  55. 	 * @param string $key The key 
  56. 	 * @return mixed Absolute cache file for the given key or false if erroneous 
  57. 	 * @access private 
  58. 	 */ 
  59. 	function __getPath($key) { 
  60. 		return $this->settings['path'] . str_replace('.', DS, $key); 
  61. 	} 
  62.  
  63. 	/** 
  64. 	 * Get absolute folder for a given key 
  65. 	 * 
  66. 	 * @param string $key The key 
  67. 	 * @return mixed Absolute cache file for the given key or false if erroneous 
  68. 	 * @access private 
  69. 	 */     
  70. 	function __getFolderPath($key) { 
  71. 		return $this->__getPath(substr($key, 0, strrpos($key, '.') + 1)); 
  72. 	} 
  73.  
  74. 	/** 
  75. 	 * Return the class (File/Folder) for a key. 
  76. 	 * 
  77. 	 * @param string $key The key 
  78. 	 * @return mixed File or Folder class for a key. 
  79. 	 * @access private 
  80. 	 */     
  81. 	function __setKey($key) { 
  82. 		return $this->__setPath($this->__getPath($key)); 
  83. 	} 
  84.  
  85. 	/** 
  86. 	 * Return the class (File/Folder) for a path. 
  87. 	 * 
  88. 	 * @param string $path The path 
  89. 	 * @return mixed File or Folder class for a path. 
  90. 	 * @access private 
  91. 	 */         
  92. 	function __setPath($path) { 
  93. 		$this->__File->Folder->cd($path); 
  94. 		if (is_dir($path)) { 
  95. 			$object  = &$this->__File->Folder; 
  96. 			return $object; 
  97. 		} 
  98.  
  99. 		$this->__File->path = $path; 
  100. 		$object  = &$this->__File; 
  101. 		return $object; 
  102. 	} 
  103.  
  104. 	/** 
  105. 	 * Override the parents key method, so the keys don't get transformed 
  106. 	 * 
  107. 	 * @param string $key The key 
  108. 	 * @return mixed The key if one is passed else return false 
  109. 	 * @access public 
  110. 	 */ 
  111. 	function key($key = null) { 
  112. 		if (empty($key)) { 
  113. 			return false; 
  114. 		} 
  115. 		return $key; 
  116. 	} 
  117. } 
  118. ?>

Leave a comment

Your email address will not be published. Required fields are marked *