Merge pull request #14534 from pradpnayak/EventTypeQuery
[civicrm-core.git] / CRM / Admin / Form / Options.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
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
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
34/**
ce064e4f 35 * This class generates form components for Options.
6a488035
TO
36 */
37class CRM_Admin_Form_Options extends CRM_Admin_Form {
38
39 /**
eceb18cc 40 * The option group name.
6a488035
TO
41 *
42 * @var array
6a488035
TO
43 */
44 protected $_gName;
45
46 /**
47 * The option group name in display format (capitalized, without underscores...etc)
48 *
49 * @var array
6a488035 50 */
6c2473d5 51 protected $_gLabel;
6a488035 52
82f3aedc
SL
53 /**
54 * Is this Option Group Domain Specific
55 * @var bool
56 */
57 protected $_domainSpecific = FALSE;
58
6a488035 59 /**
100fef9d 60 * Pre-process
6a488035
TO
61 */
62 public function preProcess() {
63 parent::preProcess();
64 $session = CRM_Core_Session::singleton();
118e964e
CW
65 if (!$this->_gName && !empty($this->urlPath[3])) {
66 $this->_gName = $this->urlPath[3];
67 }
68 if (!$this->_gName && !empty($_GET['gid'])) {
69 $this->_gName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', (int) $_GET['gid'], 'name');
6a488035
TO
70 }
71 if ($this->_gName) {
72 $this->set('gName', $this->_gName);
73 }
74 else {
75 $this->_gName = $this->get('gName');
76 }
118e964e
CW
77 $this->_gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup',
78 $this->_gName,
79 'id',
80 'name'
81 );
faa2cea0 82 $this->_gLabel = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_gid, 'title');
8326c4b5 83 $this->_domainSpecific = in_array($this->_gName, CRM_Core_OptionGroup::$_domainIDGroups);
353ffa53
TO
84 $url = "civicrm/admin/options/{$this->_gName}";
85 $params = "reset=1";
6a488035
TO
86
87 if (($this->_action & CRM_Core_Action::DELETE) &&
be2fb01f 88 in_array($this->_gName, ['email_greeting', 'postal_greeting', 'addressee'])
6a488035
TO
89 ) {
90 // Don't allow delete if the option value belongs to addressee, postal or email greetings and is in use.
353ffa53 91 $findValue = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'value');
be2fb01f 92 $queryParam = [1 => [$findValue, 'Integer']];
6a488035 93 $columnName = $this->_gName . "_id";
353ffa53
TO
94 $sql = "SELECT count(id) FROM civicrm_contact WHERE " . $columnName . " = %1";
95 $isInUse = CRM_Core_DAO::singleValueQuery($sql, $queryParam);
6a488035
TO
96 if ($isInUse) {
97 $scriptURL = "<a href='" . CRM_Utils_System::docURL2('Update Greetings and Address Data for Contacts', TRUE, NULL, NULL, NULL, "wiki") . "'>" . ts('Learn more about a script that can automatically update contact addressee and greeting options.') . "</a>";
be2fb01f 98 CRM_Core_Session::setStatus(ts('The selected %1 option has <strong>not been deleted</strong> because it is currently in use. Please update these contacts to use a different format before deleting this option. %2', [
0d48f1cc
TO
99 1 => $this->_gLabel,
100 2 => $scriptURL,
101 ]), ts('Sorry'), 'error');
6a488035
TO
102 $redirect = CRM_Utils_System::url($url, $params);
103 CRM_Utils_System::redirect($redirect);
104 }
105 }
106
6a488035
TO
107 $session->pushUserContext(CRM_Utils_System::url($url, $params));
108 $this->assign('id', $this->_id);
109
110 if ($this->_id && in_array($this->_gName, CRM_Core_OptionGroup::$_domainIDGroups)) {
111 $domainID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'domain_id', 'id');
112 if (CRM_Core_Config::domainID() != $domainID) {
0499b0ad 113 CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
6a488035
TO
114 }
115 }
116 }
117
118 /**
c490a46a 119 * Set default values for the form.
6a488035 120 */
00be9182 121 public function setDefaultValues() {
6a488035
TO
122 $defaults = parent::setDefaultValues();
123
2b90b596 124 // Default weight & value
be2fb01f
CW
125 $fieldValues = ['option_group_id' => $this->_gid];
126 foreach (['weight', 'value'] as $field) {
2b90b596
CW
127 if (empty($defaults[$field])) {
128 $defaults[$field] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', $fieldValues, $field);
129 }
6a488035
TO
130 }
131
0ef97236 132 // setDefault of contact types for email greeting, postal greeting, addressee, CRM-4575
be2fb01f 133 if (in_array($this->_gName, [
353ffa53
TO
134 'email_greeting',
135 'postal_greeting',
8d7a9d07 136 'addressee',
be2fb01f 137 ])) {
6a488035
TO
138 $defaults['contactOptions'] = (CRM_Utils_Array::value('filter', $defaults)) ? $defaults['filter'] : NULL;
139 }
140 // CRM-11516
141 if ($this->_gName == 'payment_instrument' && $this->_id) {
74afdc40 142 $defaults['financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($this->_id, NULL, 'civicrm_option_value');
6a488035 143 }
b62580ac
CW
144 if (empty($this->_id) || !CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'color')) {
145 $defaults['color'] = '#ffffff';
146 }
6a488035
TO
147 return $defaults;
148 }
149
150 /**
eceb18cc 151 * Build the form object.
6a488035
TO
152 */
153 public function buildQuickForm() {
154 parent::buildQuickForm();
be2fb01f 155 $this->setPageTitle(ts('%1 Option', [1 => $this->_gLabel]));
e2046b33 156
6a488035
TO
157 if ($this->_action & CRM_Core_Action::DELETE) {
158 return;
159 }
160
161 $this->applyFilter('__ALL__', 'trim');
162
163 $isReserved = FALSE;
164 if ($this->_id) {
165 $isReserved = (bool) CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'is_reserved');
166 }
167
168 $this->add('text',
169 'label',
170 ts('Label'),
171 CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'label'),
172 TRUE
173 );
e5720c45 174
635a99e5
CW
175 if ($this->_gName != 'activity_type') {
176 $this->add('text',
177 'value',
178 ts('Value'),
179 CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'value'),
180 TRUE
181 );
82f3aedc
SL
182 $this->addRule('value',
183 ts('This Value already exists in the database for this option group. Please select a different Value.'),
184 'optionExists',
be2fb01f 185 ['CRM_Core_DAO_OptionValue', $this->_id, $this->_gid, 'value', $this->_domainSpecific]
82f3aedc 186 );
635a99e5 187 }
0c6fe5b5 188 else {
be2fb01f 189 $this->add('text', 'icon', ts('Icon'), ['class' => 'crm-icon-picker', 'title' => ts('Choose Icon'), 'allowClear' => TRUE]);
0c6fe5b5 190 }
49c233c1 191
be2fb01f 192 if (in_array($this->_gName, ['activity_status', 'case_status'])) {
b62580ac
CW
193 $this->add('color', 'color', ts('Color'));
194 }
195
0d48f1cc
TO
196 if (!in_array($this->_gName, ['email_greeting', 'postal_greeting', 'addressee'])
197 && !$isReserved
353ffa53 198 ) {
6a488035 199 $this->addRule('label',
82f3aedc 200 ts('This Label already exists in the database for this option group. Please select a different Label.'),
6a488035 201 'optionExists',
be2fb01f 202 ['CRM_Core_DAO_OptionValue', $this->_id, $this->_gid, 'label', $this->_domainSpecific]
6a488035
TO
203 );
204 }
205
206 if ($this->_gName == 'case_status') {
be2fb01f 207 $classes = [
353ffa53 208 'Opened' => ts('Opened'),
6a488035 209 'Closed' => ts('Closed'),
be2fb01f 210 ];
6a488035
TO
211
212 $grouping = $this->add('select',
213 'grouping',
214 ts('Status Class'),
215 $classes
216 );
217 if ($isReserved) {
218 $grouping->freeze();
219 }
220 }
221 // CRM-11516
222 if ($this->_gName == 'payment_instrument') {
f743a6eb 223 $accountType = CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' ");
6a488035 224 $financialAccount = CRM_Contribute_PseudoConstant::financialAccount(NULL, key($accountType));
8ef12e64 225
226 $this->add('select', 'financial_account_id', ts('Financial Account'),
be2fb01f 227 ['' => ts('- select -')] + $financialAccount,
fd1ae183 228 TRUE
6a488035
TO
229 );
230 }
231
760ac501
CW
232 if ($this->_gName == 'activity_status') {
233 $this->add('select',
234 'filter',
235 ts('Status Type'),
be2fb01f 236 [
ce9d78e1
CW
237 CRM_Activity_BAO_Activity::INCOMPLETE => ts('Incomplete'),
238 CRM_Activity_BAO_Activity::COMPLETED => ts('Completed'),
239 CRM_Activity_BAO_Activity::CANCELLED => ts('Cancelled'),
be2fb01f 240 ]
760ac501 241 );
6a488035 242 }
760ac501
CW
243 if ($this->_gName == 'redaction_rule') {
244 $this->add('checkbox',
245 'filter',
246 ts('Regular Expression?')
247 );
6a488035
TO
248 }
249 if ($this->_gName == 'participant_listing') {
250 $this->add('text',
251 'description',
252 ts('Description'),
253 CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'description')
254 );
255 }
256 else {
257 // Hard-coding attributes here since description is still stored as varchar and not text in the schema. dgg
5d51a2f9 258 $this->add('wysiwyg', 'description',
6a488035 259 ts('Description'),
be2fb01f 260 ['rows' => 4, 'cols' => 80],
760ac501 261 $this->_gName == 'custom_search'
6a488035
TO
262 );
263 }
264
265 if ($this->_gName == 'event_badge') {
266 $this->add('text',
267 'name',
268 ts('Class Name'),
269 CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'name')
270 );
271 }
272
d70ada2a 273 $this->add('number',
6a488035 274 'weight',
7ecddde4 275 ts('Order'),
6a488035
TO
276 CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'weight'),
277 TRUE
278 );
279 $this->addRule('weight', ts('is a numeric field'), 'numeric');
280
281 // If CiviCase enabled AND "Add" mode OR "edit" mode for non-reserved activities, only allow user to pick Core or CiviCase component.
282 // FIXME: Each component should define whether adding new activity types is allowed.
283 $config = CRM_Core_Config::singleton();
284 if ($this->_gName == 'activity_type' && in_array("CiviCase", $config->enableComponents) &&
285 (($this->_action & CRM_Core_Action::ADD) || !$isReserved)
286 ) {
287 $caseID = CRM_Core_Component::getComponentID('CiviCase');
be2fb01f 288 $components = ['' => ts('Contacts AND Cases'), $caseID => ts('Cases Only')];
6a488035
TO
289 $this->add('select',
290 'component_id',
291 ts('Component'),
292 $components, FALSE
293 );
294 }
295
296 $enabled = $this->add('checkbox', 'is_active', ts('Enabled?'));
297
298 if ($isReserved) {
299 $enabled->freeze();
300 }
301
0ef97236 302 // fix for CRM-3552, CRM-4575
be2fb01f 303 $showIsDefaultGroups = [
9eab4fdd 304 'email_greeting',
305 'postal_greeting',
306 'addressee',
307 'from_email_address',
308 'case_status',
309 'encounter_medium',
310 'case_type',
311 'payment_instrument',
312 'communication_style',
694ca46e 313 'soft_credit_type',
3fff8d1e 314 'website_type',
be2fb01f 315 ];
9eab4fdd 316
317 if (in_array($this->_gName, $showIsDefaultGroups)) {
6a488035
TO
318 $this->assign('showDefault', TRUE);
319 $this->add('checkbox', 'is_default', ts('Default Option?'));
320 }
321
0ef97236 322 // get contact type for which user want to create a new greeting/addressee type, CRM-4575
0d48f1cc
TO
323 if (in_array($this->_gName, ['email_greeting', 'postal_greeting', 'addressee'])
324 && !$isReserved
353ffa53 325 ) {
be2fb01f 326 $values = [
353ffa53 327 1 => ts('Individual'),
6a488035
TO
328 2 => ts('Household'),
329 3 => ts('Organization'),
330 4 => ts('Multiple Contact Merge'),
be2fb01f
CW
331 ];
332 $this->add('select', 'contactOptions', ts('Contact Type'), ['' => '-select-'] + $values, TRUE);
6a488035
TO
333 $this->assign('showContactFilter', TRUE);
334 }
335
336 if ($this->_gName == 'participant_status') {
337 // For Participant Status options, expose the 'filter' field to track which statuses are "Counted", and the Visibility field
0ef97236 338 $this->add('checkbox', 'filter', ts('Counted?'));
6a488035
TO
339 $this->add('select', 'visibility_id', ts('Visibility'), CRM_Core_PseudoConstant::visibility());
340 }
341 if ($this->_gName == 'participant_role') {
342 // For Participant Role options, expose the 'filter' field to track which statuses are "Counted"
343 $this->add('checkbox', 'filter', ts('Counted?'));
344 }
345
be2fb01f 346 $this->addFormRule(['CRM_Admin_Form_Options', 'formRule'], $this);
6a488035
TO
347 }
348
349 /**
eceb18cc 350 * Global form rule.
6a488035 351 *
5173bd95
TO
352 * @param array $fields
353 * The input form values.
354 * @param array $files
355 * The uploaded files if any.
356 * @param array $self
357 * Current form object.
6a488035 358 *
a6c01b45
CW
359 * @return array
360 * array of errors / empty array.
0ef97236 361 * @throws \CRM_Core_Exception
6a488035 362 */
00be9182 363 public static function formRule($fields, $files, $self) {
be2fb01f 364 $errors = [];
8cc574cf 365 if ($self->_gName == 'case_status' && empty($fields['grouping'])) {
6a488035
TO
366 $errors['grouping'] = ts('Status class is a required field');
367 }
368
0d48f1cc
TO
369 if (in_array($self->_gName, ['email_greeting', 'postal_greeting', 'addressee'])
370 && empty($self->_defaultValues['is_reserved'])
353ffa53
TO
371 ) {
372 $label = $fields['label'];
373 $condition = " AND v.label = '{$label}' ";
374 $values = CRM_Core_OptionGroup::values($self->_gName, FALSE, FALSE, FALSE, $condition, 'filter');
6a488035
TO
375 $checkContactOptions = TRUE;
376
377 if ($self->_id && ($self->_defaultValues['contactOptions'] == $fields['contactOptions'])) {
378 $checkContactOptions = FALSE;
379 }
380
381 if ($checkContactOptions && in_array($fields['contactOptions'], $values)) {
382 $errors['label'] = ts('This Label already exists in the database for the selected contact type.');
383 }
384 }
385
386 if ($self->_gName == 'from_email_address') {
387 $formEmail = CRM_Utils_Mail::pluckEmailFromHeader($fields['label']);
388 if (!CRM_Utils_Rule::email($formEmail)) {
f289559e 389 $errors['label'] = ts('Please enter a valid email address.');
6a488035
TO
390 }
391
392 $formName = explode('"', $fields['label']);
a7488080 393 if (empty($formName[1]) || count($formName) != 3) {
6a488035
TO
394 $errors['label'] = ts('Please follow the proper format for From Email Address');
395 }
396 }
397
d3b018ea 398 $dataType = self::getOptionGroupDataType($self->_gName);
89c05afc 399 if ($dataType && $self->_gName !== 'activity_type') {
d67d221a 400 $validate = CRM_Utils_Type::validate($fields['value'], $dataType, FALSE);
ce7ccb1e 401 if ($validate === FALSE) {
d67d221a
SL
402 CRM_Core_Session::setStatus(
403 ts('Data Type of the value field for this option value does not match ' . $dataType),
404 ts('Value field Data Type mismatch'));
405 }
406 }
6a488035
TO
407 return $errors;
408 }
409
c62c37c7
SL
410 /**
411 * Get the DataType for a specified Option Group.
412 *
1d4e5453 413 * @param string $optionGroupName name of the option group
c62c37c7 414 *
1d4e5453 415 * @return string|null
c62c37c7
SL
416 */
417 public static function getOptionGroupDataType($optionGroupName) {
89c05afc 418 $optionGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $optionGroupName, 'id', 'name');
c62c37c7 419
89c05afc 420 $dataType = CRM_Core_BAO_OptionGroup::getDataType($optionGroupId);
c62c37c7
SL
421 return $dataType;
422 }
423
6a488035 424 /**
eceb18cc 425 * Process the form submission.
6a488035
TO
426 */
427 public function postProcess() {
428 if ($this->_action & CRM_Core_Action::DELETE) {
be2fb01f 429 $fieldValues = ['option_group_id' => $this->_gid];
0ef97236 430 CRM_Utils_Weight::delWeight('CRM_Core_DAO_OptionValue', $this->_id, $fieldValues);
6a488035
TO
431
432 if (CRM_Core_BAO_OptionValue::del($this->_id)) {
433 if ($this->_gName == 'phone_type') {
434 CRM_Core_BAO_Phone::setOptionToNull(CRM_Utils_Array::value('value', $this->_defaultValues));
435 }
436
be2fb01f 437 CRM_Core_Session::setStatus(ts('Selected %1 type has been deleted.', [1 => $this->_gLabel]), ts('Record Deleted'), 'success');
6a488035
TO
438 }
439 else {
be2fb01f 440 CRM_Core_Session::setStatus(ts('Selected %1 type has not been deleted.', [1 => $this->_gLabel]), ts('Sorry'), 'error');
6a488035
TO
441 CRM_Utils_Weight::correctDuplicateWeights('CRM_Core_DAO_OptionValue', $fieldValues);
442 }
443 }
444 else {
6a488035
TO
445 $params = $this->exportValues();
446
447 // allow multiple defaults within group.
be2fb01f 448 $allowMultiDefaults = ['email_greeting', 'postal_greeting', 'addressee', 'from_email_address'];
6a488035
TO
449 if (in_array($this->_gName, $allowMultiDefaults)) {
450 if ($this->_gName == 'from_email_address') {
be2fb01f 451 $params['reset_default_for'] = ['domain_id' => CRM_Core_Config::domainID()];
6a488035
TO
452 }
453 elseif ($filter = CRM_Utils_Array::value('contactOptions', $params)) {
454 $params['filter'] = $filter;
be2fb01f 455 $params['reset_default_for'] = ['filter' => "0, " . $params['filter']];
6a488035
TO
456 }
457
c65ce897 458 //make sure we only have a single space, CRM-6977 and dev/mail/15
6a488035 459 if ($this->_gName == 'from_email_address') {
ccbfdc72 460 $params['label'] = $this->sanitizeFromEmailAddress($params['label']);
6a488035
TO
461 }
462 }
463
74b187a2
KJ
464 // set value of filter if not present in params
465 if ($this->_id && !array_key_exists('filter', $params)) {
466 if ($this->_gName == 'participant_role') {
467 $params['filter'] = 0;
0db6c3e1
TO
468 }
469 else {
74b187a2
KJ
470 $params['filter'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'filter', 'id');
471 }
6a488035
TO
472 }
473
b62580ac
CW
474 if (isset($params['color']) && strtolower($params['color']) == '#ffffff') {
475 $params['color'] = 'null';
476 }
477
ff625280 478 $optionValue = CRM_Core_OptionValue::addOptionValue($params, $this->_gName, $this->_action, $this->_id);
8ef12e64 479
be2fb01f 480 CRM_Core_Session::setStatus(ts('The %1 \'%2\' has been saved.', [
0d48f1cc
TO
481 1 => $this->_gLabel,
482 2 => $optionValue->label,
483 ]), ts('Saved'), 'success');
7c2b40d1
CW
484
485 $this->ajaxResponse['optionValue'] = $optionValue->toArray();
6a488035
TO
486 }
487 }
e2046b33 488
ccbfdc72
MM
489 public function sanitizeFromEmailAddress($email) {
490 preg_match("/^\"(.*)\" *<([^@>]*@[^@>]*)>$/", $email, $parts);
491 return "\"{$parts[1]}\" <$parts[2]>";
492 }
493
6a488035 494}