Merge pull request #15773 from civicrm/5.20
[civicrm-core.git] / CRM / Core / PrevNextCache / Sql.php
CommitLineData
780fd0e3
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
f299f7db 6 | Copyright CiviCRM LLC (c) 2004-2020 |
780fd0e3
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 +--------------------------------------------------------------------+
26 */
27
28/**
29 * Class CRM_Core_PrevNextCache_Sql
30 *
31 * Store the previous/next cache in a special-purpose SQL table.
32 */
33class CRM_Core_PrevNextCache_Sql implements CRM_Core_PrevNextCache_Interface {
32a2c024 34
435fc552
SL
35 /**
36 * @var int
37 * Days for cache to llast forr
38 */
39 const cacheDays = 2;
40
32a2c024
TO
41 /**
42 * Store the results of a SQL query in the cache.
518fa0ee 43 * @param string $cacheKey
32a2c024
TO
44 * @param string $sql
45 * A SQL query. The query *MUST* be a SELECT statement which yields
783b4b21 46 * the following columns (in order): cachekey, entity_id1, data
2c8b42d5 47 * @param array $sqlParams
f939667b
TO
48 * An array of parameters to be used with $sql.
49 * Use the same interpolation format as CRM_Core_DAO (composeQuery/executeQuery).
50 * Ex: [1 => ['foo', 'String']]
32a2c024
TO
51 * @return bool
52 * @throws CRM_Core_Exception
f939667b 53 * @see CRM_Core_DAO::composeQuery
32a2c024 54 */
2c8b42d5 55 public function fillWithSql($cacheKey, $sql, $sqlParams = []) {
32a2c024 56 $insertSQL = "
783b4b21 57INSERT INTO civicrm_prevnext_cache (cachekey, entity_id1, data)
32a2c024 58";
2c8b42d5 59 $result = CRM_Core_DAO::executeQuery($insertSQL . $sql, $sqlParams, FALSE, NULL, FALSE, TRUE, TRUE);
32a2c024
TO
60 if (is_a($result, 'DB_Error')) {
61 throw new CRM_Core_Exception($result->message);
62 }
63 return TRUE;
64 }
65
83068a64
TO
66 public function fillWithArray($cacheKey, $rows) {
67 if (empty($rows)) {
68 return;
69 }
70
71 $insert = CRM_Utils_SQL_Insert::into('civicrm_prevnext_cache')
72 ->columns([
83068a64 73 'entity_id1',
783b4b21 74 'cachekey',
518fa0ee 75 'data',
83068a64
TO
76 ]);
77
78 foreach ($rows as &$row) {
783b4b21 79 $insert->row($row + ['cachekey' => $cacheKey]);
83068a64
TO
80 }
81
82 CRM_Core_DAO::executeQuery($insert->toSQL());
83 return TRUE;
84 }
85
0b8038a6
TO
86 /**
87 * Save checkbox selections.
88 *
89 * @param string $cacheKey
90 * @param string $action
91 * Ex: 'select', 'unselect'.
e97c66ff 92 * @param array|int|null $ids
0b8038a6
TO
93 * A list of contact IDs to (un)select.
94 * To unselect all contact IDs, use NULL.
0b8038a6 95 */
514813c0 96 public function markSelection($cacheKey, $action, $ids = NULL) {
0b8038a6
TO
97 if (!$cacheKey) {
98 return;
99 }
be2fb01f 100 $params = [];
0b8038a6 101
514813c0
TO
102 if ($ids && $cacheKey && $action) {
103 if (is_array($ids)) {
104 $cIdFilter = "(" . implode(',', $ids) . ")";
0b8038a6 105 $whereClause = "
783b4b21 106WHERE cachekey = %1
0b8038a6
TO
107AND (entity_id1 IN {$cIdFilter} OR entity_id2 IN {$cIdFilter})
108";
109 }
110 else {
111 $whereClause = "
783b4b21 112WHERE cachekey = %1
0b8038a6
TO
113AND (entity_id1 = %2 OR entity_id2 = %2)
114";
be2fb01f 115 $params[2] = ["{$ids}", 'Integer'];
0b8038a6
TO
116 }
117 if ($action == 'select') {
118 $whereClause .= "AND is_selected = 0";
ec192197 119 $sql = "UPDATE civicrm_prevnext_cache SET is_selected = 1 {$whereClause}";
be2fb01f 120 $params[1] = [$cacheKey, 'String'];
0b8038a6
TO
121 }
122 elseif ($action == 'unselect') {
123 $whereClause .= "AND is_selected = 1";
ec192197 124 $sql = "UPDATE civicrm_prevnext_cache SET is_selected = 0 {$whereClause}";
be2fb01f 125 $params[1] = [$cacheKey, 'String'];
0b8038a6
TO
126 }
127 // default action is reseting
128 }
514813c0 129 elseif (!$ids && $cacheKey && $action == 'unselect') {
0b8038a6
TO
130 $sql = "
131UPDATE civicrm_prevnext_cache
132SET is_selected = 0
783b4b21 133WHERE cachekey = %1 AND is_selected = 1
0b8038a6 134";
be2fb01f 135 $params[1] = [$cacheKey, 'String'];
0b8038a6
TO
136 }
137 CRM_Core_DAO::executeQuery($sql, $params);
138 }
139
b7994703
TO
140 /**
141 * Get the selections.
142 *
143 * @param string $cacheKey
144 * Cache key.
145 * @param string $action
40ddbe99
TO
146 * One of the following:
147 * - 'get' - get only selection records
148 * - 'getall' - get all the records of the specified cache key
b7994703
TO
149 *
150 * @return array|NULL
151 */
40ddbe99 152 public function getSelection($cacheKey, $action = 'get') {
b7994703
TO
153 if (!$cacheKey) {
154 return NULL;
155 }
be2fb01f 156 $params = [];
b7994703 157
b7994703
TO
158 if ($cacheKey && ($action == 'get' || $action == 'getall')) {
159 $actionGet = ($action == "get") ? " AND is_selected = 1 " : "";
160 $sql = "
ec192197 161SELECT entity_id1 FROM civicrm_prevnext_cache
783b4b21 162WHERE cachekey = %1
b7994703 163 $actionGet
b7994703
TO
164ORDER BY id
165";
be2fb01f 166 $params[1] = [$cacheKey, 'String'];
b7994703 167
be2fb01f 168 $contactIds = [$cacheKey => []];
b7994703
TO
169 $cIdDao = CRM_Core_DAO::executeQuery($sql, $params);
170 while ($cIdDao->fetch()) {
ec192197 171 $contactIds[$cacheKey][$cIdDao->entity_id1] = 1;
b7994703
TO
172 }
173 return $contactIds;
174 }
175 }
176
d379a6d9
TO
177 /**
178 * Get the previous and next keys.
179 *
180 * @param string $cacheKey
181 * @param int $id1
d379a6d9
TO
182 *
183 * @return array
184 */
ec192197
TO
185 public function getPositions($cacheKey, $id1) {
186 $mergeId = CRM_Core_DAO::singleValueQuery(
783b4b21 187 "SELECT id FROM civicrm_prevnext_cache WHERE cachekey = %2 AND entity_id1 = %1",
ec192197
TO
188 [
189 1 => [$id1, 'Integer'],
190 2 => [$cacheKey, 'String'],
191 ]
192 );
193
194 $pos = ['foundEntry' => 0];
195 if ($mergeId) {
196 $pos['foundEntry'] = 1;
197
198 $sql = "SELECT pn.id, pn.entity_id1, pn.entity_id2, pn.data FROM civicrm_prevnext_cache pn ";
783b4b21
SL
199 $wherePrev = " WHERE pn.id < %1 AND pn.cachekey = %2 ORDER BY ID DESC LIMIT 1";
200 $whereNext = " WHERE pn.id > %1 AND pn.cachekey = %2 ORDER BY ID ASC LIMIT 1";
ec192197
TO
201 $p = [
202 1 => [$mergeId, 'Integer'],
203 2 => [$cacheKey, 'String'],
204 ];
205
206 $dao = CRM_Core_DAO::executeQuery($sql . $wherePrev, $p);
207 if ($dao->fetch()) {
208 $pos['prev']['id1'] = $dao->entity_id1;
209 $pos['prev']['mergeId'] = $dao->id;
210 $pos['prev']['data'] = $dao->data;
211 }
212
213 $dao = CRM_Core_DAO::executeQuery($sql . $whereNext, $p);
214 if ($dao->fetch()) {
215 $pos['next']['id1'] = $dao->entity_id1;
216 $pos['next']['mergeId'] = $dao->id;
217 $pos['next']['data'] = $dao->data;
218 }
219 }
220 return $pos;
221
d379a6d9
TO
222 }
223
744b4e34
TO
224 /**
225 * Delete an item from the prevnext cache table based on the entity.
226 *
227 * @param int $id
228 * @param string $cacheKey
744b4e34 229 */
ec192197
TO
230 public function deleteItem($id = NULL, $cacheKey = NULL) {
231 $sql = "DELETE FROM civicrm_prevnext_cache WHERE (1)";
be2fb01f 232 $params = [];
15df34f4
TO
233
234 if (is_numeric($id)) {
235 $sql .= " AND ( entity_id1 = %2 OR entity_id2 = %2 )";
be2fb01f 236 $params[2] = [$id, 'Integer'];
15df34f4
TO
237 }
238
239 if (isset($cacheKey)) {
783b4b21 240 $sql .= " AND cachekey = %3";
be2fb01f 241 $params[3] = [$cacheKey, 'String'];
15df34f4
TO
242 }
243 CRM_Core_DAO::executeQuery($sql, $params);
744b4e34
TO
244 }
245
c93f3d19
TO
246 /**
247 * Get count of matching rows.
248 *
249 * @param string $cacheKey
250 * @return int
251 */
252 public function getCount($cacheKey) {
783b4b21 253 $query = "SELECT COUNT(*) FROM civicrm_prevnext_cache pn WHERE pn.cachekey = %1";
ec192197
TO
254 $params = [1 => [$cacheKey, 'String']];
255 return (int) CRM_Core_DAO::singleValueQuery($query, $params, TRUE, FALSE);
c93f3d19
TO
256 }
257
2ca46d4d
TO
258 /**
259 * Fetch a list of contacts from the prev/next cache for displaying a search results page
260 *
261 * @param string $cacheKey
262 * @param int $offset
263 * @param int $rowCount
264 * @return array
265 * List of contact IDs.
266 */
267 public function fetch($cacheKey, $offset, $rowCount) {
be2fb01f 268 $cids = [];
2ca46d4d 269 $dao = CRM_Utils_SQL_Select::from('civicrm_prevnext_cache pnc')
783b4b21 270 ->where('pnc.cachekey = @cacheKey', ['cacheKey' => $cacheKey])
2ca46d4d
TO
271 ->select('pnc.entity_id1 as cid')
272 ->orderBy('pnc.id')
273 ->limit($rowCount, $offset)
274 ->execute();
275 while ($dao->fetch()) {
276 $cids[] = $dao->cid;
277 }
278 return $cids;
279 }
280
435fc552
SL
281 /**
282 * @inheritDoc
283 */
284 public function cleanup() {
285 // clean up all prev next caches older than $cacheTimeIntervalDays days
286 // first find all the cacheKeys that match this
287 $sql = "
288 DELETE pn, c
289 FROM civicrm_cache c
290 INNER JOIN civicrm_prevnext_cache pn ON c.path = pn.cachekey
291 WHERE c.group_name = %1
292 AND c.created_date < date_sub( NOW( ), INTERVAL %2 day )
293 ";
294 $params = [
295 1 => [CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache'), 'String'],
296 2 => [self::cacheDays, 'Integer'],
297 ];
298 CRM_Core_DAO::executeQuery($sql, $params);
299 }
300
780fd0e3 301}