APIv4 - Add Address::getCoordinates action
[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
7511bc6e
TO
170 // COMMENT: Wouldn't the `Accept:` header be more appropriate? Only use `X-Requested-With:` as a
171 // fallback where `Accept:` is missing?
172 if (CRM_Utils_REST::isWebServiceRequest()) {
d42a224c 173 CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
03a7ec8f 174 }
5d76705d
CW
175 else {
176 $output = "<textarea>$output</textarea>";
03a7ec8f 177 }
5d76705d 178 echo $output;
03a7ec8f
CW
179 CRM_Utils_System::civiExit();
180 }
d6408252 181
4cc9b813 182 /**
fe482240 183 * Set headers appropriate for a js file.
e5afbdad 184 *
e97c66ff 185 * @param int|null $ttl
e5afbdad 186 * Time-to-live (seconds).
4cc9b813 187 */
e5afbdad
TO
188 public static function setJsHeaders($ttl = NULL) {
189 if ($ttl === NULL) {
190 // Encourage browsers to cache for a long time - 1 year
191 $ttl = 60 * 60 * 24 * 364;
192 }
d42a224c
CW
193 CRM_Utils_System::setHttpHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
194 CRM_Utils_System::setHttpHeader('Content-Type', 'application/javascript');
195 CRM_Utils_System::setHttpHeader('Cache-Control', "max-age=$ttl, public");
4cc9b813
CW
196 }
197
8246bca4 198 /**
199 * Set defaults for sort and pager.
200 *
201 * @param int $defaultOffset
202 * @param int $defaultRowCount
203 * @param string $defaultSort
204 * @param string $defaultsortOrder
205 *
206 * @return array
207 */
00f11506 208 public static function defaultSortAndPagerParams($defaultOffset = 0, $defaultRowCount = 25, $defaultSort = NULL, $defaultsortOrder = 'asc') {
be2fb01f
CW
209 $params = [
210 '_raw_values' => [],
211 ];
00f11506 212
be2fb01f 213 $sortMapper = [];
62cfbded
MM
214 if (isset($_GET['columns'])) {
215 foreach ($_GET['columns'] as $key => $value) {
a33b83c5 216 $sortMapper[$key] = CRM_Utils_Type::validate($value['data'], 'MysqlColumnNameOrAlias');
62cfbded
MM
217 };
218 }
00f11506 219
5d817a13
MM
220 $offset = isset($_GET['start']) ? CRM_Utils_Type::validate($_GET['start'], 'Integer') : $defaultOffset;
221 $rowCount = isset($_GET['length']) ? CRM_Utils_Type::validate($_GET['length'], 'Integer') : $defaultRowCount;
00f11506 222 // Why is the number of order by columns limited to 1?
5d817a13
MM
223 $sort = isset($_GET['order'][0]['column']) ? CRM_Utils_Array::value(CRM_Utils_Type::validate($_GET['order'][0]['column'], 'Integer'), $sortMapper) : $defaultSort;
224 $sortOrder = isset($_GET['order'][0]['dir']) ? CRM_Utils_Type::validate($_GET['order'][0]['dir'], 'MysqlOrderByDirection') : $defaultsortOrder;
00f11506
MM
225
226 if ($sort) {
2e58abf9 227 $params['sortBy'] = "{$sort} {$sortOrder}";
9c3f979f 228
da93a1ab
MM
229 $params['_raw_values']['sort'][0] = $sort;
230 $params['_raw_values']['order'][0] = $sortOrder;
00f11506
MM
231 }
232
9c3f979f 233 $params['offset'] = $offset;
00f11506 234 $params['rp'] = $rowCount;
9c3f979f
MM
235 $params['page'] = ($offset / $rowCount) + 1;
236
237 return $params;
238 }
239
f2ac86d1 240 /**
241 * Validate ajax input parameters.
242 *
243 * @param array $requiredParams
244 * @param array $optionalParams
245 *
246 * @return array
247 */
be2fb01f
CW
248 public static function validateParams($requiredParams = [], $optionalParams = []) {
249 $params = [];
9c3f979f
MM
250
251 foreach ($requiredParams as $param => $type) {
5d817a13 252 $params[$param] = CRM_Utils_Type::validate(CRM_Utils_Array::value($param, $_GET), $type);
9c3f979f
MM
253 }
254
255 foreach ($optionalParams as $param => $type) {
de6c59ca 256 if (!empty($_GET[$param])) {
c1d3e301 257 if (!is_array($_GET[$param])) {
258 $params[$param] = CRM_Utils_Type::validate(CRM_Utils_Array::value($param, $_GET), $type);
259 }
260 else {
261 foreach ($_GET[$param] as $index => $value) {
262 $params[$param][$index] = CRM_Utils_Type::validate($value, $type);
263 }
264 }
9c3f979f
MM
265 }
266 }
00f11506
MM
267
268 return $params;
9c3f979f 269
00f11506
MM
270 }
271
6a488035 272}