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