Merge pull request #9607 from yashodha/update-year
[civicrm-core.git] / CRM / Custom / Form / Group.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
0f03f337 6 | Copyright CiviCRM LLC (c) 2004-2017 |
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
0f03f337 31 * @copyright CiviCRM LLC (c) 2004-2017
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * form to process actions on the set aspect of Custom Data
38 */
39class CRM_Custom_Form_Group extends CRM_Core_Form {
40
41 /**
fe482240 42 * The set id saved to the session for an update.
6a488035
TO
43 *
44 * @var int
6a488035
TO
45 */
46 protected $_id;
47
48 /**
fe482240 49 * set is empty or not.
6a488035
TO
50 *
51 * @var bool
6a488035
TO
52 */
53 protected $_isGroupEmpty = TRUE;
54
55 /**
fe482240 56 * Array of existing subtypes set for a custom set.
6a488035
TO
57 *
58 * @var array
6a488035
TO
59 */
60 protected $_subtypes = array();
61
6a488035 62 /**
fe482240 63 * Set variables up before form is built.
6a488035 64 *
6a488035
TO
65 *
66 * @return void
6a488035
TO
67 */
68 public function preProcess() {
69 // current set id
70 $this->_id = $this->get('id');
71
148c89c8 72 if ($this->_id && $isReserved = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_id, 'is_reserved', 'id')) {
e89941dc 73 CRM_Core_Error::fatal("You cannot edit the settings of a reserved custom field-set.");
d06700a7 74 }
6a488035
TO
75 // setting title for html page
76 if ($this->_action == CRM_Core_Action::UPDATE) {
77 $title = CRM_Core_BAO_CustomGroup::getTitle($this->_id);
78 CRM_Utils_System::setTitle(ts('Edit %1', array(1 => $title)));
79 }
80 elseif ($this->_action == CRM_Core_Action::VIEW) {
81 $title = CRM_Core_BAO_CustomGroup::getTitle($this->_id);
82 CRM_Utils_System::setTitle(ts('Preview %1', array(1 => $title)));
83 }
84 else {
85 CRM_Utils_System::setTitle(ts('New Custom Field Set'));
86 }
87
88 if (isset($this->_id)) {
89 $params = array('id' => $this->_id);
90 CRM_Core_BAO_CustomGroup::retrieve($params, $this->_defaults);
91
92 $subExtends = CRM_Utils_Array::value('extends_entity_column_value', $this->_defaults);
93 if (!empty($subExtends)) {
94 $this->_subtypes = explode(CRM_Core_DAO::VALUE_SEPARATOR, substr($subExtends, 1, -1));
95 }
96 }
97 }
98
99 /**
fe482240 100 * Global form rule.
6a488035 101 *
c4ca4892
TO
102 * @param array $fields
103 * The input form values.
104 * @param array $files
105 * The uploaded files if any.
dd244018
EM
106 * @param $self
107 *
6a488035 108 *
72b3a70c
CW
109 * @return bool|array
110 * true if no errors, else array of errors
6a488035 111 */
00be9182 112 public static function formRule($fields, $files, $self) {
6a488035
TO
113 $errors = array();
114
115 //validate group title as well as name.
353ffa53
TO
116 $title = $fields['title'];
117 $name = CRM_Utils_String::munge($title, '_', 64);
118 $query = 'select count(*) from civicrm_custom_group where ( name like %1 OR title like %2 ) and id != %3';
e8646905 119 $grpCnt = CRM_Core_DAO::singleValueQuery($query, array(
353ffa53
TO
120 1 => array($name, 'String'),
121 2 => array($title, 'String'),
122 3 => array((int) $self->_id, 'Integer'),
123 ));
6a488035
TO
124 if ($grpCnt) {
125 $errors['title'] = ts('Custom group \'%1\' already exists in Database.', array(1 => $title));
126 }
127
a7488080 128 if (!empty($fields['extends'][1])) {
6a488035
TO
129 if (in_array('', $fields['extends'][1]) && count($fields['extends'][1]) > 1) {
130 $errors['extends'] = ts("Cannot combine other option with 'Any'.");
131 }
132 }
133
134 if (empty($fields['extends'][0])) {
135 $errors['extends'] = ts("You need to select the type of record that this set of custom fields is applicable for.");
136 }
137
138 $extends = array('Activity', 'Relationship', 'Group', 'Contribution', 'Membership', 'Event', 'Participant');
139 if (in_array($fields['extends'][0], $extends) && $fields['style'] == 'Tab') {
140 $errors['style'] = ts("Display Style should be Inline for this Class");
141 $self->assign('showStyle', TRUE);
142 }
143
a7488080 144 if (!empty($fields['is_multiple'])) {
e8646905 145 $self->assign('showMultiple', TRUE);
6a488035
TO
146 }
147
b05a0fb6 148 if (empty($fields['is_multiple']) && $fields['style'] == 'Tab with table') {
e232751e 149 $errors['style'] = ts("Display Style 'Tab with table' is only supported for multiple-record custom field sets.");
b05a0fb6
PJ
150 }
151
6a488035
TO
152 //checks the given custom set doesnot start with digit
153 $title = $fields['title'];
154 if (!empty($title)) {
155 // gives the ascii value
156 $asciiValue = ord($title{0});
157 if ($asciiValue >= 48 && $asciiValue <= 57) {
5ab78070 158 $errors['title'] = ts("Name cannot not start with a digit");
6a488035
TO
159 }
160 }
161
162 return empty($errors) ? TRUE : $errors;
163 }
164
165 /**
dc195289 166 * add the rules (mainly global rules) for form.
6a488035
TO
167 * All local rules are added near the element
168 *
6a488035
TO
169 *
170 * @return void
6a488035
TO
171 * @see valid_date
172 */
00be9182 173 public function addRules() {
6a488035
TO
174 $this->addFormRule(array('CRM_Custom_Form_Group', 'formRule'), $this);
175 }
176
177 /**
fe482240 178 * Build the form object.
6a488035 179 *
6a488035
TO
180 *
181 * @return void
6a488035
TO
182 */
183 public function buildQuickForm() {
184 $this->applyFilter('__ALL__', 'trim');
185
186 $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_CustomGroup');
187
188 //title
189 $this->add('text', 'title', ts('Set Name'), $attributes['title'], TRUE);
190
191 //Fix for code alignment, CRM-3058
192 $contactTypes = array('Contact', 'Individual', 'Household', 'Organization');
193 $this->assign('contactTypes', json_encode($contactTypes));
194
b6b6d6cc 195 $sel1 = array("" => ts("- select -")) + CRM_Core_SelectValues::customGroupExtends();
353ffa53 196 $sel2 = array();
6a488035
TO
197 $activityType = CRM_Core_PseudoConstant::activityType(FALSE, TRUE, FALSE, 'label', TRUE);
198
353ffa53
TO
199 $eventType = CRM_Core_OptionGroup::values('event_type');
200 $grantType = CRM_Core_OptionGroup::values('grant_type');
201 $campaignTypes = CRM_Campaign_PseudoConstant::campaignType();
202 $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypes(FALSE);
6a488035 203 $participantRole = CRM_Core_OptionGroup::values('participant_role');
6a488035
TO
204
205 ksort($sel1);
206 asort($activityType);
207 asort($eventType);
208 asort($grantType);
209 asort($membershipType);
210 asort($participantRole);
6a488035
TO
211
212 $sel2['Event'] = $eventType;
213 $sel2['Grant'] = $grantType;
214 $sel2['Activity'] = $activityType;
215 $sel2['Campaign'] = $campaignTypes;
216 $sel2['Membership'] = $membershipType;
217 $sel2['ParticipantRole'] = $participantRole;
218 $sel2['ParticipantEventName'] = CRM_Event_PseudoConstant::event(NULL, FALSE, "( is_template IS NULL OR is_template != 1 )");
219 $sel2['ParticipantEventType'] = $eventType;
879db7b0 220 $sel2['Contribution'] = CRM_Contribute_PseudoConstant::financialType();
a9c1ff43 221 $sel2['Relationship'] = self::getRelationshipTypes();
6a488035
TO
222
223 $sel2['Individual'] = CRM_Contact_BAO_ContactType::subTypePairs('Individual', FALSE, NULL);
224 $sel2['Household'] = CRM_Contact_BAO_ContactType::subTypePairs('Household', FALSE, NULL);
225 $sel2['Organization'] = CRM_Contact_BAO_ContactType::subTypePairs('Organization', FALSE, NULL);
226
227 CRM_Core_BAO_CustomGroup::getExtendedObjectTypes($sel2);
228
229 foreach ($sel2 as $main => $sub) {
230 if (!empty($sel2[$main])) {
a9c1ff43
TO
231 $sel2[$main] = array(
232 '' => ts("- Any -"),
233 ) + $sel2[$main];
6a488035
TO
234 }
235 }
236
237 $cSubTypes = CRM_Core_Component::contactSubTypes();
238
239 if (!empty($cSubTypes)) {
240 $contactSubTypes = array();
241 foreach ($cSubTypes as $key => $value) {
242 $contactSubTypes[$key] = $key;
243 }
244 $sel2['Contact'] = array(
b6b6d6cc 245 "" => ("- Any -"),
3bdca100 246 ) + $contactSubTypes;
6a488035
TO
247 }
248 else {
249 if (!isset($this->_id)) {
250 $formName = 'document.forms.' . $this->_name;
251
252 $js = "<script type='text/javascript'>\n";
253 $js .= "{$formName}['extends_1'].style.display = 'none';\n";
254 $js .= "</script>";
255 $this->assign('initHideBlocks', $js);
256 }
257 }
258
259 $sel = &$this->add('hierselect',
260 'extends',
261 ts('Used For'),
262 array(
6a488035 263 'name' => 'extends[0]',
21dfd5f5 264 'style' => 'vertical-align: top;',
6a488035
TO
265 ),
266 TRUE
267 );
268 $sel->setOptions(array($sel1, $sel2));
269 if (is_a($sel->_elements[1], 'HTML_QuickForm_select')) {
270 // make second selector a multi-select -
271 $sel->_elements[1]->setMultiple(TRUE);
272 $sel->_elements[1]->setSize(5);
273 }
274 if ($this->_action == CRM_Core_Action::UPDATE) {
275 $subName = CRM_Utils_Array::value('extends_entity_column_id', $this->_defaults);
276 if ($this->_defaults['extends'] == 'Participant') {
277 if ($subName == 1) {
278 $this->_defaults['extends'] = 'ParticipantRole';
279 }
280 elseif ($subName == 2) {
281 $this->_defaults['extends'] = 'ParticipantEventName';
282 }
283 elseif ($subName == 3) {
284 $this->_defaults['extends'] = 'ParticipantEventType';
285 }
286 }
287
288 //allow to edit settings if custom set is empty CRM-5258
289 $this->_isGroupEmpty = CRM_Core_BAO_CustomGroup::isGroupEmpty($this->_id);
290 if (!$this->_isGroupEmpty) {
291 if (!empty($this->_subtypes)) {
292 // we want to allow adding / updating subtypes for this case,
293 // and therefore freeze the first selector only.
294 $sel->_elements[0]->freeze();
295 }
296 else {
297 // freeze both the selectors
298 $sel->freeze();
299 }
300 }
301 $this->assign('isCustomGroupEmpty', $this->_isGroupEmpty);
302 $this->assign('gid', $this->_id);
303 }
304 $this->assign('defaultSubtypes', json_encode($this->_subtypes));
305
306 // help text
5d51a2f9
CW
307 $this->add('wysiwyg', 'help_pre', ts('Pre-form Help'), $attributes['help_pre']);
308 $this->add('wysiwyg', 'help_post', ts('Post-form Help'), $attributes['help_post']);
6a488035
TO
309
310 // weight
311 $this->add('text', 'weight', ts('Order'), $attributes['weight'], TRUE);
312 $this->addRule('weight', ts('is a numeric field'), 'numeric');
313
314 // display style
315 $this->add('select', 'style', ts('Display Style'), CRM_Core_SelectValues::customGroupStyle());
316
317 // is this set collapsed or expanded ?
cbaf6620 318 $this->addElement('advcheckbox', 'collapse_display', ts('Collapse this set on initial display'));
6a488035
TO
319
320 // is this set collapsed or expanded ? in advanced search
cbaf6620 321 $this->addElement('advcheckbox', 'collapse_adv_display', ts('Collapse this set in Advanced Search'));
6a488035
TO
322
323 // is this set active ?
cbaf6620 324 $this->addElement('advcheckbox', 'is_active', ts('Is this Custom Data Set active?'));
6a488035
TO
325
326 // does this set have multiple record?
cbaf6620 327 $multiple = $this->addElement('advcheckbox', 'is_multiple',
d9aa50a7 328 ts('Does this Custom Field Set allow multiple records?'), NULL);
6a488035
TO
329
330 // $min_multiple = $this->add('text', 'min_multiple', ts('Minimum number of multiple records'), $attributes['min_multiple'] );
331 // $this->addRule('min_multiple', ts('is a numeric field') , 'numeric');
332
333 $max_multiple = $this->add('text', 'max_multiple', ts('Maximum number of multiple records'), $attributes['max_multiple']);
334 $this->addRule('max_multiple', ts('is a numeric field'), 'numeric');
335
336 //allow to edit settings if custom set is empty CRM-5258
337 $this->assign('isGroupEmpty', $this->_isGroupEmpty);
338 if (!$this->_isGroupEmpty) {
339 $multiple->freeze();
340 //$min_multiple->freeze();
341 $max_multiple->freeze();
342 }
343
344 $this->assign('showStyle', FALSE);
345 $this->assign('showMultiple', FALSE);
346 $buttons = array(
347 array(
348 'type' => 'next',
349 'name' => ts('Save'),
350 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
351 'isDefault' => TRUE,
352 ),
353 array(
354 'type' => 'cancel',
355 'name' => ts('Cancel'),
356 ),
357 );
358 if (!$this->_isGroupEmpty && !empty($this->_subtypes)) {
b01812e5 359 $buttons[0]['class'] = 'crm-warnDataLoss';
6a488035
TO
360 }
361 $this->addButtons($buttons);
362
b6b6d6cc 363 // TODO: Is this condition ever true? Can this code be removed?
6a488035
TO
364 if ($this->_action & CRM_Core_Action::VIEW) {
365 $this->freeze();
366 $this->addElement('button', 'done', ts('Done'), array('onclick' => "location.href='civicrm/admin/custom/group?reset=1&action=browse'"));
367 }
368 }
369
370 /**
c490a46a 371 * Set default values for the form. Note that in edit/view mode
6a488035
TO
372 * the default values are retrieved from the database
373 *
6a488035 374 *
a6c01b45
CW
375 * @return array
376 * array of default values
6a488035 377 */
00be9182 378 public function setDefaultValues() {
6a488035
TO
379 $defaults = &$this->_defaults;
380 $this->assign('showMaxMultiple', TRUE);
381 if ($this->_action == CRM_Core_Action::ADD) {
382 $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_CustomGroup');
383
384 $defaults['is_multiple'] = $defaults['min_multiple'] = 0;
385 $defaults['is_active'] = $defaults['collapse_display'] = 1;
386 $defaults['style'] = 'Inline';
387 }
a7488080 388 elseif (empty($defaults['max_multiple']) && !$this->_isGroupEmpty) {
6a488035
TO
389 $this->assign('showMaxMultiple', FALSE);
390 }
391
b05a0fb6 392 if (($this->_action & CRM_Core_Action::UPDATE) && !empty($defaults['is_multiple'])) {
5a205b89
PJ
393 $defaults['collapse_display'] = 0;
394 }
395
6a488035
TO
396 if (isset($defaults['extends'])) {
397 $extends = $defaults['extends'];
398 unset($defaults['extends']);
399
400 $defaults['extends'][0] = $extends;
401
402 if (!empty($this->_subtypes)) {
403 $defaults['extends'][1] = $this->_subtypes;
404 }
405 else {
406 $defaults['extends'][1] = array(0 => '');
407 }
408
6a488035
TO
409 if ($extends == 'Relationship' && !empty($this->_subtypes)) {
410 $relationshipDefaults = array();
411 foreach ($defaults['extends'][1] as $donCare => $rel_type_id) {
412 $relationshipDefaults[] = $rel_type_id;
413 }
414
415 $defaults['extends'][1] = $relationshipDefaults;
416 }
417 }
418
419 return $defaults;
420 }
421
422 /**
fe482240 423 * Process the form.
6a488035 424 *
6a488035
TO
425 *
426 * @return void
6a488035
TO
427 */
428 public function postProcess() {
429 // get the submitted form values.
430 $params = $this->controller->exportValues('Group');
431 $params['overrideFKConstraint'] = 0;
432 if ($this->_action & CRM_Core_Action::UPDATE) {
433 $params['id'] = $this->_id;
434 if ($this->_defaults['extends'][0] != $params['extends'][0]) {
435 $params['overrideFKConstraint'] = 1;
436 }
437
438 if (!empty($this->_subtypes)) {
5737ecff 439 $subtypesToBeRemoved = array();
00aca323 440 $subtypesToPreserve = $params['extends'][1];
5737ecff 441 // Don't remove any value if group is extended to -any- subtype
b27a1338 442 if (!empty($subtypesToPreserve[0])) {
5737ecff 443 $subtypesToBeRemoved = array_diff($this->_subtypes, array_intersect($this->_subtypes, $subtypesToPreserve));
444 }
00aca323 445 CRM_Contact_BAO_ContactType::deleteCustomRowsOfSubtype($this->_id, $subtypesToBeRemoved, $subtypesToPreserve);
6a488035
TO
446 }
447 }
448 elseif ($this->_action & CRM_Core_Action::ADD) {
449 //new custom set , so lets set the created_id
450 $session = CRM_Core_Session::singleton();
451 $params['created_id'] = $session->get('userID');
452 $params['created_date'] = date('YmdHis');
453 }
454
455 $group = CRM_Core_BAO_CustomGroup::create($params);
456
457 // reset the cache
458 CRM_Core_BAO_Cache::deleteGroup('contact fields');
459
460 if ($this->_action & CRM_Core_Action::UPDATE) {
461 CRM_Core_Session::setStatus(ts('Your custom field set \'%1 \' has been saved.', array(1 => $group->title)), ts('Saved'), 'success');
462 }
463 else {
704f21c0
CW
464 // Jump directly to adding a field if popups are disabled
465 $action = CRM_Core_Resources::singleton()->ajaxPopupsEnabled ? '' : '/add';
6f231148 466 $url = CRM_Utils_System::url("civicrm/admin/custom/group/field$action", 'reset=1&new=1&gid=' . $group->id . '&action=' . ($action ? 'add' : 'browse'));
6a488035 467 CRM_Core_Session::setStatus(ts("Your custom field set '%1' has been added. You can add custom fields now.",
353ffa53
TO
468 array(1 => $group->title)
469 ), ts('Saved'), 'success');
6a488035
TO
470 $session = CRM_Core_Session::singleton();
471 $session->replaceUserContext($url);
472 }
473
474 // prompt Drupal Views users to update $db_prefix in settings.php, if necessary
475 global $db_prefix;
476 $config = CRM_Core_Config::singleton();
477 if (is_array($db_prefix) && $config->userSystem->is_drupal && module_exists('views')) {
478 // get table_name for each custom group
479 $tables = array();
353ffa53 480 $sql = "SELECT table_name FROM civicrm_custom_group WHERE is_active = 1";
6a488035
TO
481 $result = CRM_Core_DAO::executeQuery($sql);
482 while ($result->fetch()) {
483 $tables[$result->table_name] = $result->table_name;
484 }
485
486 // find out which tables are missing from the $db_prefix array
487 $missingTableNames = array_diff_key($tables, $db_prefix);
488
489 if (!empty($missingTableNames)) {
490 CRM_Core_Session::setStatus(ts("To ensure that all of your custom data groups are available to Views, you may need to add the following key(s) to the db_prefix array in your settings.php file: '%1'.",
353ffa53
TO
491 array(1 => implode(', ', $missingTableNames))
492 ), ts('Note'), 'info');
6a488035
TO
493 }
494 }
495 }
496
e0ef6999 497 /**
a9c1ff43 498 * Return a formatted list of relationship labels.
e0ef6999 499 *
a6c01b45 500 * @return array
a9c1ff43 501 * Array (int $id => string $label).
e0ef6999 502 */
a9c1ff43
TO
503 public static function getRelationshipTypes() {
504 // Note: We include inactive reltypes because we don't want to break custom-data
505 // UI when a reltype is disabled.
506 return CRM_Core_DAO::executeQuery('
507 SELECT
508 id,
509 (CASE 1
510 WHEN label_a_b is not null AND label_b_a is not null AND label_a_b != label_b_a
511 THEN concat(label_a_b, \' / \', label_b_a)
512 WHEN label_a_b is not null
513 THEN label_a_b
514 WHEN label_b_a is not null
515 THEN label_b_a
516 ELSE concat("RelType #", id)
517 END) as label
518 FROM civicrm_relationship_type
519 '
520 )->fetchMap('id', 'label');
6a488035 521 }
96025800 522
6a488035 523}