SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/Drivers/Cache/Memcache.php

Copyright (C) 2017 Karmabunny Pty Ltd.

This file is a part of SproutCMS.

SproutCMS is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation, either
version 2 of the License, or (at your option) any later version.

For more information, visit <http://getsproutcms.com>.

This class was originally from Kohana 2.3.4
Copyright 2007-2008 Kohana Team
  1. <?php
  2. /**
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  *
  13.  * This class was originally from Kohana 2.3.4
  14.  * Copyright 2007-2008 Kohana Team
  15.  */
  16. namespace Sprout\Helpers\Drivers\Cache;
  17.  
  18. use Kohana;
  19. use Kohana_Exception;
  20.  
  21. use Sprout\Helpers\Drivers\CacheDriver;
  22.  
  23.  
  24. /**
  25.  * Memcache-based Cache driver.
  26.  */
  27. class Memcache implements CacheDriver
  28. {
  29.  
  30. const TAGS_KEY = 'memcache_tags_array';
  31.  
  32. // Cache backend object and flags
  33. protected $backend;
  34. protected $flags;
  35.  
  36. // Tags array
  37. protected static $tags;
  38.  
  39. // Have the tags been changed?
  40. protected static $tags_changed = FALSE;
  41.  
  42. public function __construct()
  43. {
  44. if ( ! extension_loaded('memcache'))
  45. throw new Kohana_Exception('cache.extension_not_loaded', 'memcache');
  46.  
  47. $this->backend = new Memcache;
  48. $this->flags = Kohana::config('cache_memcache.compression') ? MEMCACHE_COMPRESSED : FALSE;
  49.  
  50. $servers = Kohana::config('cache_memcache.servers');
  51.  
  52. foreach ($servers as $server)
  53. {
  54. // Make sure all required keys are set
  55. $server += array('host' => '127.0.0.1', 'port' => 11211, 'persistent' => FALSE);
  56.  
  57. // Add the server to the pool
  58. $this->backend->addServer($server['host'], $server['port'], (bool) $server['persistent'])
  59. or Kohana::log('error', 'Cache: Connection failed: '.$server['host']);
  60. }
  61.  
  62. // Load tags
  63. self::$tags = $this->backend->get(self::TAGS_KEY);
  64.  
  65. if ( ! is_array(self::$tags))
  66. {
  67. // Create a new tags array
  68. self::$tags = array();
  69.  
  70. // Tags have been created
  71. self::$tags_changed = TRUE;
  72. }
  73. }
  74.  
  75. public function __destruct()
  76. {
  77. if (self::$tags_changed === TRUE)
  78. {
  79. // Save the tags
  80. $this->backend->set(self::TAGS_KEY, self::$tags, $this->flags, 0);
  81.  
  82. // Tags are now unchanged
  83. self::$tags_changed = FALSE;
  84. }
  85. }
  86.  
  87. public function find($tag)
  88. {
  89. if (isset(self::$tags[$tag]) AND $results = $this->backend->get(self::$tags[$tag]))
  90. {
  91. // Return all the found caches
  92. return $results;
  93. }
  94. else
  95. {
  96. // No matching tags
  97. return array();
  98. }
  99. }
  100.  
  101. public function get($id)
  102. {
  103. return (($return = $this->backend->get($id)) === FALSE) ? NULL : $return;
  104. }
  105.  
  106. public function set($id, $data, array $tags = NULL, $lifetime)
  107. {
  108. if ( ! empty($tags))
  109. {
  110. // Tags will be changed
  111. self::$tags_changed = TRUE;
  112.  
  113. foreach ($tags as $tag)
  114. {
  115. // Add the id to each tag
  116. self::$tags[$tag][$id] = $id;
  117. }
  118. }
  119.  
  120. if ($lifetime !== 0)
  121. {
  122. // Memcache driver expects unix timestamp
  123. $lifetime += time();
  124. }
  125.  
  126. // Set a new value
  127. return $this->backend->set($id, $data, $this->flags, $lifetime);
  128. }
  129.  
  130. public function delete($id, $tag = FALSE)
  131. {
  132. // Tags will be changed
  133. self::$tags_changed = TRUE;
  134.  
  135. if ($id === TRUE)
  136. {
  137. if ($status = $this->backend->flush())
  138. {
  139. // Remove all tags, all items have been deleted
  140. self::$tags = array();
  141.  
  142. // We must sleep after flushing, or overwriting will not work!
  143. // @see http://php.net/manual/en/function.memcache-flush.php#81420
  144. sleep(1);
  145. }
  146.  
  147. return $status;
  148. }
  149. elseif ($tag === TRUE)
  150. {
  151. if (isset(self::$tags[$id]))
  152. {
  153. foreach (self::$tags[$id] as $_id)
  154. {
  155. // Delete each id in the tag
  156. $this->backend->delete($_id);
  157. }
  158.  
  159. // Delete the tag
  160. unset(self::$tags[$id]);
  161. }
  162.  
  163. return TRUE;
  164. }
  165. else
  166. {
  167. foreach (self::$tags as $tag => $_ids)
  168. {
  169. if (isset(self::$tags[$tag][$id]))
  170. {
  171. // Remove the id from the tags
  172. unset(self::$tags[$tag][$id]);
  173. }
  174. }
  175.  
  176. return $this->backend->delete($id);
  177. }
  178. }
  179.  
  180. public function deleteExpired()
  181. {
  182. // Tags will be changed
  183. self::$tags_changed = TRUE;
  184.  
  185. foreach (self::$tags as $tag => $_ids)
  186. {
  187. foreach ($_ids as $id)
  188. {
  189. if ( ! $this->backend->get($id))
  190. {
  191. // This id has disappeared, delete it from the tags
  192. unset(self::$tags[$tag][$id]);
  193. }
  194. }
  195.  
  196. if (empty(self::$tags[$tag]))
  197. {
  198. // The tag no longer has any valid ids
  199. unset(self::$tags[$tag]);
  200. }
  201. }
  202.  
  203. // Memcache handles garbage collection internally
  204. return TRUE;
  205. }
  206.  
  207. } // End Cache Memcache Driver
  208.