commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / CRM / UF / Form / Field.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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-2015
32 * $Id$
33 *
34 */
35
36 /**
37 * form to process actions on the field aspect of Custom
38 */
39 class CRM_UF_Form_Field extends CRM_Core_Form {
40
41 /**
42 * The uf group id saved to the session for an update.
43 *
44 * @var int
45 */
46 protected $_gid;
47
48 /**
49 * The field id, used when editing the field
50 *
51 * @var int
52 */
53 protected $_id;
54
55 /**
56 * The set of fields that we can view/edit in the user field framework
57 *
58 * @var array
59 */
60 protected $_fields;
61
62 /**
63 * The title for field.
64 *
65 * @var int
66 */
67 protected $_title;
68
69 /**
70 * The set of fields sent to the select element.
71 *
72 * @var array
73 */
74 protected $_selectFields;
75
76 /**
77 * store fields with if locationtype exits status.
78 *
79 * @var array
80 */
81 protected $_hasLocationTypes;
82
83 /**
84 * Is this profile has searchable field.
85 * or is any field having in selector true.
86 *
87 * @var boolean.
88 */
89 protected $_hasSearchableORInSelector;
90
91 /**
92 * Set variables up before form is built.
93 *
94 * @return void
95 */
96 public function preProcess() {
97 $this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this);
98 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
99 if ($this->_gid) {
100 $this->_title = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid, 'title');
101
102 $this->setPageTitle(ts('Profile Field'));
103
104 $url = CRM_Utils_System::url('civicrm/admin/uf/group/field',
105 "reset=1&action=browse&gid={$this->_gid}"
106 );
107
108 $session = CRM_Core_Session::singleton();
109 $session->pushUserContext($url);
110 $breadCrumb = array(
111 array(
112 'title' => ts('CiviCRM Profile Fields'),
113 'url' => $url,
114 ),
115 );
116 CRM_Utils_System::appendBreadCrumb($breadCrumb);
117 }
118
119 $showBestResult = CRM_Utils_Request::retrieve('sbr', 'Positive', CRM_Core_DAO::$_nullArray);
120 if ($showBestResult) {
121 $this->assign('showBestResult', $showBestResult);
122 }
123
124 $this->_fields = CRM_Contact_BAO_Contact::importableFields('All', TRUE, TRUE, TRUE, TRUE, TRUE);
125 $this->_fields = array_merge(CRM_Activity_BAO_Activity::exportableFields('Activity'), $this->_fields);
126
127 //unset campaign related fields.
128 if (isset($this->_fields['activity_campaign_id'])) {
129 $this->_fields['activity_campaign_id']['title'] = ts('Campaign');
130 if (isset($this->_fields['activity_campaign'])) {
131 unset($this->_fields['activity_campaign']);
132 }
133 }
134
135 if (CRM_Core_Permission::access('CiviContribute')) {
136 $this->_fields = array_merge(CRM_Contribute_BAO_Contribution::getContributionFields(FALSE), $this->_fields);
137 $this->_fields = array_merge(CRM_Core_BAO_UFField::getContribBatchEntryFields(), $this->_fields);
138 }
139
140 if (CRM_Core_Permission::access('CiviMember')) {
141 $this->_fields = array_merge(CRM_Member_BAO_Membership::getMembershipFields(), $this->_fields);
142 }
143
144 if (CRM_Core_Permission::access('CiviEvent')) {
145 $this->_fields = array_merge(CRM_Event_BAO_Query::getParticipantFields(), $this->_fields);
146 }
147
148 if (CRM_Core_Permission::access('CiviCase')) {
149 $this->_fields = array_merge(CRM_Case_BAO_Query::getFields(), $this->_fields);
150 }
151
152 $this->_fields = array_merge($this->_fields, CRM_Contact_BAO_Query_Hook::singleton()->getFields());
153
154 $this->_selectFields = array();
155 foreach ($this->_fields as $name => $field) {
156 // lets skip note for now since we dont support it
157 if ($name == 'note') {
158 continue;
159 }
160 $this->_selectFields[$name] = $field['title'];
161 $this->_hasLocationTypes[$name] = CRM_Utils_Array::value('hasLocationType', $field);
162 }
163
164 // lets add group, tag and current_employer to this list
165 $this->_selectFields['group'] = ts('Group(s)');
166 $this->_selectFields['tag'] = ts('Tag(s)');
167 $this->_selectFields['current_employer'] = ts('Current Employer');
168 $this->_selectFields['phone_and_ext'] = ts('Phone and Extension');
169
170 //CRM-4363 check for in selector or searchable fields.
171 $this->_hasSearchableORInSelector = CRM_Core_BAO_UFField::checkSearchableORInSelector($this->_gid);
172
173 $this->assign('fieldId', $this->_id);
174 if ($this->_id) {
175 $fieldTitle = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', $this->_id, 'label');
176 $this->assign('fieldTitle', $fieldTitle);
177 }
178 }
179
180 /**
181 * Build the form object.
182 *
183 * @return void
184 */
185 public function buildQuickForm() {
186 if ($this->_action & CRM_Core_Action::DELETE) {
187 $this->addButtons(array(
188 array(
189 'type' => 'next',
190 'name' => ts('Delete Profile Field'),
191 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
192 'isDefault' => TRUE,
193 ),
194 array(
195 'type' => 'cancel',
196 'name' => ts('Cancel'),
197 ),
198 )
199 );
200 return;
201 }
202
203 if (isset($this->_id)) {
204 $params = array('id' => $this->_id);
205 CRM_Core_BAO_UFField::retrieve($params, $defaults);
206
207 // set it to null if so (avoids crappy E_NOTICE errors below
208 $defaults['location_type_id'] = CRM_Utils_Array::value('location_type_id', $defaults);
209
210 $specialFields = CRM_Core_BAO_UFGroup::getLocationFields();
211
212 if (!$defaults['location_type_id'] &&
213 $defaults["field_type"] != "Formatting" &&
214 in_array($defaults['field_name'], $specialFields)
215 ) {
216 $defaults['location_type_id'] = 0;
217 }
218
219 $defaults['field_name'] = array(
220 $defaults['field_type'],
221 ($defaults['field_type'] == "Formatting" ? "" : $defaults['field_name']),
222 ($defaults['field_name'] == "url") ? $defaults['website_type_id'] : $defaults['location_type_id'],
223 CRM_Utils_Array::value('phone_type_id', $defaults),
224 );
225 $this->_gid = $defaults['uf_group_id'];
226 }
227 else {
228 $defaults['is_active'] = 1;
229 }
230
231 $otherModules = array_values(CRM_Core_BAO_UFGroup::getUFJoinRecord($this->_gid));
232 $this->assign('otherModules', $otherModules);
233
234 if ($this->_action & CRM_Core_Action::ADD) {
235 $fieldValues = array('uf_group_id' => $this->_gid);
236 $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_UFField', $fieldValues);
237 }
238
239 // lets trim all the whitespace
240 $this->applyFilter('__ALL__', 'trim');
241
242 //hidden field to catch the group id in profile
243 $this->add('hidden', 'group_id', $this->_gid);
244
245 //hidden field to catch the field id in profile
246 $this->add('hidden', 'field_id', $this->_id);
247
248 $fields = CRM_Core_BAO_UFField::getAvailableFields($this->_gid, $defaults);
249
250 $noSearchable = $hasWebsiteTypes = array();
251 $addressCustomFields = array_keys(CRM_Core_BAO_CustomField::getFieldsForImport('Address'));
252
253 foreach ($fields as $key => $value) {
254 foreach ($value as $key1 => $value1) {
255 //CRM-2676, replacing the conflict for same custom field name from different custom group.
256 if ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($key1)) {
257 $customGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $customFieldId, 'custom_group_id');
258 $customGroupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'title');
259 $this->_mapperFields[$key][$key1] = $value1['title'] . ' :: ' . $customGroupName;
260 if (in_array($key1, $addressCustomFields)) {
261 $noSearchable[] = $value1['title'] . ' :: ' . $customGroupName;
262 }
263 }
264 else {
265 $this->_mapperFields[$key][$key1] = $value1['title'];
266 }
267 $hasLocationTypes[$key][$key1] = CRM_Utils_Array::value('hasLocationType', $value1);
268 $hasWebsiteTypes[$key][$key1] = CRM_Utils_Array::value('hasWebsiteType', $value1);
269 // hide the 'is searchable' field for 'File' custom data
270 if (isset($value1['data_type']) &&
271 isset($value1['html_type']) &&
272 (($value1['data_type'] == 'File' && $value1['html_type'] == 'File')
273 || ($value1['data_type'] == 'Link' && $value1['html_type'] == 'Link')
274 )
275 ) {
276 if (!in_array($value1['title'], $noSearchable)) {
277 $noSearchable[] = $value1['title'];
278 }
279 }
280 }
281 }
282 $this->assign('noSearchable', $noSearchable);
283
284 $this->_location_types = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
285 $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
286 $this->_website_types = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
287
288 /**
289 * FIXME: dirty hack to make the default option show up first. This
290 * avoids a mozilla browser bug with defaults on dynamically constructed
291 * selector widgets.
292 */
293 if ($defaultLocationType) {
294 $defaultLocation = $this->_location_types[$defaultLocationType->id];
295 unset($this->_location_types[$defaultLocationType->id]);
296 $this->_location_types = array(
297 $defaultLocationType->id => $defaultLocation,
298 ) + $this->_location_types;
299 }
300
301 $this->_location_types = array('Primary') + $this->_location_types;
302
303 // since we need a hierarchical list to display contact types & subtypes,
304 // this is what we going to display in first selector
305 $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(FALSE, FALSE);
306 unset($contactTypes['']);
307
308 $contactTypes = !empty($contactTypes) ? array('Contact' => 'Contacts') + $contactTypes : array();
309 $sel1 = array('' => '- select -') + $contactTypes;
310
311 if (!empty($fields['Activity'])) {
312 $sel1['Activity'] = 'Activity';
313 }
314
315 if (CRM_Core_Permission::access('CiviEvent')) {
316 $sel1['Participant'] = 'Participants';
317 }
318
319 if (!empty($fields['Contribution'])) {
320 $sel1['Contribution'] = 'Contributions';
321 }
322
323 if (!empty($fields['Membership'])) {
324 $sel1['Membership'] = 'Membership';
325 }
326
327 if (!empty($fields['Case'])) {
328 $sel1['Case'] = 'Case';
329 }
330
331 if (!empty($fields['Formatting'])) {
332 $sel1['Formatting'] = 'Formatting';
333 }
334
335 foreach ($sel1 as $key => $sel) {
336 if ($key) {
337 $sel2[$key] = $this->_mapperFields[$key];
338 }
339 }
340 $sel3[''] = NULL;
341 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
342 ksort($phoneTypes);
343
344 foreach ($sel1 as $k => $sel) {
345 if ($k) {
346 foreach ($this->_location_types as $key => $value) {
347 $sel4[$k]['phone'][$key] = &$phoneTypes;
348 $sel4[$k]['phone_and_ext'][$key] = &$phoneTypes;
349 }
350 }
351 }
352
353 foreach ($sel1 as $k => $sel) {
354 if ($k) {
355 if (is_array($this->_mapperFields[$k])) {
356 foreach ($this->_mapperFields[$k] as $key => $value) {
357 if ($hasLocationTypes[$k][$key]) {
358 $sel3[$k][$key] = $this->_location_types;
359 }
360 elseif ($hasWebsiteTypes[$k][$key]) {
361 $sel3[$k][$key] = $this->_website_types;
362 }
363 else {
364 $sel3[$key] = NULL;
365 }
366 }
367 }
368 }
369 }
370
371 $this->_defaults = array();
372 $js = "<script type='text/javascript'>\n";
373 $formName = "document.{$this->_name}";
374
375 $alreadyMixProfile = FALSE;
376 if (CRM_Core_BAO_UFField::checkProfileType($this->_gid)) {
377 $alreadyMixProfile = TRUE;
378 }
379 $this->assign('alreadyMixProfile', $alreadyMixProfile);
380
381 $sel = &$this->addElement('hierselect', 'field_name', ts('Field Name'));
382
383 $formValues = $this->exportValues();
384
385 if (empty($formValues)) {
386 for ($k = 1; $k < 4; $k++) {
387 if (!isset($defaults['field_name'][$k])) {
388 $js .= "{$formName}['field_name[$k]'].style.display = 'none';\n";
389 }
390 }
391 }
392 else {
393 if (!empty($formValues['field_name'])) {
394 for ($key = 1; $key < 4; $key++) {
395 if (!isset($formValues['field_name'][$key])) {
396 $js .= "{$formName}['field_name[$key]'].style.display = 'none';\n";
397 }
398 else {
399 $js .= "{$formName}['field_name[$key]'].style.display = '';\n";
400 }
401 }
402 }
403 else {
404 for ($k = 1; $k < 4; $k++) {
405 if (!isset($defaults['field_name'][$k])) {
406 $js .= "{$formName}['field_name[$k]'].style.display = 'none';\n";
407 }
408 }
409 }
410 }
411
412 foreach ($sel2 as $k => $v) {
413 if (is_array($sel2[$k])) {
414 asort($sel2[$k]);
415 }
416 }
417
418 $sel->setOptions(array($sel1, $sel2, $sel3, $sel4));
419
420 // proper interpretation of spec in CRM-8732
421 if (!isset($this->_id) && in_array('Search Profile', $otherModules)) {
422 $defaults['visibility'] = 'Public Pages and Listings';
423 }
424
425 $js .= "</script>\n";
426 $this->assign('initHideBoxes', $js);
427
428 $this->add('select',
429 'visibility',
430 ts('Visibility'),
431 CRM_Core_SelectValues::ufVisibility(),
432 TRUE,
433 array('onChange' => "showHideSeletorSearch(this.value);")
434 );
435
436 //CRM-4363
437 $js = array('onChange' => "mixProfile();");
438 // should the field appear in selectors (as a column)?
439 $this->add('checkbox', 'in_selector', ts('Results Column?'), NULL, NULL, $js);
440 $this->add('checkbox', 'is_searchable', ts('Searchable?'), NULL, NULL, $js);
441
442 $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFField');
443
444 // weight
445 $this->add('text', 'weight', ts('Order'), $attributes['weight'], TRUE);
446 $this->addRule('weight', ts('is a numeric field'), 'numeric');
447
448 $this->add('textarea', 'help_pre', ts('Field Pre Help'), $attributes['help_pre']);
449 $this->add('textarea', 'help_post', ts('Field Post Help'), $attributes['help_post']);
450
451 $this->add('checkbox', 'is_required', ts('Required?'));
452
453 $this->add('checkbox', 'is_multi_summary', ts('Include in multi-record listing?'));
454 $this->add('checkbox', 'is_active', ts('Active?'));
455 $this->add('checkbox', 'is_view', ts('View Only?'));
456
457 // $this->add( 'checkbox', 'is_registration', ts( 'Display in Registration Form?' ) );
458 //$this->add( 'checkbox', 'is_match' , ts( 'Key to Match Contacts?' ) );
459
460 $this->add('text', 'label', ts('Field Label'), $attributes['label']);
461
462 $js = NULL;
463 if ($this->_hasSearchableORInSelector) {
464 $js = array('onclick' => "return verify( );");
465 }
466
467 // add buttons
468 $this->addButtons(array(
469 array(
470 'type' => 'next',
471 'name' => ts('Save'),
472 'isDefault' => TRUE,
473 'js' => $js,
474 ),
475 array(
476 'type' => 'next',
477 'name' => ts('Save and New'),
478 'subName' => 'new',
479 'js' => $js,
480 ),
481 array(
482 'type' => 'cancel',
483 'name' => ts('Cancel'),
484 ),
485 )
486 );
487
488 $this->addFormRule(array('CRM_UF_Form_Field', 'formRule'), $this);
489
490 // if view mode pls freeze it with the done button.
491 if ($this->_action & CRM_Core_Action::VIEW) {
492 $this->freeze();
493 $this->addElement('button', 'done', ts('Done'),
494 array('onclick' => "location.href='civicrm/admin/uf/group/field?reset=1&action=browse&gid=" . $this->_gid . "'")
495 );
496 }
497
498 $this->setDefaults($defaults);
499 }
500
501 /**
502 * Process the form.
503 *
504 * @return void
505 */
506 public function postProcess() {
507 $ids = array('uf_group' => $this->_gid);
508 if ($this->_action & CRM_Core_Action::DELETE) {
509 $fieldValues = array('uf_group_id' => $this->_gid);
510 CRM_Utils_Weight::delWeight('CRM_Core_DAO_UFField', $this->_id, $fieldValues);
511 $deleted = CRM_Core_BAO_UFField::del($this->_id);
512
513 //update group_type every time. CRM-3608
514 if ($this->_gid && $deleted) {
515 //get the profile type.
516 $fieldsType = CRM_Core_BAO_UFGroup::calculateGroupType($this->_gid, TRUE);
517 CRM_Core_BAO_UFGroup::updateGroupTypes($this->_gid, $fieldsType);
518 }
519
520 CRM_Core_Session::setStatus(ts('Selected Profile Field has been deleted.'), ts('Profile Field Deleted'), 'success');
521 return;
522 }
523
524 // store the submitted values in an array
525 $params = $this->controller->exportValues('Field');
526 if ($params['visibility'] == 'User and User Admin Only') {
527 $params['is_searchable'] = $params['in_selector'] = 0;
528 }
529
530 if ($this->_action & CRM_Core_Action::UPDATE) {
531 $ids['uf_field'] = $this->_id;
532 }
533
534 $name = NULL;
535 if (isset($params['field_name'][1]) && isset($this->_selectFields[$params['field_name'][1]])) {
536 // we dont get a name for a html formatting element
537 $name = $this->_selectFields[$params['field_name'][1]];
538 }
539
540 //Hack for Formatting Field Name
541 if ($params['field_name'][0] == 'Formatting') {
542 $params['field_name'][1] = 'formatting_' . rand(1000, 9999);
543 }
544
545 //check for duplicate fields
546 if ($params["field_name"][0] != "Formatting" && CRM_Core_BAO_UFField::duplicateField($params, $ids)) {
547 CRM_Core_Session::setStatus(ts('The selected field already exists in this profile.'), ts('Field Not Added'), 'error');
548 return;
549 }
550 else {
551 $params['weight'] = CRM_Core_BAO_UFField::autoWeight($params);
552 $ufField = CRM_Core_BAO_UFField::add($params, $ids);
553
554 //reset other field is searchable and in selector settings, CRM-4363
555 if ($this->_hasSearchableORInSelector &&
556 in_array($ufField->field_type, array('Participant', 'Contribution', 'Membership', 'Activity', 'Case'))
557 ) {
558 CRM_Core_BAO_UFField::resetInSelectorANDSearchable($this->_gid);
559 }
560
561 $config = CRM_Core_Config::singleton();
562 $showBestResult = FALSE;
563 if (in_array($ufField->field_name, array(
564 'country',
565 'state_province',
566 )) && count($config->countryLimit) > 1
567 ) {
568 // get state or country field weight if exists
569 $field = 'state_province';
570 if ($ufField->field_name == 'state_province') {
571 $field = 'country';
572 }
573 $ufFieldDAO = new CRM_Core_DAO_UFField();
574 $ufFieldDAO->field_name = $field;
575 $ufFieldDAO->location_type_id = $ufField->location_type_id;
576 $ufFieldDAO->uf_group_id = $ufField->uf_group_id;
577
578 if ($ufFieldDAO->find(TRUE)) {
579 if ($field == 'country' && $ufFieldDAO->weight > $ufField->weight) {
580 $showBestResult = TRUE;
581 }
582 elseif ($field == 'state_province' && $ufFieldDAO->weight < $ufField->weight) {
583 $showBestResult = TRUE;
584 }
585 }
586 }
587
588 //update group_type every time. CRM-3608
589 if ($this->_gid && is_a($ufField, 'CRM_Core_DAO_UFField')) {
590 // get the profile type.
591 $fieldsType = CRM_Core_BAO_UFGroup::calculateGroupType($this->_gid, TRUE);
592 CRM_Core_BAO_UFGroup::updateGroupTypes($this->_gid, $fieldsType);
593 }
594 CRM_Core_Session::setStatus(ts('Your CiviCRM Profile Field \'%1\' has been saved to \'%2\'.',
595 array(1 => $name, 2 => $this->_title)
596 ), ts('Profile Field Saved'), 'success');
597 }
598 $buttonName = $this->controller->getButtonName();
599
600 $session = CRM_Core_Session::singleton();
601 if ($buttonName == $this->getButtonName('next', 'new')) {
602 $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/uf/group/field/add',
603 "reset=1&action=add&gid={$this->_gid}&sbr={$showBestResult}"
604 ));
605 }
606 else {
607 $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/uf/group/field',
608 "reset=1&action=browse&gid={$this->_gid}"
609 ));
610 $session->set('showBestResult', $showBestResult);
611 }
612 }
613
614 /**
615 * Validation rule for subtype.
616 *
617 * @param string $fieldType
618 * Type of field.
619 * @param array $groupType
620 * Contains all groupTypes.
621 * @param array $errors
622 * List of errors to be posted back to the form.
623 */
624 public static function formRuleSubType($fieldType, $groupType, &$errors) {
625 if (in_array($fieldType, array(
626 'Participant',
627 'Contribution',
628 'Membership',
629 'Activity',
630 ))) {
631 $individualSubTypes = CRM_Contact_BAO_ContactType::subTypes('Individual');
632 foreach ($groupType as $value) {
633 if (!in_array($value, $individualSubTypes) &&
634 !in_array($value, array(
635 'Participant',
636 'Contribution',
637 'Membership',
638 'Individual',
639 'Contact',
640 'Activity',
641 'Formatting',
642 ))
643 ) {
644 $errors['field_name'] = ts('Cannot add or update profile field "%1" with combination of Household or Organization or any subtypes of Household or Organization.', array(1 => $fieldType));
645 break;
646 }
647 }
648 }
649 else {
650 $basicType = CRM_Contact_BAO_ContactType::getBasicType($groupType);
651 if ($basicType) {
652 if (!is_array($basicType)) {
653 $basicType = array($basicType);
654 }
655 if (!in_array($fieldType, $basicType) && $fieldType != 'Contact') {
656 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of subtype other than "%1".',
657 array(1 => $fieldType)
658 );
659 }
660 }
661 }
662 }
663
664 /**
665 * Validation rule for custom data extends entity column values.
666 *
667 * @param Object $customField
668 * Custom field.
669 * @param int $gid
670 * Group Id.
671 * @param string $fieldType
672 * Group type of the field.
673 * @param array $errors
674 * Collect errors.
675 *
676 * @return array
677 * list of errors to be posted back to the form
678 */
679 public static function formRuleCustomDataExtentColumnValue($customField, $gid, $fieldType, &$errors) {
680 // fix me : check object $customField
681 if (in_array($fieldType, array(
682 'Participant',
683 'Contribution',
684 'Membership',
685 'Activity',
686 'Case',
687 ))) {
688 $params = array('id' => $customField->custom_group_id);
689 $customGroup = array();
690 CRM_Core_BAO_CustomGroup::retrieve($params, $customGroup);
691 if (($fieldType != CRM_Utils_Array::value('extends', $customGroup)) || empty($customGroup['extends_entity_column_value'])) {
692 return $errors;
693 }
694
695 $extendsColumnValues = array();
696 foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, $customGroup['extends_entity_column_value']) as $val) {
697 if ($val) {
698 $extendsColumnValues[] = $val;
699 }
700 }
701
702 if (empty($extendsColumnValues)) {
703 return $errors;
704 }
705
706 $fieldTypeValues = CRM_Core_BAO_UFGroup::groupTypeValues($gid, $fieldType);
707 if (empty($fieldTypeValues[$fieldType])) {
708 return;
709 }
710
711 $disallowedTypes = array_diff($extendsColumnValues, $fieldTypeValues[$fieldType]);
712 if (!empty($disallowedTypes)) {
713 $errors['field_name'] = ts('Profile is already having custom fields extending different group types, you can not add or update this custom field.');
714 }
715 }
716 }
717
718 /**
719 * Validation rule to prevent multiple fields of primary location type within the same communication type.
720 *
721 * @param array $fields
722 * Submitted fields.
723 * @param string $profileFieldName
724 * Group Id.
725 * @param array $groupFields
726 * List of fields already in the group.
727 * @param array $errors
728 * Collect errors.
729 *
730 */
731 public static function formRulePrimaryCheck($fields, $profileFieldName, $groupFields, &$errors) {
732 //FIXME: This may need to also apply to website fields if they are refactored to allow more than one per profile
733 $checkPrimary = array('phone' => 'civicrm_phone.phone', 'phone_and_ext' => 'civicrm_phone.phone');
734 $whereCheck = NULL;
735 $primaryOfSameTypeFound = NULL;
736 $fieldID = empty($fields['field_id']) ? 0 : $fields['field_id'];
737 // Is this a primary location type field of interest
738 if (array_key_exists($profileFieldName, $checkPrimary)) {
739 $whereCheck = $checkPrimary[$profileFieldName];
740 }
741 $potentialLocationType = CRM_Utils_Array::value(2, $fields['field_name']);
742
743 if ($whereCheck && $potentialLocationType == 0) {
744 $primaryOfSameTypeFound = '';
745
746 foreach ($groupFields as $groupField) {
747 // if it is a phone
748 if ($groupField['where'] == $whereCheck && is_null($groupField['location_type_id']) && $groupField['field_id'] != $fieldID) {
749 $primaryOfSameTypeFound = $groupField['title'];
750 break;
751 }
752 }
753 if ($primaryOfSameTypeFound) {
754 $errors['field_name'] = ts('You have already added a primary location field of this type: %1', array(1 => $primaryOfSameTypeFound));
755 }
756 }
757 }
758
759 /**
760 * Global validation rules for the form.
761 *
762 * @param array $fields
763 * Posted values of the form.
764 *
765 * @param $files
766 * @param $self
767 *
768 * @return array
769 * list of errors to be posted back to the form
770 */
771 public static function formRule($fields, $files, $self) {
772 $is_required = CRM_Utils_Array::value('is_required', $fields, FALSE);
773 $is_registration = CRM_Utils_Array::value('is_registration', $fields, FALSE);
774 $is_view = CRM_Utils_Array::value('is_view', $fields, FALSE);
775 $in_selector = CRM_Utils_Array::value('in_selector', $fields, FALSE);
776 $is_active = CRM_Utils_Array::value('is_active', $fields, FALSE);
777
778 $errors = array();
779 if ($is_view && $is_registration) {
780 $errors['is_registration'] = ts('View Only cannot be selected if this field is to be included on the registration form');
781 }
782 if ($is_view && $is_required) {
783 $errors['is_view'] = ts('A View Only field cannot be required');
784 }
785
786 $entityName = $fields['field_name'][0];
787 if (!$entityName) {
788 $errors['field_name'] = ts('Please select a field name');
789 }
790
791 if ($in_selector && in_array($entityName, array(
792 'Contribution',
793 'Participant',
794 'Membership',
795 'Activity',
796 ))
797 ) {
798 $errors['in_selector'] = ts("'In Selector' cannot be checked for %1 fields.", array(1 => $entityName));
799 }
800
801 $isCustomField = FALSE;
802 $profileFieldName = CRM_Utils_Array::value(1, $fields['field_name']);
803 if ($profileFieldName) {
804 //get custom field id
805 $customFieldId = explode('_', $profileFieldName);
806 if ($customFieldId[0] == 'custom') {
807 $customField = new CRM_Core_DAO_CustomField();
808 $customField->id = $customFieldId[1];
809 $customField->find(TRUE);
810 $isCustomField = TRUE;
811 if (!empty($fields['field_id']) && !$customField->is_active && $is_active) {
812 $errors['field_name'] = ts('Cannot set this field "Active" since the selected custom field is disabled.');
813 }
814
815 //check if profile already has a different multi-record custom set field configured
816 $customGroupId = CRM_Core_BAO_CustomField::isMultiRecordField($profileFieldName);
817 if ($customGroupId) {
818 if ($profileMultiRecordCustomGid = CRM_Core_BAO_UFField::checkMultiRecordFieldExists($self->_gid)) {
819 if ($customGroupId != $profileMultiRecordCustomGid) {
820 $errors['field_name'] = ts("You cannot configure multi-record custom fields belonging to different custom sets in one profile");
821 }
822 }
823 }
824 }
825 }
826
827 // Get list of fields already in the group
828 $groupFields = CRM_Core_BAO_UFGroup::getFields($fields['group_id'], FALSE, NULL, NULL, NULL, TRUE, NULL, TRUE);
829 // Check if we already added a primary field of the same communication type
830 self::formRulePrimaryCheck($fields, $profileFieldName, $groupFields, $errors);
831
832 //check profile is configured for double option process
833 //adding group field, email field should be present in the group
834 //fixed for issue CRM-2861 & CRM-4153
835 if (CRM_Core_BAO_UFGroup::isProfileDoubleOptin()) {
836 if (CRM_Utils_Array::value(1, $fields['field_name']) == 'group') {
837 $dao = new CRM_Core_BAO_UFField();
838 $dao->uf_group_id = $fields['group_id'];
839 $dao->find();
840 $emailField = FALSE;
841 while ($dao->fetch()) {
842 //check email field is present in the group
843 if ($dao->field_name == 'email') {
844 $emailField = TRUE;
845 break;
846 }
847 }
848
849 if (!$emailField) {
850 $disableSettingURL = CRM_Utils_System::url(
851 'civicrm/admin/setting/preferences/mailing',
852 'reset=1'
853 );
854
855 $errors['field_name'] = ts('Your site is currently configured to require double-opt in when users join (subscribe) to Group(s) via a Profile form. In this mode, you need to include an Email field in a Profile BEFORE you can add the Group(s) field. This ensures that an opt-in confirmation email can be sent. Your site administrator can disable double opt-in on the civimail admin settings: <em>%1</em>', array(1 => $disableSettingURL));
856 }
857 }
858 }
859
860 //fix for CRM-3037
861 $fieldType = $fields['field_name'][0];
862
863 //get the group type.
864 $groupType = CRM_Core_BAO_UFGroup::calculateGroupType($self->_gid, FALSE, CRM_Utils_Array::value('field_id', $fields));
865
866 switch ($fieldType) {
867 case 'Contact':
868 self::formRuleSubType($fieldType, $groupType, $errors);
869 break;
870
871 case 'Individual':
872 if (in_array('Activity', $groupType) ||
873 in_array('Household', $groupType) ||
874 in_array('Organization', $groupType)
875 ) {
876
877 //CRM-7603 - need to support activity + individual.
878 //$errors['field_name'] =
879 //ts( 'Cannot add or update profile field type Individual with combination of Household or Organization or Activity' );
880 if (in_array('Household', $groupType) ||
881 in_array('Organization', $groupType)
882 ) {
883 $errors['field_name'] = ts('Cannot add or update profile field type Individual with combination of Household or Organization');
884 }
885 }
886 else {
887 self::formRuleSubType($fieldType, $groupType, $errors);
888 }
889 break;
890
891 case 'Household':
892 if (in_array('Activity', $groupType) || in_array('Individual', $groupType) || in_array('Organization', $groupType)) {
893 $errors['field_name'] = ts('Cannot add or update profile field type Household with combination of Individual or Organization or Activity');
894 }
895 else {
896 self::formRuleSubType($fieldType, $groupType, $errors);
897 }
898 break;
899
900 case 'Organization':
901 if (in_array('Activity', $groupType) || in_array('Household', $groupType) || in_array('Individual', $groupType)) {
902 $errors['field_name'] = ts('Cannot add or update profile field type Organization with combination of Household or Individual or Activity');
903 }
904 else {
905 self::formRuleSubType($fieldType, $groupType, $errors);
906 }
907 break;
908
909 case 'Activity':
910 if (in_array('Individual', $groupType) ||
911 in_array('Membership', $groupType) ||
912 in_array('Contribution', $groupType) ||
913 in_array('Organization', $groupType) ||
914 in_array('Household', $groupType) ||
915 in_array('Participant', $groupType)
916 ) {
917
918 //CRM-7603 - need to support activity + contact type.
919 //$errors['field_name'] =
920 //ts( 'Cannot add or update profile field type Activity with combination Participant or Membership or Contribution or Household or Organization or Individual' );
921 if (in_array('Membership', $groupType) ||
922 in_array('Contribution', $groupType) ||
923 in_array('Participant', $groupType)
924 ) {
925 $errors['field_name'] = ts('Cannot add or update profile field type Activity with combination Participant or Membership or Contribution');
926 }
927 }
928 else {
929 self::formRuleSubType($fieldType, $groupType, $errors);
930 }
931
932 if ($isCustomField && !isset($errors['field_name'])) {
933 self::formRuleCustomDataExtentColumnValue($customField, $self->_gid, $fieldType, $errors);
934 }
935 break;
936
937 case 'Participant':
938 if (in_array('Membership', $groupType) || in_array('Contribution', $groupType)
939 || in_array('Organization', $groupType) || in_array('Household', $groupType) || in_array('Activity', $groupType)
940 ) {
941 $errors['field_name'] = ts('Cannot add or update profile field type Participant with combination of Activity or Membership or Contribution or Household or Organization.');
942 }
943 else {
944 self::formRuleSubType($fieldType, $groupType, $errors);
945 }
946 break;
947
948 case 'Contribution':
949 //special case where in we allow contribution + oganization fields, for on behalf feature
950 $profileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup',
951 'on_behalf_organization', 'id', 'name'
952 );
953
954 if (in_array('Participant', $groupType) || in_array('Membership', $groupType)
955 || ($profileId != $self->_gid && in_array('Organization', $groupType)) || in_array('Household', $groupType) || in_array('Activity', $groupType)
956 ) {
957 $errors['field_name'] = ts('Cannot add or update profile field type Contribution with combination of Activity or Membership or Participant or Household or Organization');
958 }
959 else {
960 self::formRuleSubType($fieldType, $groupType, $errors);
961 }
962 break;
963
964 case 'Membership':
965 //special case where in we allow contribution + oganization fields, for on behalf feature
966 $profileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup',
967 'on_behalf_organization', 'id', 'name'
968 );
969
970 if (in_array('Participant', $groupType) || in_array('Contribution', $groupType)
971 || ($profileId != $self->_gid && in_array('Organization', $groupType)) || in_array('Household', $groupType) || in_array('Activity', $groupType)
972 ) {
973 $errors['field_name'] = ts('Cannot add or update profile field type Membership with combination of Activity or Participant or Contribution or Household or Organization');
974 }
975 else {
976 self::formRuleSubType($fieldType, $groupType, $errors);
977 }
978 break;
979
980 default:
981 $profileType = CRM_Core_BAO_UFField::getProfileType($fields['group_id'], TRUE, FALSE, TRUE);
982 if (CRM_Contact_BAO_ContactType::isaSubType($fieldType)) {
983 if (CRM_Contact_BAO_ContactType::isaSubType($profileType)) {
984 if ($fieldType != $profileType) {
985 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', array(
986 1 => $fieldType,
987 2 => $profileType,
988 ));
989 }
990 }
991 else {
992 $basicType = CRM_Contact_BAO_ContactType::getBasicType($fieldType);
993 if ($profileType &&
994 $profileType != $basicType &&
995 $profileType != 'Contact'
996 ) {
997 $errors['field_name'] = ts('Cannot add or update profile field type "%1" with combination of "%2".', array(
998 1 => $fieldType,
999 2 => $profileType,
1000 ));
1001 }
1002 }
1003 }
1004 elseif (
1005 CRM_Utils_Array::value(1, $fields['field_name']) == 'contact_sub_type' &&
1006 !in_array($profileType, array('Individual', 'Household', 'Organization')) &&
1007 !in_array($profileType, CRM_Contact_BAO_ContactType::subTypes())
1008 ) {
1009 $errors['field_name'] = ts('Cannot add or update profile field Contact Subtype as profile type is not one of Individual, Household or Organization.');
1010 }
1011 }
1012 return empty($errors) ? TRUE : $errors;
1013 }
1014
1015 }