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