Merge pull request #13039 from colemanw/quicksearchSetting
[civicrm-core.git] / CRM / Admin / Page / AJAX.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2018 |
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 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2018
32 */
33
34 /**
35 * This class contains all the function that are called using AJAX.
36 */
37 class CRM_Admin_Page_AJAX {
38
39 /**
40 * CRM-12337 Output navigation menu as executable javascript.
41 *
42 * @see smarty_function_crmNavigationMenu
43 */
44 public static function getNavigationMenu() {
45 $contactID = CRM_Core_Session::singleton()->get('userID');
46 if ($contactID) {
47 CRM_Core_Page_AJAX::setJsHeaders();
48 $smarty = CRM_Core_Smarty::singleton();
49 $smarty->assign('quicksearchOptions', self::getSearchOptions());
50 print $smarty->fetchWith('CRM/common/navigation.js.tpl', array(
51 'navigation' => CRM_Core_BAO_Navigation::createNavigation(),
52 ));
53 }
54 CRM_Utils_System::civiExit();
55 }
56
57 public static function getSearchOptions() {
58 $searchOptions = Civi::settings()->get('quicksearch_options');
59 $searchOptions[] = 'sort_name';
60 $searchOptions = array_intersect_key(CRM_Core_SelectValues::quicksearchOptions(), array_flip($searchOptions));
61 foreach ($searchOptions as $key => $label) {
62 if (strpos($key, 'custom_') === 0) {
63 unset($searchOptions[$key]);
64 $id = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', substr($key, 7), 'id', 'name');
65 $searchOptions["custom_$id"] = $label;
66 }
67 }
68 return $searchOptions;
69 }
70
71 /**
72 * Process drag/move action for menu tree.
73 */
74 public static function menuTree() {
75 CRM_Core_BAO_Navigation::processNavigation($_GET);
76 }
77
78 /**
79 * Build status message while enabling/ disabling various objects.
80 */
81 public static function getStatusMsg() {
82 require_once 'api/v3/utils.php';
83 $recordID = CRM_Utils_Type::escape($_GET['id'], 'Integer');
84 $entity = CRM_Utils_Type::escape($_GET['entity'], 'String');
85 $ret = array();
86
87 if ($recordID && $entity && $recordBAO = _civicrm_api3_get_BAO($entity)) {
88 switch ($recordBAO) {
89 case 'CRM_Core_BAO_UFGroup':
90 $method = 'getUFJoinRecord';
91 $result = array($recordBAO, $method);
92 $ufJoin = call_user_func_array(($result), array($recordID, TRUE));
93 if (!empty($ufJoin)) {
94 $ret['content'] = ts('This profile is currently used for %1.', array(1 => implode(', ', $ufJoin))) . ' <br/><br/>' . ts('If you disable the profile - it will be removed from these forms and/or modules. Do you want to continue?');
95 }
96 else {
97 $ret['content'] = ts('Are you sure you want to disable this profile?');
98 }
99 break;
100
101 case 'CRM_Price_BAO_PriceSet':
102 $usedBy = CRM_Price_BAO_PriceSet::getUsedBy($recordID);
103 $priceSet = CRM_Price_BAO_PriceSet::getTitle($recordID);
104
105 if (!CRM_Utils_System::isNull($usedBy)) {
106 $template = CRM_Core_Smarty::singleton();
107 $template->assign('usedBy', $usedBy);
108 $comps = array(
109 'Event' => 'civicrm_event',
110 'Contribution' => 'civicrm_contribution_page',
111 'EventTemplate' => 'civicrm_event_template',
112 );
113 $contexts = array();
114 foreach ($comps as $name => $table) {
115 if (array_key_exists($table, $usedBy)) {
116 $contexts[] = $name;
117 }
118 }
119 $template->assign('contexts', $contexts);
120
121 $ret['illegal'] = TRUE;
122 $table = $template->fetch('CRM/Price/Page/table.tpl');
123 $ret['content'] = ts('Unable to disable the \'%1\' price set - it is currently in use by one or more active events, contribution pages or contributions.', array(
124 1 => $priceSet,
125 )) . "<br/> $table";
126 }
127 else {
128 $ret['content'] = ts('Are you sure you want to disable \'%1\' Price Set?', array(1 => $priceSet));
129 }
130 break;
131
132 case 'CRM_Event_BAO_Event':
133 $ret['content'] = ts('Are you sure you want to disable this Event?');
134 break;
135
136 case 'CRM_Core_BAO_UFField':
137 $ret['content'] = ts('Are you sure you want to disable this CiviCRM Profile field?');
138 break;
139
140 case 'CRM_Contribute_BAO_Product':
141 $ret['content'] = ts('Are you sure you want to disable this premium? This action will remove the premium from any contribution pages that currently offer it. However it will not delete the premium record - so you can re-enable it and add it back to your contribution page(s) at a later time.');
142 break;
143
144 case 'CRM_Contact_BAO_Relationship':
145 $ret['content'] = ts('Are you sure you want to disable this relationship?');
146 break;
147
148 case 'CRM_Contact_BAO_RelationshipType':
149 $ret['content'] = ts('Are you sure you want to disable this relationship type?') . '<br/><br/>' . ts('Users will no longer be able to select this value when adding or editing relationships between contacts.');
150 break;
151
152 case 'CRM_Financial_BAO_FinancialType':
153 $ret['content'] = ts('Are you sure you want to disable this financial type?');
154 break;
155
156 case 'CRM_Financial_BAO_FinancialAccount':
157 if (!CRM_Financial_BAO_FinancialAccount::getARAccounts($recordID)) {
158 $ret['illegal'] = TRUE;
159 $ret['content'] = ts('The selected financial account cannot be disabled because at least one Accounts Receivable type account is required (to ensure that accounting transactions are in balance).');
160 }
161 else {
162 $ret['content'] = ts('Are you sure you want to disable this financial account?');
163 }
164 break;
165
166 case 'CRM_Financial_BAO_PaymentProcessor':
167 $ret['content'] = ts('Are you sure you want to disable this payment processor?') . ' <br/><br/>' . ts('Users will no longer be able to select this value when adding or editing transaction pages.');
168 break;
169
170 case 'CRM_Financial_BAO_PaymentProcessorType':
171 $ret['content'] = ts('Are you sure you want to disable this payment processor type?');
172 break;
173
174 case 'CRM_Core_BAO_LocationType':
175 $ret['content'] = ts('Are you sure you want to disable this location type?') . ' <br/><br/>' . ts('Users will no longer be able to select this value when adding or editing contact locations.');
176 break;
177
178 case 'CRM_Event_BAO_ParticipantStatusType':
179 $ret['content'] = ts('Are you sure you want to disable this Participant Status?') . '<br/><br/> ' . ts('Users will no longer be able to select this value when adding or editing Participant Status.');
180 break;
181
182 case 'CRM_Mailing_BAO_MailingComponent':
183 $ret['content'] = ts('Are you sure you want to disable this component?');
184 break;
185
186 case 'CRM_Core_BAO_CustomField':
187 $ret['content'] = ts('Are you sure you want to disable this custom data field?');
188 break;
189
190 case 'CRM_Core_BAO_CustomGroup':
191 $ret['content'] = ts('Are you sure you want to disable this custom data group? Any profile fields that are linked to custom fields of this group will be disabled.');
192 break;
193
194 case 'CRM_Core_BAO_MessageTemplate':
195 $ret['content'] = ts('Are you sure you want to disable this message tempate?');
196 break;
197
198 case 'CRM_ACL_BAO_ACL':
199 $ret['content'] = ts('Are you sure you want to disable this ACL?');
200 break;
201
202 case 'CRM_ACL_BAO_EntityRole':
203 $ret['content'] = ts('Are you sure you want to disable this ACL Role Assignment?');
204 break;
205
206 case 'CRM_Member_BAO_MembershipType':
207 $ret['content'] = ts('Are you sure you want to disable this membership type?');
208 break;
209
210 case 'CRM_Member_BAO_MembershipStatus':
211 $ret['content'] = ts('Are you sure you want to disable this membership status rule?');
212 break;
213
214 case 'CRM_Price_BAO_PriceField':
215 $ret['content'] = ts('Are you sure you want to disable this price field?');
216 break;
217
218 case 'CRM_Contact_BAO_Group':
219 $ret['content'] = ts('Are you sure you want to disable this Group?');
220 break;
221
222 case 'CRM_Core_BAO_OptionGroup':
223 $ret['content'] = ts('Are you sure you want to disable this Option?');
224 break;
225
226 case 'CRM_Contact_BAO_ContactType':
227 $ret['content'] = ts('Are you sure you want to disable this Contact Type?');
228 break;
229
230 case 'CRM_Core_BAO_OptionValue':
231 $label = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $recordID, 'label');
232 $ret['content'] = ts('Are you sure you want to disable the \'%1\' option ?', array(1 => $label));
233 $ret['content'] .= '<br /><br />' . ts('WARNING - Disabling an option which has been assigned to existing records will result in that option being cleared when the record is edited.');
234 break;
235
236 case 'CRM_Contribute_BAO_ContributionRecur':
237 $recurDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recordID);
238 $ret['content'] = ts('Are you sure you want to mark this recurring contribution as cancelled?');
239 $ret['content'] .= '<br /><br /><strong>' . ts('WARNING - This action sets the CiviCRM recurring contribution status to Cancelled, but does NOT send a cancellation request to the payment processor. You will need to ensure that this recurring payment (subscription) is cancelled by the payment processor.') . '</strong>';
240 if ($recurDetails->membership_id) {
241 $ret['content'] .= '<br /><br /><strong>' . ts('This recurring contribution is linked to an auto-renew membership. If you cancel it, the associated membership will no longer renew automatically. However, the current membership status will not be affected.') . '</strong>';
242 }
243 break;
244
245 default:
246 $ret['content'] = ts('Are you sure you want to disable this record?');
247 break;
248 }
249 }
250 else {
251 $ret = array('status' => 'error', 'content' => 'Error: Unknown entity type.', 'illegal' => TRUE);
252 }
253 CRM_Core_Page_AJAX::returnJsonResponse($ret);
254 }
255
256 /**
257 * Get a list of mappings.
258 *
259 * This appears to be only used by scheduled reminders.
260 */
261 static public function mappingList() {
262 if (empty($_GET['mappingID'])) {
263 CRM_Utils_JSON::output(array('status' => 'error', 'error_msg' => 'required params missing.'));
264 }
265
266 $mapping = CRM_Core_BAO_ActionSchedule::getMapping($_GET['mappingID']);
267 $dateFieldLabels = $mapping ? $mapping->getDateFields() : array();
268
269 // The UX here is quirky -- for "Activity" types, there's a simple drop "Recipients"
270 // dropdown which is always displayed. For other types, the "Recipients" drop down is
271 // conditional upon the weird isLimit ('Limit To / Also Include / Neither') dropdown.
272 $noThanksJustKidding = !$_GET['isLimit'];
273 if ($mapping instanceof CRM_Activity_ActionMapping || !$noThanksJustKidding) {
274 $entityRecipientLabels = $mapping ? ($mapping->getRecipientTypes() + CRM_Core_BAO_ActionSchedule::getAdditionalRecipients()) : array();
275 }
276 else {
277 $entityRecipientLabels = CRM_Core_BAO_ActionSchedule::getAdditionalRecipients();
278 }
279 $recipientMapping = array_combine(array_keys($entityRecipientLabels), array_keys($entityRecipientLabels));
280
281 $output = array(
282 'sel4' => CRM_Utils_Array::makeNonAssociative($dateFieldLabels),
283 'sel5' => CRM_Utils_Array::makeNonAssociative($entityRecipientLabels),
284 'recipientMapping' => $recipientMapping,
285 );
286
287 CRM_Utils_JSON::output($output);
288 }
289
290 /**
291 * (Scheduled Reminders) Get the list of possible recipient filters.
292 *
293 * Ex: GET /civicrm/ajax/recipientListing?mappingID=contribpage&recipientType=
294 */
295 public static function recipientListing() {
296 $mappingID = filter_input(INPUT_GET, 'mappingID', FILTER_VALIDATE_REGEXP, array(
297 'options' => array(
298 'regexp' => '/^[a-zA-Z0-9_\-]+$/',
299 ),
300 ));
301 $recipientType = filter_input(INPUT_GET, 'recipientType', FILTER_VALIDATE_REGEXP, array(
302 'options' => array(
303 'regexp' => '/^[a-zA-Z0-9_\-]+$/',
304 ),
305 ));
306
307 CRM_Utils_JSON::output(array(
308 'recipients' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_ActionSchedule::getRecipientListing($mappingID, $recipientType)),
309 ));
310 }
311
312 /**
313 * Outputs one branch in the tag tree
314 *
315 * Used by jstree to incrementally load tags
316 */
317 public static function getTagTree() {
318 $parent = CRM_Utils_Type::escape(CRM_Utils_Array::value('parent_id', $_GET, 0), 'Integer');
319 $substring = CRM_Utils_Type::escape(CRM_Utils_Array::value('str', $_GET), 'String');
320 $result = array();
321
322 $whereClauses = array('is_tagset <> 1');
323 $orderColumn = 'name';
324
325 // fetch all child tags in Array('parent_tag' => array('child_tag_1', 'child_tag_2', ...)) format
326 $childTagIDs = CRM_Core_BAO_Tag::getChildTags($substring);
327 $parentIDs = array_keys($childTagIDs);
328
329 if ($parent) {
330 $whereClauses[] = "parent_id = $parent";
331 }
332 elseif ($substring) {
333 $whereClauses['substring'] = " name LIKE '%$substring%' ";
334 if (!empty($parentIDs)) {
335 $whereClauses['substring'] = sprintf(" %s OR id IN (%s) ", $whereClauses['substring'], implode(',', $parentIDs));
336 }
337 $orderColumn = 'id';
338 }
339 else {
340 $whereClauses[] = "parent_id IS NULL";
341 }
342
343 $dao = CRM_Utils_SQL_Select::from('civicrm_tag')
344 ->where($whereClauses)
345 ->groupBy('id')
346 ->orderBy($orderColumn)
347 ->execute();
348
349 while ($dao->fetch()) {
350 if (!empty($substring)) {
351 $result[] = $dao->id;
352 if (!empty($childTagIDs[$dao->id])) {
353 $result = array_merge($result, $childTagIDs[$dao->id]);
354 }
355 }
356 else {
357 $hasChildTags = empty($childTagIDs[$dao->id]) ? FALSE : TRUE;
358 $usedFor = (array) explode(',', $dao->used_for);
359 $tag = [
360 'id' => $dao->id,
361 'text' => $dao->name,
362 'a_attr' => [
363 'class' => 'crm-tag-item',
364 ],
365 'children' => $hasChildTags,
366 'data' => [
367 'description' => (string) $dao->description,
368 'is_selectable' => (bool) $dao->is_selectable,
369 'is_reserved' => (bool) $dao->is_reserved,
370 'used_for' => $usedFor,
371 'color' => $dao->color ? $dao->color : '#ffffff',
372 'usages' => civicrm_api3('EntityTag', 'getcount', [
373 'entity_table' => ['IN' => $usedFor],
374 'tag_id' => $dao->id,
375 ]),
376 ],
377 ];
378 if ($dao->description || $dao->is_reserved) {
379 $tag['li_attr']['title'] = ((string) $dao->description) . ($dao->is_reserved ? ' (*' . ts('Reserved') . ')' : '');
380 }
381 if ($dao->is_reserved) {
382 $tag['li_attr']['class'] = 'is-reserved';
383 }
384 if ($dao->color) {
385 $tag['a_attr']['style'] = "background-color: {$dao->color}; color: " . CRM_Utils_Color::getContrast($dao->color);
386 }
387 $result[] = $tag;
388 }
389 }
390
391 if ($substring) {
392 $result = array_values(array_unique($result));
393 }
394
395 if (!empty($_REQUEST['is_unit_test'])) {
396 return $result;
397 }
398
399 CRM_Utils_JSON::output($result);
400 }
401
402 }