]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarCache/SugarCacheAbstract.php
Release 6.4.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-2011 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(
117         $key
118         )
119     {
120         if ( SugarCache::$isCacheReset )
121             return null;
122
123         $this->_cacheRequests++;
124         if ( !$this->useLocalStore || !isset($this->_localStore[$key]) ) {
125             $this->_localStore[$key] = $this->_getExternal($this->_keyPrefix.$key);
126             if ( isset($this->_localStore[$key]) ) {
127                 $this->_cacheExternalHits++;
128             }
129             else {
130                 $this->_cacheMisses++;
131             }
132         }
133         elseif ( isset($this->_localStore[$key]) ) {
134             $this->_cacheLocalHits++;
135         }
136
137         if ( isset($this->_localStore[$key]) ) {
138             return $this->_localStore[$key];
139         }
140
141         return null;
142     }
143
144     /**
145      * PHP's magic __set() method, used here for setting a value for a key in the cache.
146      *
147      * @param  string $key
148      * @return mixed
149      */
150     public function __set(
151         $key,
152         $value
153         )
154     {
155         if ( is_null($value) ) {
156             $value = SugarCache::EXTERNAL_CACHE_NULL_VALUE;
157         }
158
159         if ( $this->useLocalStore ) {
160             $this->_localStore[$key] = $value;
161         }
162         $this->_setExternal($this->_keyPrefix.$key,$value);
163     }
164
165     /**
166      * PHP's magic __isset() method, used here for checking for a key in the cache.
167      *
168      * @param  string $key
169      * @return mixed
170      */
171     public function __isset(
172         $key
173         )
174     {
175         return !is_null($this->__get($key));
176     }
177
178     /**
179      * PHP's magic __unset() method, used here for clearing a key in the cache.
180      *
181      * @param  string $key
182      * @return mixed
183      */
184     public function __unset(
185         $key
186         )
187     {
188         unset($this->_localStore[$key]);
189         $this->_clearExternal($this->_keyPrefix.$key);
190     }
191
192     /**
193      * Reset the cache for this request
194      */
195     public function reset()
196     {
197         $this->_localStore = array();
198         SugarCache::$isCacheReset = true;
199     }
200
201     /**
202      * Reset the cache fully
203      */
204     public function resetFull()
205     {
206         $this->reset();
207         $this->_resetExternal();
208     }
209
210     /**
211      * Flush the contents of the cache
212      */
213     public function flush()
214     {
215         $this->_localStore = array();
216         $this->_resetExternal();
217     }
218
219     /**
220      * Returns the number of cache hits made
221      *
222      * @return array assocative array with each key have the value
223      */
224     public function getCacheStats()
225     {
226         return array(
227             'requests'     => $this->_cacheRequests,
228             'externalHits' => $this->_cacheExternalHits,
229             'localHits'    => $this->_cacheLocalHits,
230             'misses'       => $this->_cacheMisses,
231             );
232     }
233
234     /**
235      * Returns what backend is used for caching, uses normalized class name for lookup
236      *
237      * @return string
238      */
239     public function __toString()
240     {
241         return strtolower(str_replace('SugarCache','',get_class($this)));
242     }
243
244     /**
245      * Hook for the child implementations of the individual backends to provide thier own logic for
246      * setting a value from cache
247      *
248      * @param string $key
249      * @param mixed  $value
250      */
251     abstract protected function _setExternal(
252         $key,
253         $value
254         );
255
256     /**
257      * Hook for the child implementations of the individual backends to provide thier own logic for
258      * getting a value from cache
259      *
260      * @param  string $key
261      * @return mixed  $value, returns null if the key is not in the cache
262      */
263     abstract protected function _getExternal(
264         $key
265         );
266
267     /**
268      * Hook for the child implementations of the individual backends to provide thier own logic for
269      * clearing a value out of thier cache
270      *
271      * @param string $key
272      */
273     abstract protected function _clearExternal(
274         $key
275         );
276
277     /**
278      * Hook for the child implementations of the individual backends to provide thier own logic for
279      * clearing thier cache out fully
280      */
281     abstract protected function _resetExternal();
282
283     /**
284      * Hook for testing if the backend should be used or not. Typically we'll extend this for backend specific
285      * checks as well.
286      *
287      * @return boolean true if we can use the backend, false if not
288      */
289     public function useBackend()
290     {
291         if ( !empty($GLOBALS['sugar_config']['external_cache_disabled'])
292                 && $GLOBALS['sugar_config']['external_cache_disabled'] == true ) {
293             return false;
294         }
295
296         if (defined('SUGARCRM_IS_INSTALLING')) {
297             return false;
298         }
299
300         if ( isset($GLOBALS['sugar_config']['external_cache_force_backend'])
301                 && ( $GLOBALS['sugar_config']['external_cache_force_backend'] != (string) $this ) ) {
302             return false;
303         }
304
305         return true;
306     }
307
308     /**
309      * Returns the priority level for this backend
310      *
311      * @see self::$_priority
312      *
313      * @return int
314      */
315     public function getPriority()
316     {
317         return $this->_priority;
318     }
319 }