Merge pull request #19093 from civicrm/5.32
[civicrm-core.git] / CRM / Core / Page / AJAX.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
19 * This is base class for all ajax calls
20 */
21class CRM_Core_Page_AJAX {
22
23 /**
fe482240 24 * Call generic ajax forms.
6a488035 25 *
6a488035 26 */
00be9182 27 public static function run() {
6a488035
TO
28 $className = CRM_Utils_Type::escape($_REQUEST['class_name'], 'String');
29 $type = '';
30 if (!empty($_REQUEST['type'])) {
31 $type = CRM_Utils_Type::escape($_REQUEST['type'], 'String');
32 }
33
34 if (!$className) {
79e11805 35 throw new CRM_Core_Exception(ts('Invalid className: %1', [1 => $className]));
6a488035
TO
36 }
37
38 $fnName = NULL;
39 if (isset($_REQUEST['fn_name'])) {
40 $fnName = CRM_Utils_Type::escape($_REQUEST['fn_name'], 'String');
41 }
42
43 if (!self::checkAuthz($type, $className, $fnName)) {
44 CRM_Utils_System::civiExit();
45 }
46
47 switch ($type) {
48 case 'method':
be2fb01f 49 call_user_func([$className, $fnName]);
6a488035
TO
50 break;
51
52 case 'page':
53 case 'class':
54 case '':
55 // FIXME: This is done to maintain current wire protocol, but it might be
56 // simpler to just require different 'types' for pages and forms
57 if (preg_match('/^CRM_[a-zA-Z0-9]+_Page_Inline_/', $className)) {
7c550ca0 58 $page = new $className();
6a488035
TO
59 $page->run();
60 }
61 else {
62 $wrapper = new CRM_Utils_Wrapper();
63 $wrapper->run($className);
64 }
65 break;
2aa397bc 66
6a488035
TO
67 default:
68 CRM_Core_Error::debug_log_message('Unsupported inline request type: ' . var_export($type, TRUE));
69 }
70 CRM_Utils_System::civiExit();
71 }
72
73 /**
fe482240 74 * Change is_quick_config priceSet to complex.
6a488035 75 *
6a488035 76 */
00be9182 77 public static function setIsQuickConfig() {
6a488035 78 $id = $context = NULL;
a7488080 79 if (!empty($_REQUEST['id'])) {
6a488035
TO
80 $id = CRM_Utils_Type::escape($_REQUEST['id'], 'Integer');
81 }
cbb7c7e0 82
edc80cda
SM
83 $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric');
84
cbb7c7e0 85 // return false if $id is null and
6a488035 86 // $context is not civicrm_event or civicrm_contribution_page
be2fb01f 87 if (!$id || !in_array($context, ['civicrm_event', 'civicrm_contribution_page'])) {
2aa397bc 88 return FALSE;
6a488035 89 }
9da8dc8c 90 $priceSetId = CRM_Price_BAO_PriceSet::getFor($context, $id, NULL);
6a488035 91 if ($priceSetId) {
50e2d48d 92 $sql = "UPDATE
93 civicrm_price_set cps
94 INNER JOIN civicrm_price_set_entity cpse ON cps.id = cpse.price_set_id
95 INNER JOIN {$context} ce ON cpse.entity_id = ce.id AND ce.id = %1
96 SET cps.is_quick_config = 0, cps.financial_type_id = IF(cps.financial_type_id IS NULL, ce.financial_type_id, cps.financial_type_id)
97 ";
be2fb01f 98 CRM_Core_DAO::executeQuery($sql, [1 => [$id, 'Integer']]);
50e2d48d 99
6a488035 100 if ($context == 'civicrm_event') {
6a488035
TO
101 CRM_Core_BAO_Discount::del($id, $context);
102 }
103 }
50e2d48d 104
ecdef330 105 CRM_Utils_JSON::output($priceSetId);
6a488035
TO
106 }
107
108 /**
109 * Determine whether the request is for a valid class/method name.
110 *
6a0b768e
TO
111 * @param string $type
112 * 'method'|'class'|''.
113 * @param string $className
114 * 'Class_Name'.
115 * @param string $fnName
116 * Method name.
77b97be7
EM
117 *
118 * @return bool
6a488035 119 */
2aa397bc 120 public static function checkAuthz($type, $className, $fnName = NULL) {
6a488035
TO
121 switch ($type) {
122 case 'method':
123 if (!preg_match('/^CRM_[a-zA-Z0-9]+_Page_AJAX$/', $className)) {
124 return FALSE;
125 }
126 if (!preg_match('/^[a-zA-Z0-9]+$/', $fnName)) {
127 return FALSE;
128 }
129
130 // ensure that function exists
131 return method_exists($className, $fnName);
132
133 case 'page':
134 case 'class':
135 case '':
136 if (!preg_match('/^CRM_[a-zA-Z0-9]+_(Page|Form)_Inline_[a-zA-Z0-9]+$/', $className)) {
137 return FALSE;
138 }
139 return class_exists($className);
2aa397bc 140
6a488035
TO
141 default:
142 return FALSE;
143 }
144 }
03a7ec8f
CW
145
146 /**
147 * Outputs the CiviCRM standard json-formatted page/form response
148 * @param array|string $response
149 */
00be9182 150 public static function returnJsonResponse($response) {
03a7ec8f
CW
151 // Allow lazy callers to not wrap content in an array
152 if (is_string($response)) {
be2fb01f 153 $response = ['content' => $response];
03a7ec8f 154 }
0e017a41 155 // Add session variables to response
03a7ec8f 156 $session = CRM_Core_Session::singleton();
be2fb01f 157 $response += [
03a7ec8f
CW
158 'status' => 'success',
159 'userContext' => htmlspecialchars_decode($session->readUserContext()),
0e017a41 160 'title' => CRM_Utils_System::$title,
be2fb01f 161 ];
0e017a41
CW
162 // crmMessages will be automatically handled by our ajax preprocessor
163 // @see js/Common.js
03a7ec8f
CW
164 if ($session->getStatus(FALSE)) {
165 $response['crmMessages'] = $session->getStatus(TRUE);
166 }
5d76705d 167 $output = json_encode($response);
03a7ec8f
CW
168
169 // CRM-11831 @see http://www.malsup.com/jquery/form/#file-upload
5d76705d 170 if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
d42a224c 171 CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
03a7ec8f 172 }
5d76705d
CW
173 else {
174 $output = "<textarea>$output</textarea>";
03a7ec8f 175 }
5d76705d 176 echo $output;
03a7ec8f
CW
177 CRM_Utils_System::civiExit();
178 }
d6408252 179
4cc9b813 180 /**
fe482240 181 * Set headers appropriate for a js file.
e5afbdad 182 *
e97c66ff 183 * @param int|null $ttl
e5afbdad 184 * Time-to-live (seconds).
4cc9b813 185 */
e5afbdad
TO
186 public static function setJsHeaders($ttl = NULL) {
187 if ($ttl === NULL) {
188 // Encourage browsers to cache for a long time - 1 year
189 $ttl = 60 * 60 * 24 * 364;
190 }
d42a224c
CW
191 CRM_Utils_System::setHttpHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
192 CRM_Utils_System::setHttpHeader('Content-Type', 'application/javascript');
193 CRM_Utils_System::setHttpHeader('Cache-Control', "max-age=$ttl, public");
4cc9b813
CW
194 }
195
8246bca4 196 /**
197 * Set defaults for sort and pager.
198 *
199 * @param int $defaultOffset
200 * @param int $defaultRowCount
201 * @param string $defaultSort
202 * @param string $defaultsortOrder
203 *
204 * @return array
205 */
00f11506 206 public static function defaultSortAndPagerParams($defaultOffset = 0, $defaultRowCount = 25, $defaultSort = NULL, $defaultsortOrder = 'asc') {
be2fb01f
CW
207 $params = [
208 '_raw_values' => [],
209 ];
00f11506 210
be2fb01f 211 $sortMapper = [];
62cfbded
MM
212 if (isset($_GET['columns'])) {
213 foreach ($_GET['columns'] as $key => $value) {
a33b83c5 214 $sortMapper[$key] = CRM_Utils_Type::validate($value['data'], 'MysqlColumnNameOrAlias');
62cfbded
MM
215 };
216 }
00f11506 217
5d817a13
MM
218 $offset = isset($_GET['start']) ? CRM_Utils_Type::validate($_GET['start'], 'Integer') : $defaultOffset;
219 $rowCount = isset($_GET['length']) ? CRM_Utils_Type::validate($_GET['length'], 'Integer') : $defaultRowCount;
00f11506 220 // Why is the number of order by columns limited to 1?
5d817a13
MM
221 $sort = isset($_GET['order'][0]['column']) ? CRM_Utils_Array::value(CRM_Utils_Type::validate($_GET['order'][0]['column'], 'Integer'), $sortMapper) : $defaultSort;
222 $sortOrder = isset($_GET['order'][0]['dir']) ? CRM_Utils_Type::validate($_GET['order'][0]['dir'], 'MysqlOrderByDirection') : $defaultsortOrder;
00f11506
MM
223
224 if ($sort) {
2e58abf9 225 $params['sortBy'] = "{$sort} {$sortOrder}";
9c3f979f 226
da93a1ab
MM
227 $params['_raw_values']['sort'][0] = $sort;
228 $params['_raw_values']['order'][0] = $sortOrder;
00f11506
MM
229 }
230
9c3f979f 231 $params['offset'] = $offset;
00f11506 232 $params['rp'] = $rowCount;
9c3f979f
MM
233 $params['page'] = ($offset / $rowCount) + 1;
234
235 return $params;
236 }
237
f2ac86d1 238 /**
239 * Validate ajax input parameters.
240 *
241 * @param array $requiredParams
242 * @param array $optionalParams
243 *
244 * @return array
245 */
be2fb01f
CW
246 public static function validateParams($requiredParams = [], $optionalParams = []) {
247 $params = [];
9c3f979f
MM
248
249 foreach ($requiredParams as $param => $type) {
5d817a13 250 $params[$param] = CRM_Utils_Type::validate(CRM_Utils_Array::value($param, $_GET), $type);
9c3f979f
MM
251 }
252
253 foreach ($optionalParams as $param => $type) {
de6c59ca 254 if (!empty($_GET[$param])) {
c1d3e301 255 if (!is_array($_GET[$param])) {
256 $params[$param] = CRM_Utils_Type::validate(CRM_Utils_Array::value($param, $_GET), $type);
257 }
258 else {
259 foreach ($_GET[$param] as $index => $value) {
260 $params[$param][$index] = CRM_Utils_Type::validate($value, $type);
261 }
262 }
9c3f979f
MM
263 }
264 }
00f11506
MM
265
266 return $params;
9c3f979f 267
00f11506
MM
268 }
269
6a488035 270}