3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This class contains all the function that are called using AJAX.
21 class CRM_Admin_Page_AJAX
{
24 * Outputs menubar data (json format) for the current user.
26 public static function navMenu() {
27 if (CRM_Core_Session
::getLoggedInContactID()) {
29 $menu = CRM_Core_BAO_Navigation
::buildNavigationTree();
30 CRM_Core_BAO_Navigation
::buildHomeMenu($menu);
31 CRM_Utils_Hook
::navigationMenu($menu);
32 CRM_Core_BAO_Navigation
::fixNavigationMenu($menu);
33 CRM_Core_BAO_Navigation
::orderByWeight($menu);
34 CRM_Core_BAO_Navigation
::filterByPermission($menu);
35 self
::formatMenuItems($menu);
39 'search' => CRM_Utils_Array
::makeNonAssociative(self
::getSearchOptions()),
41 // Encourage browsers to cache for a long time - 1 year
42 $ttl = 60 * 60 * 24 * 364;
43 CRM_Utils_System
::setHttpHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() +
$ttl));
44 CRM_Utils_System
::setHttpHeader('Cache-Control', "max-age=$ttl, public");
45 CRM_Utils_System
::setHttpHeader('Content-Type', 'application/json');
46 print (json_encode($output));
48 CRM_Utils_System
::civiExit();
54 public static function formatMenuItems(&$menu) {
55 foreach ($menu as $key => &$item) {
56 $props = $item['attributes'];
57 unset($item['attributes']);
58 if (!empty($props['separator'])) {
59 $item['separator'] = ($props['separator'] == 1 ?
'bottom' : 'top');
61 if (!empty($props['icon'])) {
62 $item['icon'] = $props['icon'];
64 if (!empty($props['attr'])) {
65 $item['attr'] = $props['attr'];
67 if (!empty($props['url'])) {
68 $item['url'] = CRM_Utils_System
::evalUrl(CRM_Core_BAO_Navigation
::makeFullyFormedUrl($props['url']));
70 if (!empty($props['label'])) {
71 $item['label'] = ts($props['label'], ['context' => 'menu']);
73 $item['name'] = !empty($props['name']) ?
$props['name'] : CRM_Utils_String
::munge(CRM_Utils_Array
::value('label', $props));
74 if (!empty($item['child'])) {
75 self
::formatMenuItems($item['child']);
78 $menu = array_values($menu);
81 public static function getSearchOptions() {
82 $searchOptions = Civi
::settings()->get('quicksearch_options');
83 $labels = CRM_Core_SelectValues
::quicksearchOptions();
85 foreach ($searchOptions as $key) {
86 $label = $labels[$key];
87 if (strpos($key, 'custom_') === 0) {
88 $key = 'custom_' . CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField', substr($key, 7), 'id', 'name');
89 $label = array_slice(explode(': ', $label, 2), -1);
91 $result[$key] = $label;
97 * Process drag/move action for menu tree.
99 public static function menuTree() {
100 CRM_Core_BAO_Navigation
::processNavigation($_GET);
104 * Build status message while enabling/ disabling various objects.
106 public static function getStatusMsg() {
107 require_once 'api/v3/utils.php';
108 $recordID = CRM_Utils_Type
::escape($_GET['id'], 'Integer');
109 $entity = CRM_Utils_Type
::escape($_GET['entity'], 'String');
112 if ($recordID && $entity && $recordBAO = _civicrm_api3_get_BAO($entity)) {
113 switch ($recordBAO) {
114 case 'CRM_Core_BAO_UFGroup':
115 $method = 'getUFJoinRecord';
116 $result = [$recordBAO, $method];
117 $ufJoin = call_user_func_array(($result), [$recordID, TRUE]);
118 if (!empty($ufJoin)) {
119 $ret['content'] = ts('This profile is currently used for %1.', [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?');
122 $ret['content'] = ts('Are you sure you want to disable this profile?');
126 case 'CRM_Price_BAO_PriceSet':
127 $usedBy = CRM_Price_BAO_PriceSet
::getUsedBy($recordID);
128 $priceSet = CRM_Price_BAO_PriceSet
::getTitle($recordID);
130 if (!CRM_Utils_System
::isNull($usedBy)) {
131 $template = CRM_Core_Smarty
::singleton();
132 $template->assign('usedBy', $usedBy);
134 'Event' => 'civicrm_event',
135 'Contribution' => 'civicrm_contribution_page',
136 'EventTemplate' => 'civicrm_event_template',
139 foreach ($comps as $name => $table) {
140 if (array_key_exists($table, $usedBy)) {
144 $template->assign('contexts', $contexts);
146 $ret['illegal'] = TRUE;
147 $table = $template->fetch('CRM/Price/Page/table.tpl');
148 $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.', [
153 $ret['content'] = ts('Are you sure you want to disable \'%1\' Price Set?', [1 => $priceSet]);
157 case 'CRM_Event_BAO_Event':
158 $ret['content'] = ts('Are you sure you want to disable this Event?');
161 case 'CRM_Core_BAO_UFField':
162 $ret['content'] = ts('Are you sure you want to disable this CiviCRM Profile field?');
165 case 'CRM_Contribute_BAO_Product':
166 $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.');
169 case 'CRM_Contact_BAO_Relationship':
170 $ret['content'] = ts('Are you sure you want to disable this relationship?');
173 case 'CRM_Contact_BAO_RelationshipType':
174 $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.');
177 case 'CRM_Financial_BAO_FinancialType':
178 $ret['content'] = ts('Are you sure you want to disable this financial type?');
181 case 'CRM_Financial_BAO_FinancialAccount':
182 if (!CRM_Financial_BAO_FinancialAccount
::getARAccounts($recordID)) {
183 $ret['illegal'] = TRUE;
184 $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).');
187 $ret['content'] = ts('Are you sure you want to disable this financial account?');
191 case 'CRM_Financial_BAO_PaymentProcessor':
192 $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.');
195 case 'CRM_Financial_BAO_PaymentProcessorType':
196 $ret['content'] = ts('Are you sure you want to disable this payment processor type?');
199 case 'CRM_Core_BAO_LocationType':
200 $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.');
203 case 'CRM_Event_BAO_ParticipantStatusType':
204 $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.');
207 case 'CRM_Mailing_BAO_MailingComponent':
208 $ret['content'] = ts('Are you sure you want to disable this component?');
211 case 'CRM_Core_BAO_CustomField':
212 $ret['content'] = ts('Are you sure you want to disable this custom data field?');
215 case 'CRM_Core_BAO_CustomGroup':
216 $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.');
219 case 'CRM_Core_BAO_MessageTemplate':
220 $ret['content'] = ts('Are you sure you want to disable this message tempate?');
223 case 'CRM_ACL_BAO_ACL':
224 $ret['content'] = ts('Are you sure you want to disable this ACL?');
227 case 'CRM_ACL_BAO_EntityRole':
228 $ret['content'] = ts('Are you sure you want to disable this ACL Role Assignment?');
231 case 'CRM_Member_BAO_MembershipType':
232 $ret['content'] = ts('Are you sure you want to disable this membership type?');
235 case 'CRM_Member_BAO_MembershipStatus':
236 $ret['content'] = ts('Are you sure you want to disable this membership status rule?');
239 case 'CRM_Price_BAO_PriceField':
240 $ret['content'] = ts('Are you sure you want to disable this price field?');
243 case 'CRM_Contact_BAO_Group':
244 $ret['content'] = ts('Are you sure you want to disable this Group?');
245 $ret['content'] .= '<br /><br /><strong>' . ts('WARNING - Disabling this group will disable all the child groups associated if any.') . '</strong>';
248 case 'CRM_Core_BAO_OptionGroup':
249 $ret['content'] = ts('Are you sure you want to disable this Option?');
252 case 'CRM_Contact_BAO_ContactType':
253 $ret['content'] = ts('Are you sure you want to disable this Contact Type?');
256 case 'CRM_Core_BAO_OptionValue':
257 $label = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_OptionValue', $recordID, 'label');
258 $ret['content'] = ts('Are you sure you want to disable the \'%1\' option ?', [1 => $label]);
259 $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.');
262 case 'CRM_Contribute_BAO_ContributionRecur':
263 $recurDetails = CRM_Contribute_BAO_ContributionRecur
::getSubscriptionDetails($recordID);
264 $ret['content'] = ts('Are you sure you want to mark this recurring contribution as cancelled?');
265 $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>';
266 if ($recurDetails->membership_id
) {
267 $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>';
272 $ret['content'] = ts('Are you sure you want to disable this record?');
277 $ret = ['status' => 'error', 'content' => 'Error: Unknown entity type.', 'illegal' => TRUE];
279 CRM_Core_Page_AJAX
::returnJsonResponse($ret);
283 * Get a list of mappings.
285 * This appears to be only used by scheduled reminders.
287 public static function mappingList() {
288 if (empty($_GET['mappingID'])) {
289 CRM_Utils_JSON
::output(['status' => 'error', 'error_msg' => 'required params missing.']);
292 $mapping = CRM_Core_BAO_ActionSchedule
::getMapping($_GET['mappingID']);
293 $dateFieldLabels = $mapping ?
$mapping->getDateFields() : [];
295 // The UX here is quirky -- for "Activity" types, there's a simple drop "Recipients"
296 // dropdown which is always displayed. For other types, the "Recipients" drop down is
297 // conditional upon the weird isLimit ('Limit To / Also Include / Neither') dropdown.
298 $noThanksJustKidding = !$_GET['isLimit'];
299 if ($mapping instanceof CRM_Activity_ActionMapping ||
!$noThanksJustKidding) {
300 $entityRecipientLabels = $mapping ?
($mapping->getRecipientTypes() + CRM_Core_BAO_ActionSchedule
::getAdditionalRecipients()) : [];
303 $entityRecipientLabels = CRM_Core_BAO_ActionSchedule
::getAdditionalRecipients();
305 $recipientMapping = array_combine(array_keys($entityRecipientLabels), array_keys($entityRecipientLabels));
308 'sel4' => CRM_Utils_Array
::makeNonAssociative($dateFieldLabels),
309 'sel5' => CRM_Utils_Array
::makeNonAssociative($entityRecipientLabels),
310 'recipientMapping' => $recipientMapping,
313 CRM_Utils_JSON
::output($output);
317 * (Scheduled Reminders) Get the list of possible recipient filters.
319 * Ex: GET /civicrm/ajax/recipientListing?mappingID=contribpage&recipientType=
321 public static function recipientListing() {
322 $mappingID = filter_input(INPUT_GET
, 'mappingID', FILTER_VALIDATE_REGEXP
, [
324 'regexp' => '/^[a-zA-Z0-9_\-]+$/',
327 $recipientType = filter_input(INPUT_GET
, 'recipientType', FILTER_VALIDATE_REGEXP
, [
329 'regexp' => '/^[a-zA-Z0-9_\-]+$/',
333 CRM_Utils_JSON
::output([
334 'recipients' => CRM_Utils_Array
::makeNonAssociative(CRM_Core_BAO_ActionSchedule
::getRecipientListing($mappingID, $recipientType)),
339 * Outputs one branch in the tag tree
341 * Used by jstree to incrementally load tags
343 public static function getTagTree() {
344 $parent = CRM_Utils_Type
::escape(($_GET['parent_id'] ??
0), 'Integer');
345 $substring = CRM_Utils_Type
::escape(CRM_Utils_Array
::value('str', $_GET), 'String');
348 $whereClauses = ['is_tagset <> 1'];
349 $orderColumn = 'name';
351 // fetch all child tags in Array('parent_tag' => array('child_tag_1', 'child_tag_2', ...)) format
352 $childTagIDs = CRM_Core_BAO_Tag
::getChildTags($substring);
353 $parentIDs = array_keys($childTagIDs);
356 $whereClauses[] = "parent_id = $parent";
358 elseif ($substring) {
359 $whereClauses['substring'] = " name LIKE '%$substring%' ";
360 if (!empty($parentIDs)) {
361 $whereClauses['substring'] = sprintf(" %s OR id IN (%s) ", $whereClauses['substring'], implode(',', $parentIDs));
366 $whereClauses[] = "parent_id IS NULL";
369 $dao = CRM_Utils_SQL_Select
::from('civicrm_tag')
370 ->where($whereClauses)
372 ->orderBy($orderColumn)
375 while ($dao->fetch()) {
376 if (!empty($substring)) {
377 $result[] = $dao->id
;
378 if (!empty($childTagIDs[$dao->id
])) {
379 $result = array_merge($result, $childTagIDs[$dao->id
]);
383 $hasChildTags = !empty($childTagIDs[$dao->id
]);
384 $usedFor = (array) explode(',', $dao->used_for
);
387 'text' => $dao->name
,
389 'class' => 'crm-tag-item',
391 'children' => $hasChildTags,
393 'description' => (string) $dao->description
,
394 'is_selectable' => (bool) $dao->is_selectable
,
395 'is_reserved' => (bool) $dao->is_reserved
,
396 'used_for' => $usedFor,
397 'color' => $dao->color ?
$dao->color
: '#ffffff',
398 'usages' => civicrm_api3('EntityTag', 'getcount', [
399 'entity_table' => ['IN' => $usedFor],
400 'tag_id' => $dao->id
,
404 if ($dao->description ||
$dao->is_reserved
) {
405 $tag['li_attr']['title'] = ((string) $dao->description
) . ($dao->is_reserved ?
' (*' . ts('Reserved') . ')' : '');
407 if ($dao->is_reserved
) {
408 $tag['li_attr']['class'] = 'is-reserved';
411 $tag['a_attr']['style'] = "background-color: {$dao->color}; color: " . CRM_Utils_Color
::getContrast($dao->color
);
418 $result = array_values(array_unique($result));
421 if (!empty($_REQUEST['is_unit_test'])) {
425 CRM_Utils_JSON
::output($result);