| 1 | <?php |
| 2 | /* |
| 3 | +--------------------------------------------------------------------+ |
| 4 | | Copyright CiviCRM LLC. All rights reserved. | |
| 5 | | | |
| 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 | +--------------------------------------------------------------------+ |
| 10 | */ |
| 11 | |
| 12 | /** |
| 13 | * |
| 14 | * @package CRM |
| 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
| 16 | */ |
| 17 | |
| 18 | /** |
| 19 | * Create a page for displaying UF Groups. |
| 20 | * |
| 21 | * Heart of this class is the run method which checks |
| 22 | * for action type and then displays the appropriate |
| 23 | * page. |
| 24 | * |
| 25 | */ |
| 26 | class CRM_UF_Page_Group extends CRM_Core_Page { |
| 27 | |
| 28 | /** |
| 29 | * The action links that we need to display for the browse screen. |
| 30 | * |
| 31 | * @var array |
| 32 | */ |
| 33 | private static $_actionLinks = NULL; |
| 34 | |
| 35 | /** |
| 36 | * Get the action links for this page. |
| 37 | * |
| 38 | * @param |
| 39 | * |
| 40 | * @return array |
| 41 | */ |
| 42 | public static function &actionLinks() { |
| 43 | // check if variable _actionsLinks is populated |
| 44 | if (!self::$_actionLinks) { |
| 45 | // helper variable for nicer formatting |
| 46 | $copyExtra = ts('Are you sure you want to make a copy of this Profile?'); |
| 47 | self::$_actionLinks = [ |
| 48 | CRM_Core_Action::BROWSE => [ |
| 49 | 'name' => ts('Fields'), |
| 50 | 'url' => 'civicrm/admin/uf/group/field', |
| 51 | 'qs' => 'reset=1&action=browse&gid=%%id%%', |
| 52 | 'title' => ts('View and Edit Fields'), |
| 53 | ], |
| 54 | CRM_Core_Action::UPDATE => [ |
| 55 | 'name' => ts('Settings'), |
| 56 | 'url' => 'civicrm/admin/uf/group/update', |
| 57 | 'qs' => 'action=update&id=%%id%%&context=group', |
| 58 | 'title' => ts('Edit CiviCRM Profile Group'), |
| 59 | ], |
| 60 | CRM_Core_Action::PREVIEW => [ |
| 61 | 'name' => ts('Preview'), |
| 62 | 'url' => 'civicrm/admin/uf/group', |
| 63 | 'qs' => 'action=preview&id=%%id%%&field=0&context=group', |
| 64 | 'title' => ts('Edit CiviCRM Profile Group'), |
| 65 | ], |
| 66 | CRM_Core_Action::ADD => [ |
| 67 | 'name' => ts('Use - Create Mode'), |
| 68 | 'url' => 'civicrm/profile/create', |
| 69 | 'qs' => 'gid=%%id%%&reset=1', |
| 70 | 'title' => ts('Use - Create Mode'), |
| 71 | 'fe' => TRUE, |
| 72 | ], |
| 73 | CRM_Core_Action::ADVANCED => [ |
| 74 | 'name' => ts('Use - Edit Mode'), |
| 75 | 'url' => 'civicrm/profile/edit', |
| 76 | 'qs' => 'gid=%%id%%&reset=1', |
| 77 | 'title' => ts('Use - Edit Mode'), |
| 78 | 'fe' => TRUE, |
| 79 | ], |
| 80 | CRM_Core_Action::BASIC => [ |
| 81 | 'name' => ts('Use - Listings Mode'), |
| 82 | 'url' => 'civicrm/profile', |
| 83 | 'qs' => 'gid=%%id%%&reset=1', |
| 84 | 'title' => ts('Use - Listings Mode'), |
| 85 | 'fe' => TRUE, |
| 86 | ], |
| 87 | CRM_Core_Action::DISABLE => [ |
| 88 | 'name' => ts('Disable'), |
| 89 | 'ref' => 'crm-enable-disable', |
| 90 | 'title' => ts('Disable CiviCRM Profile Group'), |
| 91 | ], |
| 92 | CRM_Core_Action::ENABLE => [ |
| 93 | 'name' => ts('Enable'), |
| 94 | 'ref' => 'crm-enable-disable', |
| 95 | 'title' => ts('Enable CiviCRM Profile Group'), |
| 96 | ], |
| 97 | CRM_Core_Action::DELETE => [ |
| 98 | 'name' => ts('Delete'), |
| 99 | 'url' => 'civicrm/admin/uf/group', |
| 100 | 'qs' => 'action=delete&id=%%id%%', |
| 101 | 'title' => ts('Delete CiviCRM Profile Group'), |
| 102 | ], |
| 103 | CRM_Core_Action::COPY => [ |
| 104 | 'name' => ts('Copy'), |
| 105 | 'url' => 'civicrm/admin/uf/group', |
| 106 | 'qs' => 'action=copy&gid=%%id%%', |
| 107 | 'title' => ts('Make a Copy of CiviCRM Profile Group'), |
| 108 | 'extra' => 'onclick = "return confirm(\'' . $copyExtra . '\');"', |
| 109 | ], |
| 110 | ]; |
| 111 | $allowRemoteSubmit = Civi::settings()->get('remote_profile_submissions'); |
| 112 | if ($allowRemoteSubmit) { |
| 113 | self::$_actionLinks[CRM_Core_Action::PROFILE] = [ |
| 114 | 'name' => ts('HTML Form Snippet'), |
| 115 | 'url' => 'civicrm/admin/uf/group', |
| 116 | 'qs' => 'action=profile&gid=%%id%%', |
| 117 | 'title' => ts('HTML Form Snippet for this Profile'), |
| 118 | ]; |
| 119 | } |
| 120 | } |
| 121 | return self::$_actionLinks; |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Run the page. |
| 126 | * |
| 127 | * This method is called after the page is created. It checks for the |
| 128 | * type of action and executes that action. |
| 129 | * Finally it calls the parent's run method. |
| 130 | */ |
| 131 | public function run() { |
| 132 | // get the requested action |
| 133 | $action = CRM_Utils_Request::retrieve('action', 'String', |
| 134 | $this, FALSE, |
| 135 | // default to 'browse' |
| 136 | 'browse' |
| 137 | ); |
| 138 | |
| 139 | // assign vars to templates |
| 140 | $this->assign('action', $action); |
| 141 | $this->assign('selectedChild', CRM_Utils_Request::retrieve('selectedChild', 'Alphanumeric', $this)); |
| 142 | $id = CRM_Utils_Request::retrieve('id', 'Positive', |
| 143 | $this, FALSE, 0 |
| 144 | ); |
| 145 | |
| 146 | //set the context and then start w/ action. |
| 147 | $this->setContext($id, $action); |
| 148 | |
| 149 | // what action to take ? |
| 150 | if ($action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::DELETE | CRM_Core_Action::DISABLE)) { |
| 151 | $this->edit($id, $action); |
| 152 | } |
| 153 | else { |
| 154 | // if action is enable or disable do the needful. |
| 155 | if ($action & CRM_Core_Action::ENABLE) { |
| 156 | CRM_Core_BAO_UFGroup::setIsActive($id, 1); |
| 157 | |
| 158 | // update cms integration with registration / my account |
| 159 | CRM_Utils_System::updateCategories(); |
| 160 | } |
| 161 | elseif ($action & CRM_Core_Action::PROFILE) { |
| 162 | $this->profile(); |
| 163 | CRM_Utils_System::setTitle(ts('%1 - HTML Form Snippet', [1 => $this->_title])); |
| 164 | } |
| 165 | elseif ($action & CRM_Core_Action::PREVIEW) { |
| 166 | $this->preview($id, $action); |
| 167 | } |
| 168 | elseif ($action & CRM_Core_Action::COPY) { |
| 169 | $this->copy(); |
| 170 | } |
| 171 | // finally browse the uf groups |
| 172 | $this->browse(); |
| 173 | } |
| 174 | // parent run |
| 175 | return parent::run(); |
| 176 | } |
| 177 | |
| 178 | /** |
| 179 | * make a copy of a profile, including |
| 180 | * all the fields in the profile |
| 181 | * |
| 182 | * @return void |
| 183 | */ |
| 184 | public function copy() { |
| 185 | $gid = CRM_Utils_Request::retrieve('gid', 'Positive', |
| 186 | $this, TRUE, 0, 'GET' |
| 187 | ); |
| 188 | |
| 189 | CRM_Core_BAO_UFGroup::copy($gid); |
| 190 | CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/uf/group', 'reset=1')); |
| 191 | } |
| 192 | |
| 193 | /** |
| 194 | * for profile mode (standalone html form ) for uf group |
| 195 | * |
| 196 | * @return void |
| 197 | */ |
| 198 | public function profile() { |
| 199 | $config = CRM_Core_Config::singleton(); |
| 200 | |
| 201 | // reassign resource base to be the full url, CRM-4660 |
| 202 | $config->resourceBase = $config->userFrameworkResourceURL; |
| 203 | $config->useFrameworkRelativeBase = $config->userFrameworkBaseURL; |
| 204 | |
| 205 | $gid = CRM_Utils_Request::retrieve('gid', 'Positive', |
| 206 | $this, FALSE, 0, 'GET' |
| 207 | ); |
| 208 | $controller = new CRM_Core_Controller_Simple('CRM_Profile_Form_Edit', ts('Create'), CRM_Core_Action::ADD, |
| 209 | FALSE, FALSE, TRUE |
| 210 | ); |
| 211 | $controller->reset(); |
| 212 | $controller->process(); |
| 213 | $controller->set('gid', $gid); |
| 214 | $controller->setEmbedded(TRUE); |
| 215 | $controller->run(); |
| 216 | $template = CRM_Core_Smarty::singleton(); |
| 217 | $template->assign('gid', $gid); |
| 218 | $template->assign('tplFile', 'CRM/Profile/Form/Edit.tpl'); |
| 219 | $profile = trim($template->fetch('CRM/Form/default.tpl')); |
| 220 | |
| 221 | // not sure how to circumvent our own navigation system to generate the right form url |
| 222 | $urlReplaceWith = 'civicrm/profile/create&gid=' . $gid . '&reset=1'; |
| 223 | if ($config->userSystem->is_drupal && $config->cleanURL) { |
| 224 | $urlReplaceWith = 'civicrm/profile/create?gid=' . $gid . '&reset=1'; |
| 225 | } |
| 226 | $profile = str_replace('civicrm/admin/uf/group', $urlReplaceWith, $profile); |
| 227 | |
| 228 | // FIXME: (CRM-3587) hack to make standalone profile work |
| 229 | // in wordpress and joomla without administrator login |
| 230 | if ($config->userFramework == 'Joomla') { |
| 231 | $profile = str_replace('/administrator/', '/index.php', $profile); |
| 232 | } |
| 233 | elseif ($config->userFramework == 'WordPress') { |
| 234 | //@todo remove this part when it is OK to deprecate CIVICRM_UF_WP_BASEPAGE-CRM-15933 |
| 235 | if (defined('CIVICRM_UF_WP_BASEPAGE')) { |
| 236 | $wpbase = CIVICRM_UF_WP_BASEPAGE; |
| 237 | } |
| 238 | elseif (!empty($config->wpBasePage)) { |
| 239 | $wpbase = $config->wpBasePage; |
| 240 | } |
| 241 | else { |
| 242 | $wpbase = 'index.php'; |
| 243 | } |
| 244 | $profile = str_replace('/wp-admin/admin.php', '/' . $wpbase . '/', $profile); |
| 245 | } |
| 246 | |
| 247 | // add header files |
| 248 | CRM_Core_Resources::singleton()->addCoreResources('html-header'); |
| 249 | $profile = CRM_Core_Region::instance('html-header')->render('', FALSE) . $profile; |
| 250 | |
| 251 | $this->assign('profile', htmlentities($profile, ENT_NOQUOTES, 'UTF-8')); |
| 252 | //get the title of uf group |
| 253 | if ($gid) { |
| 254 | $title = CRM_Core_BAO_UFGroup::getTitle($gid); |
| 255 | $this->_title = $title; |
| 256 | } |
| 257 | else { |
| 258 | $title = 'Profile Form'; |
| 259 | } |
| 260 | |
| 261 | $this->assign('title', $title); |
| 262 | $this->assign('action', CRM_Core_Action::PROFILE); |
| 263 | $this->assign('isForm', 0); |
| 264 | } |
| 265 | |
| 266 | /** |
| 267 | * Edit uf group. |
| 268 | * |
| 269 | * @param int $id |
| 270 | * Uf group id. |
| 271 | * @param string $action |
| 272 | * The action to be invoked. |
| 273 | * |
| 274 | * @return void |
| 275 | */ |
| 276 | public function edit($id, $action) { |
| 277 | // create a simple controller for editing uf data |
| 278 | $controller = new CRM_Core_Controller_Simple('CRM_UF_Form_Group', ts('CiviCRM Profile Group'), $action); |
| 279 | $this->setContext($id, $action); |
| 280 | $controller->set('id', $id); |
| 281 | $controller->setEmbedded(TRUE); |
| 282 | $controller->process(); |
| 283 | $controller->run(); |
| 284 | } |
| 285 | |
| 286 | /** |
| 287 | * Browse all uf data groups. |
| 288 | * |
| 289 | * @param |
| 290 | * |
| 291 | * @return void |
| 292 | */ |
| 293 | public function browse($action = NULL) { |
| 294 | $ufGroup = []; |
| 295 | $allUFGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup(); |
| 296 | if (empty($allUFGroups)) { |
| 297 | return; |
| 298 | } |
| 299 | |
| 300 | $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id'); |
| 301 | CRM_Utils_Hook::aclGroup(CRM_Core_Permission::ADMIN, NULL, 'civicrm_uf_group', $ufGroups, $allUFGroups); |
| 302 | |
| 303 | foreach ($allUFGroups as $id => $value) { |
| 304 | $ufGroup[$id] = []; |
| 305 | $ufGroup[$id]['id'] = $id; |
| 306 | $ufGroup[$id]['title'] = $value['title']; |
| 307 | $ufGroup[$id]['frontend_title'] = $value['frontend_title']; |
| 308 | $ufGroup[$id]['created_id'] = $value['created_id']; |
| 309 | $ufGroup[$id]['created_by'] = CRM_Contact_BAO_Contact::displayName($value['created_id']); |
| 310 | $ufGroup[$id]['description'] = $value['description']; |
| 311 | $ufGroup[$id]['is_active'] = $value['is_active']; |
| 312 | $ufGroup[$id]['group_type'] = $value['group_type']; |
| 313 | $ufGroup[$id]['is_reserved'] = $value['is_reserved']; |
| 314 | |
| 315 | // form all action links |
| 316 | $action = array_sum(array_keys(self::actionLinks())); |
| 317 | |
| 318 | // update enable/disable links depending on uf_group properties. |
| 319 | if ($value['is_active']) { |
| 320 | $action -= CRM_Core_Action::ENABLE; |
| 321 | } |
| 322 | else { |
| 323 | $action -= CRM_Core_Action::DISABLE; |
| 324 | } |
| 325 | |
| 326 | // drop certain actions if the profile is reserved |
| 327 | if ($value['is_reserved']) { |
| 328 | $action -= CRM_Core_Action::UPDATE; |
| 329 | $action -= CRM_Core_Action::DISABLE; |
| 330 | $action -= CRM_Core_Action::DELETE; |
| 331 | } |
| 332 | |
| 333 | $groupTypes = self::extractGroupTypes($value['group_type']); |
| 334 | |
| 335 | // drop Create, Edit and View mode links if profile group_type is one of the following: |
| 336 | // Contribution, Membership, Activity, Participant, Case, Grant |
| 337 | $isMixedProfile = CRM_Core_BAO_UFField::checkProfileType($id); |
| 338 | if ($isMixedProfile) { |
| 339 | $action -= CRM_Core_Action::ADD; |
| 340 | $action -= CRM_Core_Action::ADVANCED; |
| 341 | $action -= CRM_Core_Action::BASIC; |
| 342 | |
| 343 | //CRM-21004 |
| 344 | if (array_key_exists(CRM_Core_Action::PROFILE, self::$_actionLinks)) { |
| 345 | $action -= CRM_Core_Action::PROFILE; |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | $ufGroup[$id]['group_type'] = self::formatGroupTypes($groupTypes); |
| 350 | |
| 351 | $ufGroup[$id]['action'] = CRM_Core_Action::formLink(self::actionLinks(), $action, |
| 352 | ['id' => $id], |
| 353 | ts('more'), |
| 354 | FALSE, |
| 355 | 'ufGroup.row.actions', |
| 356 | 'UFGroup', |
| 357 | $id |
| 358 | ); |
| 359 | //get the "Used For" from uf_join |
| 360 | $ufGroup[$id]['module'] = implode(', ', CRM_Core_BAO_UFGroup::getUFJoinRecord($id, TRUE)); |
| 361 | } |
| 362 | |
| 363 | $this->assign('rows', $ufGroup); |
| 364 | } |
| 365 | |
| 366 | /** |
| 367 | * for preview mode for ufoup. |
| 368 | * |
| 369 | * @param int $id |
| 370 | * Uf group id. |
| 371 | * |
| 372 | * @param int $action |
| 373 | */ |
| 374 | public function preview($id, $action) { |
| 375 | $controller = new CRM_Core_Controller_Simple('CRM_UF_Form_Preview', ts('CiviCRM Profile Group Preview'), NULL); |
| 376 | $controller->set('id', $id); |
| 377 | $controller->setEmbedded(TRUE); |
| 378 | $controller->process(); |
| 379 | $controller->run(); |
| 380 | } |
| 381 | |
| 382 | /** |
| 383 | * @param int $id |
| 384 | * @param $action |
| 385 | */ |
| 386 | public function setContext($id, $action) { |
| 387 | $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this); |
| 388 | |
| 389 | //we need to differentiate context for update and preview profile. |
| 390 | if (!$context && !($action & (CRM_Core_Action::UPDATE | CRM_Core_Action::PREVIEW))) { |
| 391 | $context = 'group'; |
| 392 | } |
| 393 | |
| 394 | if ($context == 'field') { |
| 395 | $url = CRM_Utils_System::url('civicrm/admin/uf/group/field', "reset=1&action=browse&gid={$id}"); |
| 396 | } |
| 397 | else { |
| 398 | $url = CRM_Utils_System::url('civicrm/admin/uf/group', 'reset=1&action=browse'); |
| 399 | } |
| 400 | |
| 401 | $session = CRM_Core_Session::singleton(); |
| 402 | $session->pushUserContext($url); |
| 403 | } |
| 404 | |
| 405 | /** |
| 406 | * @param $groupType |
| 407 | * |
| 408 | * @return array |
| 409 | */ |
| 410 | public static function extractGroupTypes($groupType) { |
| 411 | $returnGroupTypes = []; |
| 412 | if (!$groupType) { |
| 413 | return $returnGroupTypes; |
| 414 | } |
| 415 | |
| 416 | $groupTypeParts = explode(CRM_Core_DAO::VALUE_SEPARATOR, $groupType); |
| 417 | foreach (explode(',', $groupTypeParts[0]) as $type) { |
| 418 | $returnGroupTypes[$type] = $type; |
| 419 | } |
| 420 | |
| 421 | if (!empty($groupTypeParts[1])) { |
| 422 | foreach (explode(',', $groupTypeParts[1]) as $typeValue) { |
| 423 | $groupTypeValues = $valueLabels = []; |
| 424 | $valueParts = explode(':', $typeValue); |
| 425 | $typeName = NULL; |
| 426 | switch ($valueParts[0]) { |
| 427 | case 'ContributionType': |
| 428 | $typeName = 'Contribution'; |
| 429 | $valueLabels = CRM_Contribute_PseudoConstant::financialType(); |
| 430 | break; |
| 431 | |
| 432 | case 'ParticipantRole': |
| 433 | $typeName = 'Participant'; |
| 434 | $valueLabels = CRM_Event_PseudoConstant::participantRole(); |
| 435 | break; |
| 436 | |
| 437 | case 'ParticipantEventName': |
| 438 | $typeName = 'Participant'; |
| 439 | $valueLabels = CRM_Event_PseudoConstant::event(); |
| 440 | break; |
| 441 | |
| 442 | case 'ParticipantEventType': |
| 443 | $typeName = 'Participant'; |
| 444 | $valueLabels = CRM_Event_PseudoConstant::eventType(); |
| 445 | break; |
| 446 | |
| 447 | case 'MembershipType': |
| 448 | $typeName = 'Membership'; |
| 449 | $valueLabels = CRM_Member_PseudoConstant::membershipType(); |
| 450 | break; |
| 451 | |
| 452 | case 'ActivityType': |
| 453 | $typeName = 'Activity'; |
| 454 | $valueLabels = CRM_Core_PseudoConstant::ActivityType(TRUE, TRUE, FALSE, 'label', TRUE); |
| 455 | break; |
| 456 | |
| 457 | case 'CaseType': |
| 458 | $typeName = 'Case'; |
| 459 | $valueLabels = CRM_Case_PseudoConstant::caseType(); |
| 460 | break; |
| 461 | } |
| 462 | |
| 463 | foreach ($valueParts as $val) { |
| 464 | if (CRM_Utils_Rule::integer($val)) { |
| 465 | $groupTypeValues[$val] = $valueLabels[$val] ?? NULL; |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | if (!is_array($returnGroupTypes[$typeName])) { |
| 470 | $returnGroupTypes[$typeName] = []; |
| 471 | } |
| 472 | $returnGroupTypes[$typeName][$valueParts[0]] = $groupTypeValues; |
| 473 | } |
| 474 | } |
| 475 | return $returnGroupTypes; |
| 476 | } |
| 477 | |
| 478 | /** |
| 479 | * Format 'group_type' field for display |
| 480 | * |
| 481 | * @param array $groupTypes |
| 482 | * output from self::extractGroupTypes |
| 483 | * @return string |
| 484 | */ |
| 485 | public static function formatGroupTypes($groupTypes) { |
| 486 | $groupTypesString = ''; |
| 487 | if (!empty($groupTypes)) { |
| 488 | $groupTypesStrings = []; |
| 489 | foreach ($groupTypes as $groupType => $typeValues) { |
| 490 | if (is_array($typeValues)) { |
| 491 | if ($groupType == 'Participant') { |
| 492 | foreach ($typeValues as $subType => $subTypeValues) { |
| 493 | $groupTypesStrings[] = $subType . '::' . implode(': ', $subTypeValues); |
| 494 | } |
| 495 | } |
| 496 | else { |
| 497 | $groupTypesStrings[] = $groupType . '::' . implode(': ', current($typeValues)); |
| 498 | } |
| 499 | } |
| 500 | else { |
| 501 | $groupTypesStrings[] = $groupType; |
| 502 | } |
| 503 | } |
| 504 | $groupTypesString = implode(', ', $groupTypesStrings); |
| 505 | } |
| 506 | return $groupTypesString; |
| 507 | } |
| 508 | |
| 509 | } |