]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarCache/SugarCacheAbstract.php
Release 6.5.0
[Github/sugarcrm.git] / include / SugarCache / SugarCacheAbstract.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37
38 /**
39  * Abstract cache class
40  * @api
41  */
42 abstract class SugarCacheAbstract
43 {
44     /**
45      * @var set to false if you don't want to use the local store, true by default.
46      */
47     public $useLocalStore = true;
48
49     /**
50      * @var timeout in seconds used for cache item expiration
51      */
52     protected $_expireTimeout = 300;
53
54     /**
55      * @var prefix to use for all cache key entries
56      */
57     protected $_keyPrefix = 'sugarcrm_';
58
59     /**
60      * @var stores locally any cached items so we don't have to hit the external cache as much
61      */
62     protected $_localStore = array();
63
64     /**
65      * @var records the number of get requests made against the cache
66      */
67     protected $_cacheRequests = 0;
68
69     /**
70      * @var records the number of hits made against the cache that have been resolved without hitting the
71      * external cache
72      */
73     protected $_cacheLocalHits = 0;
74
75     /**
76      * @var records the number of hits made against the cache that are resolved using the external cache
77      */
78     protected $_cacheExternalHits = 0;
79
80     /**
81      * @var records the number of get requests that aren't in the cache
82      */
83     protected $_cacheMisses = 0;
84
85     /**
86      * @var indicates the priority level for using this cache; the lower number indicates the highest
87      * priority ( 1 would be the highest priority, but we should never ship a backend with this number
88      * so we don't bump out custom backends. ) Shipping backends use priorities in the range of 900-999.
89      */
90     protected $_priority = 899;
91
92     /**
93      * Constructor
94      */
95     public function __construct()
96     {
97         if ( isset($GLOBALS['sugar_config']['cache_expire_timeout']) )
98             $this->_expireTimeout = $GLOBALS['sugar_config']['cache_expire_timeout'];
99         if ( isset($GLOBALS['sugar_config']['unique_key']) )
100             $this->_keyPrefix = $GLOBALS['sugar_config']['unique_key'];
101     }
102
103     /**
104      * Destructor
105      */
106     public function __destruct()
107     {
108     }
109
110     /**
111      * PHP's magic __get() method, used here for getting the current value from the cache.
112      *
113      * @param  string $key
114      * @return mixed
115      */
116     public function __get($key)
117     {
118         if ( SugarCache::$isCacheReset )
119             return null;
120
121         $this->_cacheRequests++;
122         if ( !$this->useLocalStore || !isset($this->_localStore[$key]) ) {
123             $this->_localStore[$key] = $this->_getExternal($this->_keyPrefix.$key);
124             if ( isset($this->_localStore[$key]) ) {
125                 $this->_cacheExternalHits++;
126             }
127             else {
128                 $this->_cacheMisses++;
129             }
130         }
131         elseif ( isset($this->_localStore[$key]) ) {
132             $this->_cacheLocalHits++;
133         }
134
135         if ( isset($this->_localStore[$key]) ) {
136             return $this->_localStore[$key];
137         }
138
139         return null;
140     }
141
142     /**
143      * PHP's magic __set() method, used here for setting a value for a key in the cache.
144      *
145      * @param  string $key
146      * @return mixed
147      */
148     public function __set( $key, $value)
149     {
150         $this->set($key, $value);
151
152     }
153
154     /**
155      *  Set a value for a key in the cache, optionally specify a ttl. A ttl value of zero
156      * will indicate that a value should only be stored per the request.
157      *
158      * @param $key
159      * @param $value
160      * @param $ttl
161      */
162     public function set($key, $value, $ttl = null)
163     {
164         if ( is_null($value) )
165         {
166             $value = SugarCache::EXTERNAL_CACHE_NULL_VALUE;
167         }
168
169
170         if ( $this->useLocalStore )
171         {
172             $this->_localStore[$key] = $value;
173         }
174
175         if( $ttl === NULL )
176         {
177             $this->_setExternal($this->_keyPrefix.$key,$value);
178         }
179         else if( $ttl > 0 )
180         {
181             //For BC reasons the setExternal signature will remain the same.
182             $previousExpireTimeout = $this->_expireTimeout;
183             $this->_expireTimeout = $ttl;
184             $this->_setExternal($this->_keyPrefix.$key,$value);
185             $this->_expireTimeout = $previousExpireTimeout;
186         }
187     }
188     /**
189      * PHP's magic __isset() method, used here for checking for a key in the cache.
190      *
191      * @param  string $key
192      * @return mixed
193      */
194     public function __isset($key)
195     {
196         return !is_null($this->__get($key));
197     }
198
199     /**
200      * PHP's magic __unset() method, used here for clearing a key in the cache.
201      *
202      * @param  string $key
203      * @return mixed
204      */
205     public function __unset($key)
206     {
207         unset($this->_localStore[$key]);
208         $this->_clearExternal($this->_keyPrefix.$key);
209     }
210
211     /**
212      * Reset the cache for this request
213      */
214     public function reset()
215     {
216         $this->_localStore = array();
217         SugarCache::$isCacheReset = true;
218     }
219
220     /**
221      * Reset the cache fully
222      */
223     public function resetFull()
224     {
225         $this->reset();
226         $this->_resetExternal();
227     }
228
229     /**
230      * Flush the contents of the cache
231      */
232     public function flush()
233     {
234         $this->_localStore = array();
235         $this->_resetExternal();
236     }
237
238     /**
239      * Returns the number of cache hits made
240      *
241      * @return array assocative array with each key have the value
242      */
243     public function getCacheStats()
244     {
245         return array(
246             'requests'     => $this->_cacheRequests,
247             'externalHits' => $this->_cacheExternalHits,
248             'localHits'    => $this->_cacheLocalHits,
249             'misses'       => $this->_cacheMisses,
250             );
251     }
252
253     /**
254      * Returns what backend is used for caching, uses normalized class name for lookup
255      *
256      * @return string
257      */
258     public function __toString()
259     {
260         return strtolower(str_replace('SugarCache','',get_class($this)));
261     }
262
263     /**
264      * Hook for the child implementations of the individual backends to provide thier own logic for
265      * setting a value from cache
266      *
267      * @param string $key
268      * @param mixed  $value
269      */
270     abstract protected function _setExternal($key,$value);
271
272     /**
273      * Hook for the child implementations of the individual backends to provide thier own logic for
274      * getting a value from cache
275      *
276      * @param  string $key
277      * @return mixed  $value, returns null if the key is not in the cache
278      */
279     abstract protected function _getExternal($key);
280
281     /**
282      * Hook for the child implementations of the individual backends to provide thier own logic for
283      * clearing a value out of thier cache
284      *
285      * @param string $key
286      */
287     abstract protected function _clearExternal($key);
288
289     /**
290      * Hook for the child implementations of the individual backends to provide thier own logic for
291      * clearing thier cache out fully
292      */
293     abstract protected function _resetExternal();
294
295     /**
296      * Hook for testing if the backend should be used or not. Typically we'll extend this for backend specific
297      * checks as well.
298      *
299      * @return boolean true if we can use the backend, false if not
300      */
301     public function useBackend()
302     {
303         if ( !empty($GLOBALS['sugar_config']['external_cache_disabled'])
304                 && $GLOBALS['sugar_config']['external_cache_disabled'] == true ) {
305             return false;
306         }
307
308         if (defined('SUGARCRM_IS_INSTALLING')) {
309             return false;
310         }
311
312         if ( isset($GLOBALS['sugar_config']['external_cache_force_backend'])
313                 && ( $GLOBALS['sugar_config']['external_cache_force_backend'] != (string) $this ) ) {
314             return false;
315         }
316
317         return true;
318     }
319
320     /**
321      * Returns the priority level for this backend
322      *
323      * @see self::$_priority
324      *
325      * @return int
326      */
327     public function getPriority()
328     {
329         return $this->_priority;
330     }
331 }