Regen CRM/Core/DAO/AllCoreTables.data.php
[civicrm-core.git] / CRM / Core / BAO / Cache.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
fa938177 6 | Copyright CiviCRM LLC (c) 2004-2016 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035 27
6a488035 28/**
192d36c5 29 * BAO object for civicrm_cache table.
30 *
31 * This is a database cache and is persisted across sessions. Typically we use
6a488035
TO
32 * this to store meta data (like profile fields, custom fields etc).
33 *
34 * The group_name column is used for grouping together all cache elements that logically belong to the same set.
35 * Thus all session cache entries are grouped under 'CiviCRM Session'. This allows us to delete all entries of
36 * a specific group if needed.
37 *
38 * The path column allows us to differentiate between items in that group. Thus for the session cache, the path is
39 * the unique form name for each form (per user)
40 */
41class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
42
e79e9c87
TO
43 /**
44 * @var array ($cacheKey => $cacheValue)
45 */
46 static $_cache = NULL;
47
6a488035 48 /**
fe482240 49 * Retrieve an item from the DB cache.
6a488035 50 *
6a0b768e
TO
51 * @param string $group
52 * (required) The group name of the item.
53 * @param string $path
54 * (required) The path under which this item is stored.
55 * @param int $componentID
56 * The optional component ID (so componenets can share the same name space).
6a488035 57 *
a6c01b45
CW
58 * @return object
59 * The data if present in cache, else null
6a488035 60 */
00be9182 61 public static function &getItem($group, $path, $componentID = NULL) {
e79e9c87
TO
62 if (self::$_cache === NULL) {
63 self::$_cache = array();
def0681b 64 }
6a488035 65
def0681b 66 $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
e79e9c87 67 if (!array_key_exists($argString, self::$_cache)) {
def0681b 68 $cache = CRM_Utils_Cache::singleton();
e79e9c87
TO
69 self::$_cache[$argString] = $cache->get($argString);
70 if (!self::$_cache[$argString]) {
def0681b 71 $dao = new CRM_Core_DAO_Cache();
6a488035 72
f9f40af3
TO
73 $dao->group_name = $group;
74 $dao->path = $path;
def0681b
KJ
75 $dao->component_id = $componentID;
76
77 $data = NULL;
78 if ($dao->find(TRUE)) {
79 $data = unserialize($dao->data);
80 }
81 $dao->free();
e79e9c87
TO
82 self::$_cache[$argString] = $data;
83 $cache->set($argString, self::$_cache[$argString]);
def0681b 84 }
6a488035 85 }
e79e9c87 86 return self::$_cache[$argString];
6a488035
TO
87 }
88
89 /**
fe482240 90 * Retrieve all items in a group.
6a488035 91 *
6a0b768e
TO
92 * @param string $group
93 * (required) The group name of the item.
94 * @param int $componentID
95 * The optional component ID (so componenets can share the same name space).
6a488035 96 *
a6c01b45
CW
97 * @return object
98 * The data if present in cache, else null
6a488035 99 */
00be9182 100 public static function &getItems($group, $componentID = NULL) {
e79e9c87
TO
101 if (self::$_cache === NULL) {
102 self::$_cache = array();
def0681b 103 }
6a488035 104
def0681b 105 $argString = "CRM_CT_CI_{$group}_{$componentID}";
e79e9c87 106 if (!array_key_exists($argString, self::$_cache)) {
def0681b 107 $cache = CRM_Utils_Cache::singleton();
e79e9c87
TO
108 self::$_cache[$argString] = $cache->get($argString);
109 if (!self::$_cache[$argString]) {
def0681b
KJ
110 $dao = new CRM_Core_DAO_Cache();
111
f9f40af3 112 $dao->group_name = $group;
def0681b
KJ
113 $dao->component_id = $componentID;
114 $dao->find();
6a488035 115
1a4e6781 116 $result = array();
def0681b
KJ
117 while ($dao->fetch()) {
118 $result[$dao->path] = unserialize($dao->data);
119 }
120 $dao->free();
121
e79e9c87
TO
122 self::$_cache[$argString] = $result;
123 $cache->set($argString, self::$_cache[$argString]);
def0681b 124 }
6a488035 125 }
def0681b 126
e79e9c87 127 return self::$_cache[$argString];
6a488035
TO
128 }
129
130 /**
fe482240 131 * Store an item in the DB cache.
6a488035 132 *
6a0b768e
TO
133 * @param object $data
134 * (required) A reference to the data that will be serialized and stored.
135 * @param string $group
136 * (required) The group name of the item.
137 * @param string $path
138 * (required) The path under which this item is stored.
139 * @param int $componentID
140 * The optional component ID (so componenets can share the same name space).
6a488035 141 */
00be9182 142 public static function setItem(&$data, $group, $path, $componentID = NULL) {
e79e9c87
TO
143 if (self::$_cache === NULL) {
144 self::$_cache = array();
def0681b
KJ
145 }
146
6a488035
TO
147 $dao = new CRM_Core_DAO_Cache();
148
f9f40af3
TO
149 $dao->group_name = $group;
150 $dao->path = $path;
6a488035
TO
151 $dao->component_id = $componentID;
152
153 // get a lock so that multiple ajax requests on the same page
154 // dont trample on each other
155 // CRM-11234
83617886 156 $lock = Civi::lockManager()->acquire("cache.{$group}_{$path}._{$componentID}");
6a488035
TO
157 if (!$lock->isAcquired()) {
158 CRM_Core_Error::fatal();
159 }
160
161 $dao->find(TRUE);
162 $dao->data = serialize($data);
163 $dao->created_date = date('YmdHis');
9f35e05d 164 $dao->save(FALSE);
6a488035
TO
165
166 $lock->release();
167
168 $dao->free();
def0681b 169
80259ba2
TO
170 // cache coherency - refresh or remove dependent caches
171
def0681b
KJ
172 $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
173 $cache = CRM_Utils_Cache::singleton();
174 $data = unserialize($dao->data);
e79e9c87 175 self::$_cache[$argString] = $data;
def0681b 176 $cache->set($argString, $data);
80259ba2
TO
177
178 $argString = "CRM_CT_CI_{$group}_{$componentID}";
e79e9c87 179 unset(self::$_cache[$argString]);
80259ba2 180 $cache->delete($argString);
6a488035
TO
181 }
182
183 /**
1a4e6781 184 * Delete all the cache elements that belong to a group OR delete the entire cache if group is not specified.
6a488035 185 *
6a0b768e
TO
186 * @param string $group
187 * The group name of the entries to be deleted.
188 * @param string $path
189 * Path of the item that needs to be deleted.
1a4e6781 190 * @param bool $clearAll clear all caches
6a488035 191 */
00be9182 192 public static function deleteGroup($group = NULL, $path = NULL, $clearAll = TRUE) {
6a488035
TO
193 $dao = new CRM_Core_DAO_Cache();
194
195 if (!empty($group)) {
196 $dao->group_name = $group;
197 }
198
199 if (!empty($path)) {
200 $dao->path = $path;
201 }
202
203 $dao->delete();
204
205 if ($clearAll) {
206 // also reset ACL Cache
207 CRM_ACL_BAO_Cache::resetCache();
208
209 // also reset memory cache if any
210 CRM_Utils_System::flushCache();
211 }
212 }
213
214 /**
215 * The next two functions are internal functions used to store and retrieve session from
216 * the database cache. This keeps the session to a limited size and allows us to
217 * create separate session scopes for each form in a tab
6a488035
TO
218 */
219
220 /**
221 * This function takes entries from the session array and stores it in the cache.
1a4e6781 222 *
6a488035
TO
223 * It also deletes the entries from the $_SESSION object (for a smaller session size)
224 *
6a0b768e
TO
225 * @param array $names
226 * Array of session values that should be persisted.
6a488035
TO
227 * This is either a form name + qfKey or just a form name
228 * (in the case of profile)
6a0b768e
TO
229 * @param bool $resetSession
230 * Should session state be reset on completion of DB store?.
6a488035 231 */
00be9182 232 public static function storeSessionToCache($names, $resetSession = TRUE) {
6a488035
TO
233 foreach ($names as $key => $sessionName) {
234 if (is_array($sessionName)) {
2aa397bc 235 $value = NULL;
6a488035
TO
236 if (!empty($_SESSION[$sessionName[0]][$sessionName[1]])) {
237 $value = $_SESSION[$sessionName[0]][$sessionName[1]];
238 }
239 self::setItem($value, 'CiviCRM Session', "{$sessionName[0]}_{$sessionName[1]}");
2aa397bc
TO
240 if ($resetSession) {
241 $_SESSION[$sessionName[0]][$sessionName[1]] = NULL;
242 unset($_SESSION[$sessionName[0]][$sessionName[1]]);
6a488035 243 }
2aa397bc 244 }
6a488035 245 else {
2aa397bc 246 $value = NULL;
6a488035
TO
247 if (!empty($_SESSION[$sessionName])) {
248 $value = $_SESSION[$sessionName];
249 }
250 self::setItem($value, 'CiviCRM Session', $sessionName);
2aa397bc
TO
251 if ($resetSession) {
252 $_SESSION[$sessionName] = NULL;
253 unset($_SESSION[$sessionName]);
6a488035
TO
254 }
255 }
2aa397bc 256 }
6a488035
TO
257
258 self::cleanup();
259 }
260
261 /* Retrieve the session values from the cache and populate the $_SESSION array
006389de
TO
262 *
263 * @param array $names
264 * Array of session values that should be persisted.
265 * This is either a form name + qfKey or just a form name
266 * (in the case of profile)
006389de 267 */
6a488035 268
b5c2afd0 269 /**
1a4e6781
EM
270 * Restore session from cache.
271 *
100fef9d 272 * @param string $names
b5c2afd0 273 */
00be9182 274 public static function restoreSessionFromCache($names) {
6a488035
TO
275 foreach ($names as $key => $sessionName) {
276 if (is_array($sessionName)) {
277 $value = self::getItem('CiviCRM Session',
278 "{$sessionName[0]}_{$sessionName[1]}"
279 );
280 if ($value) {
281 $_SESSION[$sessionName[0]][$sessionName[1]] = $value;
282 }
283 }
284 else {
285 $value = self::getItem('CiviCRM Session',
286 $sessionName
287 );
288 if ($value) {
289 $_SESSION[$sessionName] = $value;
290 }
291 }
292 }
293 }
294
295 /**
1a4e6781
EM
296 * Do periodic cleanup of the CiviCRM session table.
297 *
298 * Also delete all session cache entries which are a couple of days old.
299 * This keeps the session cache to a manageable size
6a488035 300 *
554259a7
EM
301 * @param bool $session
302 * @param bool $table
303 * @param bool $prevNext
6a488035 304 */
2aa397bc 305 public static function cleanup($session = FALSE, $table = FALSE, $prevNext = FALSE) {
6a488035
TO
306 // clean up the session cache every $cacheCleanUpNumber probabilistically
307 $cleanUpNumber = 757;
308
309 // clean up all sessions older than $cacheTimeIntervalDays days
310 $timeIntervalDays = 2;
311 $timeIntervalMins = 30;
312
313 if (mt_rand(1, 100000) % $cleanUpNumber == 0) {
2aa397bc 314 $session = $table = $prevNext = TRUE;
6a488035
TO
315 }
316
f9f40af3 317 if (!$session && !$table && !$prevNext) {
6a488035
TO
318 return;
319 }
320
f9f40af3 321 if ($prevNext) {
6a488035
TO
322 // delete all PrevNext caches
323 CRM_Core_BAO_PrevNextCache::cleanupCache();
324 }
325
f9f40af3 326 if ($table) {
40c712ed 327 CRM_Core_Config::clearTempTables($timeIntervalDays . ' day');
6a488035
TO
328 }
329
f9f40af3 330 if ($session) {
6a488035
TO
331 // first delete all sessions which are related to any potential transaction
332 // page
333 $transactionPages = array(
f9f40af3
TO
334 'CRM_Contribute_Controller_Contribution',
335 'CRM_Event_Controller_Registration',
336 );
6a488035
TO
337
338 $params = array(
1a4e6781
EM
339 1 => array(
340 date('Y-m-d H:i:s', time() - $timeIntervalMins * 60),
341 'String',
342 ),
6a488035
TO
343 );
344 foreach ($transactionPages as $trPage) {
345 $params[] = array("%${trPage}%", 'String');
795492f3 346 $where[] = 'path LIKE %' . count($params);
6a488035
TO
347 }
348
349 $sql = "
350DELETE FROM civicrm_cache
351WHERE group_name = 'CiviCRM Session'
352AND created_date <= %1
f9f40af3 353AND (" . implode(' OR ', $where) . ")";
6a488035
TO
354 CRM_Core_DAO::executeQuery($sql, $params);
355
356 $sql = "
357DELETE FROM civicrm_cache
358WHERE group_name = 'CiviCRM Session'
359AND created_date < date_sub( NOW( ), INTERVAL $timeIntervalDays DAY )
360";
361 CRM_Core_DAO::executeQuery($sql);
8c52547a 362 }
6a488035 363 }
96025800 364
6a488035 365}