1047 lines
33 KiB
PHP
1047 lines
33 KiB
PHP
|
<?php
|
||
|
/*
|
||
|
+--------------------------------------------------------------------+
|
||
|
| CiviCRM version 4.7 |
|
||
|
+--------------------------------------------------------------------+
|
||
|
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||
|
+--------------------------------------------------------------------+
|
||
|
| This file is a part of CiviCRM. |
|
||
|
| |
|
||
|
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||
|
| under the terms of the GNU Affero General Public License |
|
||
|
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||
|
| |
|
||
|
| CiviCRM is distributed in the hope that it will be useful, but |
|
||
|
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||
|
| See the GNU Affero General Public License for more details. |
|
||
|
| |
|
||
|
| You should have received a copy of the GNU Affero General Public |
|
||
|
| License and the CiviCRM Licensing Exception along |
|
||
|
| with this program; if not, contact CiviCRM LLC |
|
||
|
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||
|
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||
|
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||
|
+--------------------------------------------------------------------+
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @package CRM
|
||
|
* @copyright CiviCRM LLC (c) 2004-2017
|
||
|
* $Id$
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* form to process actions on the field aspect of Custom
|
||
|
*/
|
||
|
class CRM_Custom_Form_Field extends CRM_Core_Form {
|
||
|
|
||
|
/**
|
||
|
* Constants for number of options for data types of multiple option.
|
||
|
*/
|
||
|
const NUM_OPTION = 11;
|
||
|
|
||
|
/**
|
||
|
* The custom group id saved to the session for an update.
|
||
|
*
|
||
|
* @var int
|
||
|
*/
|
||
|
protected $_gid;
|
||
|
|
||
|
/**
|
||
|
* The field id, used when editing the field
|
||
|
*
|
||
|
* @var int
|
||
|
*/
|
||
|
protected $_id;
|
||
|
|
||
|
/**
|
||
|
* The default custom data/input types, when editing the field
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $_defaultDataType;
|
||
|
|
||
|
/**
|
||
|
* Array of custom field values if update mode.
|
||
|
*/
|
||
|
protected $_values;
|
||
|
|
||
|
/**
|
||
|
* Array for valid combinations of data_type & html_type
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
private static $_dataTypeValues = NULL;
|
||
|
private static $_dataTypeKeys = NULL;
|
||
|
|
||
|
private static $_dataToHTML = NULL;
|
||
|
|
||
|
private static $_dataToLabels = NULL;
|
||
|
|
||
|
/**
|
||
|
* Set variables up before form is built.
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function preProcess() {
|
||
|
if (!(self::$_dataTypeKeys)) {
|
||
|
self::$_dataTypeKeys = array_keys(CRM_Core_BAO_CustomField::dataType());
|
||
|
self::$_dataTypeValues = array_values(CRM_Core_BAO_CustomField::dataType());
|
||
|
}
|
||
|
|
||
|
if (!self::$_dataToHTML) {
|
||
|
self::$_dataToHTML = CRM_Core_BAO_CustomField::dataToHtml();
|
||
|
}
|
||
|
|
||
|
//custom field id
|
||
|
$this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
|
||
|
|
||
|
$this->_values = array();
|
||
|
//get the values form db if update.
|
||
|
if ($this->_id) {
|
||
|
$params = array('id' => $this->_id);
|
||
|
CRM_Core_BAO_CustomField::retrieve($params, $this->_values);
|
||
|
// note_length is an alias for the text_length field
|
||
|
$this->_values['note_length'] = CRM_Utils_Array::value('text_length', $this->_values);
|
||
|
// custom group id
|
||
|
$this->_gid = $this->_values['custom_group_id'];
|
||
|
}
|
||
|
else {
|
||
|
// custom group id
|
||
|
$this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this);
|
||
|
}
|
||
|
|
||
|
if ($isReserved = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_reserved', 'id')) {
|
||
|
CRM_Core_Error::fatal("You cannot add or edit fields in a reserved custom field-set.");
|
||
|
}
|
||
|
|
||
|
if ($this->_gid) {
|
||
|
$url = CRM_Utils_System::url('civicrm/admin/custom/group/field',
|
||
|
"reset=1&action=browse&gid={$this->_gid}"
|
||
|
);
|
||
|
|
||
|
$session = CRM_Core_Session::singleton();
|
||
|
$session->pushUserContext($url);
|
||
|
}
|
||
|
|
||
|
if (self::$_dataToLabels == NULL) {
|
||
|
self::$_dataToLabels = array(
|
||
|
array(
|
||
|
'Text' => ts('Text'),
|
||
|
'Select' => ts('Select'),
|
||
|
'Radio' => ts('Radio'),
|
||
|
'CheckBox' => ts('CheckBox'),
|
||
|
'Multi-Select' => ts('Multi-Select'),
|
||
|
'AdvMulti-Select' => ts('Adv Multi-Select (obsolete)'),
|
||
|
'Autocomplete-Select' => ts('Autocomplete-Select'),
|
||
|
),
|
||
|
array(
|
||
|
'Text' => ts('Text'),
|
||
|
'Select' => ts('Select'),
|
||
|
'Radio' => ts('Radio'),
|
||
|
),
|
||
|
array(
|
||
|
'Text' => ts('Text'),
|
||
|
'Select' => ts('Select'),
|
||
|
'Radio' => ts('Radio'),
|
||
|
),
|
||
|
array(
|
||
|
'Text' => ts('Text'),
|
||
|
'Select' => ts('Select'),
|
||
|
'Radio' => ts('Radio'),
|
||
|
),
|
||
|
array('TextArea' => ts('TextArea'), 'RichTextEditor' => ts('Rich Text Editor')),
|
||
|
array('Date' => ts('Select Date')),
|
||
|
array('Radio' => ts('Radio')),
|
||
|
array('StateProvince' => ts('Select State/Province'), 'Multi-Select' => ts('Multi-Select State/Province')),
|
||
|
array('Country' => ts('Select Country'), 'Multi-Select' => ts('Multi-Select Country')),
|
||
|
array('File' => ts('Select File')),
|
||
|
array('Link' => ts('Link')),
|
||
|
array('ContactReference' => ts('Autocomplete-Select')),
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set default values for the form. Note that in edit/view mode
|
||
|
* the default values are retrieved from the database
|
||
|
*
|
||
|
* @return array
|
||
|
* array of default values
|
||
|
*/
|
||
|
public function setDefaultValues() {
|
||
|
$defaults = $this->_values;
|
||
|
|
||
|
if ($this->_id) {
|
||
|
$this->assign('id', $this->_id);
|
||
|
$this->_gid = $defaults['custom_group_id'];
|
||
|
|
||
|
//get the value for state or country
|
||
|
if ($defaults['data_type'] == 'StateProvince' &&
|
||
|
$stateId = CRM_Utils_Array::value('default_value', $defaults)
|
||
|
) {
|
||
|
$defaults['default_value'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $stateId);
|
||
|
}
|
||
|
elseif ($defaults['data_type'] == 'Country' &&
|
||
|
$countryId = CRM_Utils_Array::value('default_value', $defaults)
|
||
|
) {
|
||
|
$defaults['default_value'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Country', $countryId);
|
||
|
}
|
||
|
|
||
|
if ($defaults['data_type'] == 'ContactReference' && !empty($defaults['filter'])) {
|
||
|
$contactRefFilter = 'Advance';
|
||
|
if (strpos($defaults['filter'], 'action=lookup') !== FALSE &&
|
||
|
strpos($defaults['filter'], 'group=') !== FALSE
|
||
|
) {
|
||
|
$filterParts = explode('&', $defaults['filter']);
|
||
|
|
||
|
if (count($filterParts) == 2) {
|
||
|
$contactRefFilter = 'Group';
|
||
|
foreach ($filterParts as $part) {
|
||
|
if (strpos($part, 'group=') === FALSE) {
|
||
|
continue;
|
||
|
}
|
||
|
$groups = substr($part, strpos($part, '=') + 1);
|
||
|
foreach (explode(',', $groups) as $grp) {
|
||
|
if (CRM_Utils_Rule::positiveInteger($grp)) {
|
||
|
$defaults['group_id'][] = $grp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$defaults['filter_selected'] = $contactRefFilter;
|
||
|
}
|
||
|
|
||
|
if (!empty($defaults['data_type'])) {
|
||
|
$defaultDataType = array_search($defaults['data_type'],
|
||
|
self::$_dataTypeKeys
|
||
|
);
|
||
|
$defaultHTMLType = array_search($defaults['html_type'],
|
||
|
self::$_dataToHTML[$defaultDataType]
|
||
|
);
|
||
|
$defaults['data_type'] = array(
|
||
|
'0' => $defaultDataType,
|
||
|
'1' => $defaultHTMLType,
|
||
|
);
|
||
|
$this->_defaultDataType = $defaults['data_type'];
|
||
|
}
|
||
|
|
||
|
$defaults['option_type'] = 2;
|
||
|
|
||
|
$this->assign('changeFieldType', CRM_Custom_Form_ChangeFieldType::fieldTypeTransitions($this->_values['data_type'], $this->_values['html_type']));
|
||
|
}
|
||
|
else {
|
||
|
$defaults['is_active'] = 1;
|
||
|
$defaults['option_type'] = 1;
|
||
|
}
|
||
|
|
||
|
// set defaults for weight.
|
||
|
for ($i = 1; $i <= self::NUM_OPTION; $i++) {
|
||
|
$defaults['option_status[' . $i . ']'] = 1;
|
||
|
$defaults['option_weight[' . $i . ']'] = $i;
|
||
|
$defaults['option_value[' . $i . ']'] = $i;
|
||
|
}
|
||
|
|
||
|
if ($this->_action & CRM_Core_Action::ADD) {
|
||
|
$fieldValues = array('custom_group_id' => $this->_gid);
|
||
|
$defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_CustomField', $fieldValues);
|
||
|
|
||
|
$defaults['text_length'] = 255;
|
||
|
$defaults['note_columns'] = 60;
|
||
|
$defaults['note_rows'] = 4;
|
||
|
$defaults['is_view'] = 0;
|
||
|
}
|
||
|
|
||
|
if (!empty($defaults['html_type'])) {
|
||
|
$dontShowLink = substr($defaults['html_type'], -14) == 'State/Province' || substr($defaults['html_type'], -7) == 'Country' ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
if (isset($dontShowLink)) {
|
||
|
$this->assign('dontShowLink', $dontShowLink);
|
||
|
}
|
||
|
if ($this->_action & CRM_Core_Action::ADD &&
|
||
|
CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple', 'id')
|
||
|
) {
|
||
|
$defaults['in_selector'] = 1;
|
||
|
}
|
||
|
|
||
|
return $defaults;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Build the form object.
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function buildQuickForm() {
|
||
|
if ($this->_gid) {
|
||
|
$this->_title = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'title');
|
||
|
CRM_Utils_System::setTitle($this->_title . ' - ' . ($this->_id ? ts('Edit Field') : ts('New Field')));
|
||
|
$this->assign('gid', $this->_gid);
|
||
|
}
|
||
|
|
||
|
// lets trim all the whitespace
|
||
|
$this->applyFilter('__ALL__', 'trim');
|
||
|
|
||
|
$attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_CustomField');
|
||
|
|
||
|
// label
|
||
|
$this->add('text',
|
||
|
'label',
|
||
|
ts('Field Label'),
|
||
|
$attributes['label'],
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
$dt = &self::$_dataTypeValues;
|
||
|
$it = array();
|
||
|
foreach ($dt as $key => $value) {
|
||
|
$it[$key] = self::$_dataToLabels[$key];
|
||
|
}
|
||
|
$sel = &$this->addElement('hierselect',
|
||
|
'data_type',
|
||
|
ts('Data and Input Field Type'),
|
||
|
'onclick="clearSearchBoxes();custom_option_html_type(this.form)"; onBlur="custom_option_html_type(this.form)";',
|
||
|
' '
|
||
|
);
|
||
|
$sel->setOptions(array($dt, $it));
|
||
|
|
||
|
if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple')) {
|
||
|
$this->add('checkbox', 'in_selector', ts('Display in Table?'));
|
||
|
}
|
||
|
|
||
|
if ($this->_action == CRM_Core_Action::UPDATE) {
|
||
|
$this->freeze('data_type');
|
||
|
}
|
||
|
$includeFieldIds = NULL;
|
||
|
if ($this->_action == CRM_Core_Action::UPDATE) {
|
||
|
$includeFieldIds = $this->_values['id'];
|
||
|
}
|
||
|
$optionGroups = CRM_Core_BAO_CustomField::customOptionGroup($includeFieldIds);
|
||
|
$emptyOptGroup = FALSE;
|
||
|
if (empty($optionGroups)) {
|
||
|
$emptyOptGroup = TRUE;
|
||
|
$optionTypes = array('1' => ts('Create a new set of options'));
|
||
|
}
|
||
|
else {
|
||
|
$optionTypes = array(
|
||
|
'1' => ts('Create a new set of options'),
|
||
|
'2' => ts('Reuse an existing set'),
|
||
|
);
|
||
|
|
||
|
$this->add('select',
|
||
|
'option_group_id',
|
||
|
ts('Multiple Choice Option Sets'),
|
||
|
array(
|
||
|
'' => ts('- select -'),
|
||
|
) + $optionGroups
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$element = &$this->addRadio('option_type',
|
||
|
ts('Option Type'),
|
||
|
$optionTypes,
|
||
|
array(
|
||
|
'onclick' => "showOptionSelect();",
|
||
|
), '<br/>'
|
||
|
);
|
||
|
|
||
|
$contactGroups = CRM_Core_PseudoConstant::group();
|
||
|
asort($contactGroups);
|
||
|
|
||
|
$this->add('select',
|
||
|
'group_id',
|
||
|
ts('Limit List to Group'),
|
||
|
$contactGroups,
|
||
|
FALSE,
|
||
|
array('multiple' => 'multiple')
|
||
|
);
|
||
|
|
||
|
$this->add('text',
|
||
|
'filter',
|
||
|
ts('Advanced Filter'),
|
||
|
$attributes['filter']
|
||
|
);
|
||
|
|
||
|
$this->add('hidden', 'filter_selected', 'Group', array('id' => 'filter_selected'));
|
||
|
|
||
|
//if empty option group freeze the option type.
|
||
|
if ($emptyOptGroup) {
|
||
|
$element->freeze();
|
||
|
}
|
||
|
|
||
|
// form fields of Custom Option rows
|
||
|
$defaultOption = array();
|
||
|
$_showHide = new CRM_Core_ShowHideBlocks('', '');
|
||
|
for ($i = 1; $i <= self::NUM_OPTION; $i++) {
|
||
|
|
||
|
//the show hide blocks
|
||
|
$showBlocks = 'optionField_' . $i;
|
||
|
if ($i > 2) {
|
||
|
$_showHide->addHide($showBlocks);
|
||
|
if ($i == self::NUM_OPTION) {
|
||
|
$_showHide->addHide('additionalOption');
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$_showHide->addShow($showBlocks);
|
||
|
}
|
||
|
|
||
|
$optionAttributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue');
|
||
|
// label
|
||
|
$this->add('text', 'option_label[' . $i . ']', ts('Label'),
|
||
|
$optionAttributes['label']
|
||
|
);
|
||
|
|
||
|
// value
|
||
|
$this->add('text', 'option_value[' . $i . ']', ts('Value'),
|
||
|
$optionAttributes['value']
|
||
|
);
|
||
|
|
||
|
// weight
|
||
|
$this->add('text', "option_weight[$i]", ts('Order'),
|
||
|
$optionAttributes['weight']
|
||
|
);
|
||
|
|
||
|
// is active ?
|
||
|
$this->add('checkbox', "option_status[$i]", ts('Active?'));
|
||
|
|
||
|
$defaultOption[$i] = $this->createElement('radio', NULL, NULL, NULL, $i);
|
||
|
|
||
|
//for checkbox handling of default option
|
||
|
$this->add('checkbox', "default_checkbox_option[$i]", NULL);
|
||
|
}
|
||
|
|
||
|
//default option selection
|
||
|
$this->addGroup($defaultOption, 'default_option');
|
||
|
|
||
|
$_showHide->addToTemplate();
|
||
|
|
||
|
// text length for alpha numeric data types
|
||
|
$this->add('number',
|
||
|
'text_length',
|
||
|
ts('Database field length'),
|
||
|
$attributes['text_length'] + array('min' => 1),
|
||
|
FALSE
|
||
|
);
|
||
|
$this->addRule('text_length', ts('Value should be a positive number'), 'integer');
|
||
|
|
||
|
$this->add('text',
|
||
|
'start_date_years',
|
||
|
ts('Dates may be up to'),
|
||
|
$attributes['start_date_years'],
|
||
|
FALSE
|
||
|
);
|
||
|
$this->add('text',
|
||
|
'end_date_years',
|
||
|
ts('Dates may be up to'),
|
||
|
$attributes['end_date_years'],
|
||
|
FALSE
|
||
|
);
|
||
|
|
||
|
$this->addRule('start_date_years', ts('Value should be a positive number'), 'integer');
|
||
|
$this->addRule('end_date_years', ts('Value should be a positive number'), 'integer');
|
||
|
|
||
|
$this->add('select', 'date_format', ts('Date Format'),
|
||
|
array('' => ts('- select -')) + CRM_Core_SelectValues::getDatePluginInputFormats()
|
||
|
);
|
||
|
|
||
|
$this->add('select', 'time_format', ts('Time'),
|
||
|
array('' => ts('- none -')) + CRM_Core_SelectValues::getTimeFormats()
|
||
|
);
|
||
|
|
||
|
// for Note field
|
||
|
$this->add('number',
|
||
|
'note_columns',
|
||
|
ts('Width (columns)') . ' ',
|
||
|
$attributes['note_columns'],
|
||
|
FALSE
|
||
|
);
|
||
|
$this->add('number',
|
||
|
'note_rows',
|
||
|
ts('Height (rows)') . ' ',
|
||
|
$attributes['note_rows'],
|
||
|
FALSE
|
||
|
);
|
||
|
$this->add('number',
|
||
|
'note_length',
|
||
|
ts('Maximum length') . ' ',
|
||
|
$attributes['text_length'], // note_length is an alias for the text-length field
|
||
|
FALSE
|
||
|
);
|
||
|
|
||
|
$this->addRule('note_columns', ts('Value should be a positive number'), 'positiveInteger');
|
||
|
$this->addRule('note_rows', ts('Value should be a positive number'), 'positiveInteger');
|
||
|
$this->addRule('note_length', ts('Value should be a positive number'), 'positiveInteger');
|
||
|
|
||
|
// weight
|
||
|
$this->add('number', 'weight', ts('Order'),
|
||
|
$attributes['weight'],
|
||
|
TRUE
|
||
|
);
|
||
|
$this->addRule('weight', ts('is a numeric field'), 'numeric');
|
||
|
|
||
|
// is required ?
|
||
|
$this->add('advcheckbox', 'is_required', ts('Required?'));
|
||
|
|
||
|
// checkbox / radio options per line
|
||
|
$this->add('number', 'options_per_line', ts('Options Per Line'), array('min' => 0));
|
||
|
$this->addRule('options_per_line', ts('must be a numeric value'), 'numeric');
|
||
|
|
||
|
// default value, help pre, help post, mask, attributes, javascript ?
|
||
|
$this->add('text', 'default_value', ts('Default Value'),
|
||
|
$attributes['default_value']
|
||
|
);
|
||
|
$this->add('textarea', 'help_pre', ts('Field Pre Help'),
|
||
|
$attributes['help_pre']
|
||
|
);
|
||
|
$this->add('textarea', 'help_post', ts('Field Post Help'),
|
||
|
$attributes['help_post']
|
||
|
);
|
||
|
$this->add('text', 'mask', ts('Mask'),
|
||
|
$attributes['mask']
|
||
|
);
|
||
|
|
||
|
// is active ?
|
||
|
$this->add('advcheckbox', 'is_active', ts('Active?'));
|
||
|
|
||
|
// is active ?
|
||
|
$this->add('advcheckbox', 'is_view', ts('View Only?'));
|
||
|
|
||
|
// is searchable ?
|
||
|
$this->addElement('advcheckbox',
|
||
|
'is_searchable',
|
||
|
ts('Is this Field Searchable?'),
|
||
|
NULL, array('onclick' => "showSearchRange(this)")
|
||
|
);
|
||
|
|
||
|
// is searchable by range?
|
||
|
$searchRange = array();
|
||
|
$searchRange[] = $this->createElement('radio', NULL, NULL, ts('Yes'), '1');
|
||
|
$searchRange[] = $this->createElement('radio', NULL, NULL, ts('No'), '0');
|
||
|
|
||
|
$this->addGroup($searchRange, 'is_search_range', ts('Search by Range?'));
|
||
|
|
||
|
// add buttons
|
||
|
$this->addButtons(array(
|
||
|
array(
|
||
|
'type' => 'done',
|
||
|
'name' => ts('Save'),
|
||
|
'isDefault' => TRUE,
|
||
|
),
|
||
|
array(
|
||
|
'type' => 'next',
|
||
|
'name' => ts('Save and New'),
|
||
|
'subName' => 'new',
|
||
|
),
|
||
|
array(
|
||
|
'type' => 'cancel',
|
||
|
'name' => ts('Cancel'),
|
||
|
),
|
||
|
)
|
||
|
);
|
||
|
|
||
|
// add a form rule to check default value
|
||
|
$this->addFormRule(array('CRM_Custom_Form_Field', 'formRule'), $this);
|
||
|
|
||
|
// if view mode pls freeze it with the done button.
|
||
|
if ($this->_action & CRM_Core_Action::VIEW) {
|
||
|
$this->freeze();
|
||
|
$url = CRM_Utils_System::url('civicrm/admin/custom/group/field', 'reset=1&action=browse&gid=' . $this->_gid);
|
||
|
$this->addElement('button',
|
||
|
'done',
|
||
|
ts('Done'),
|
||
|
array('onclick' => "location.href='$url'")
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Global validation rules for the form.
|
||
|
*
|
||
|
* @param array $fields
|
||
|
* Posted values of the form.
|
||
|
*
|
||
|
* @param $files
|
||
|
* @param $self
|
||
|
*
|
||
|
* @return array
|
||
|
* if errors then list of errors to be posted back to the form,
|
||
|
* true otherwise
|
||
|
*/
|
||
|
public static function formRule($fields, $files, $self) {
|
||
|
$default = CRM_Utils_Array::value('default_value', $fields);
|
||
|
|
||
|
$errors = array();
|
||
|
|
||
|
self::clearEmptyOptions($fields);
|
||
|
|
||
|
//validate field label as well as name.
|
||
|
$title = $fields['label'];
|
||
|
$name = CRM_Utils_String::munge($title, '_', 64);
|
||
|
$gId = $self->_gid; // CRM-7564
|
||
|
$query = 'select count(*) from civicrm_custom_field where ( name like %1 OR label like %2 ) and id != %3 and custom_group_id = %4';
|
||
|
$fldCnt = CRM_Core_DAO::singleValueQuery($query, array(
|
||
|
1 => array($name, 'String'),
|
||
|
2 => array($title, 'String'),
|
||
|
3 => array((int) $self->_id, 'Integer'),
|
||
|
4 => array($gId, 'Integer'),
|
||
|
));
|
||
|
if ($fldCnt) {
|
||
|
$errors['label'] = ts('Custom field \'%1\' already exists in Database.', array(1 => $title));
|
||
|
}
|
||
|
|
||
|
//checks the given custom field name doesnot start with digit
|
||
|
if (!empty($title)) {
|
||
|
// gives the ascii value
|
||
|
$asciiValue = ord($title{0});
|
||
|
if ($asciiValue >= 48 && $asciiValue <= 57) {
|
||
|
$errors['label'] = ts("Name cannot not start with a digit");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ensure that the label is not 'id'
|
||
|
if (strtolower($title) == 'id') {
|
||
|
$errors['label'] = ts("You cannot use 'id' as a field label.");
|
||
|
}
|
||
|
|
||
|
if (!isset($fields['data_type'][0]) || !isset($fields['data_type'][1])) {
|
||
|
$errors['_qf_default'] = ts('Please enter valid - Data and Input Field Type.');
|
||
|
}
|
||
|
|
||
|
$dataType = self::$_dataTypeKeys[$fields['data_type'][0]];
|
||
|
|
||
|
if ($default || $dataType == 'ContactReference') {
|
||
|
switch ($dataType) {
|
||
|
case 'Int':
|
||
|
if (!CRM_Utils_Rule::integer($default)) {
|
||
|
$errors['default_value'] = ts('Please enter a valid integer.');
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Float':
|
||
|
if (!CRM_Utils_Rule::numeric($default)) {
|
||
|
$errors['default_value'] = ts('Please enter a valid number.');
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Money':
|
||
|
if (!CRM_Utils_Rule::money($default)) {
|
||
|
$errors['default_value'] = ts('Please enter a valid number.');
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Link':
|
||
|
if (!CRM_Utils_Rule::url($default)) {
|
||
|
$errors['default_value'] = ts('Please enter a valid link.');
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Date':
|
||
|
if (!CRM_Utils_Rule::date($default)) {
|
||
|
$errors['default_value'] = ts('Please enter a valid date as default value using YYYY-MM-DD format. Example: 2004-12-31.');
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Boolean':
|
||
|
if ($default != '1' && $default != '0') {
|
||
|
$errors['default_value'] = ts('Please enter 1 (for Yes) or 0 (for No) if you want to set a default value.');
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Country':
|
||
|
if (!empty($default)) {
|
||
|
$query = "SELECT count(*) FROM civicrm_country WHERE name = %1 OR iso_code = %1";
|
||
|
$params = array(1 => array($fields['default_value'], 'String'));
|
||
|
if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
|
||
|
$errors['default_value'] = ts('Invalid default value for country.');
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'StateProvince':
|
||
|
if (!empty($default)) {
|
||
|
$query = "
|
||
|
SELECT count(*)
|
||
|
FROM civicrm_state_province
|
||
|
WHERE name = %1
|
||
|
OR abbreviation = %1";
|
||
|
$params = array(1 => array($fields['default_value'], 'String'));
|
||
|
if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
|
||
|
$errors['default_value'] = ts('The invalid default value for State/Province data type');
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'ContactReference':
|
||
|
if ($fields['filter_selected'] == 'Advance' && !empty($fields['filter'])) {
|
||
|
if (strpos($fields['filter'], 'entity=') !== FALSE) {
|
||
|
$errors['filter'] = ts("Please do not include entity parameter (entity is always 'contact')");
|
||
|
}
|
||
|
elseif (strpos($fields['filter'], 'action=get') === FALSE) {
|
||
|
$errors['filter'] = ts("Only 'get' action is supported.");
|
||
|
}
|
||
|
}
|
||
|
$self->setDefaults(array('filter_selected', $fields['filter_selected']));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (self::$_dataTypeKeys[$fields['data_type'][0]] == 'Date') {
|
||
|
if (!$fields['date_format']) {
|
||
|
$errors['date_format'] = ts('Please select a date format.');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Check the option values entered
|
||
|
* Appropriate values are required for the selected datatype
|
||
|
* Incomplete row checking is also required.
|
||
|
*/
|
||
|
$_flagOption = $_rowError = 0;
|
||
|
$_showHide = new CRM_Core_ShowHideBlocks('', '');
|
||
|
$dataType = self::$_dataTypeKeys[$fields['data_type'][0]];
|
||
|
if (isset($fields['data_type'][1])) {
|
||
|
$dataField = $fields['data_type'][1];
|
||
|
}
|
||
|
$optionFields = array('Select', 'Multi-Select', 'CheckBox', 'Radio', 'AdvMulti-Select');
|
||
|
|
||
|
if (isset($fields['option_type']) && $fields['option_type'] == 1) {
|
||
|
//capture duplicate Custom option values
|
||
|
if (!empty($fields['option_value'])) {
|
||
|
$countValue = count($fields['option_value']);
|
||
|
$uniqueCount = count(array_unique($fields['option_value']));
|
||
|
|
||
|
if ($countValue > $uniqueCount) {
|
||
|
|
||
|
$start = 1;
|
||
|
while ($start < self::NUM_OPTION) {
|
||
|
$nextIndex = $start + 1;
|
||
|
while ($nextIndex <= self::NUM_OPTION) {
|
||
|
if ($fields['option_value'][$start] == $fields['option_value'][$nextIndex] &&
|
||
|
strlen($fields['option_value'][$nextIndex])
|
||
|
) {
|
||
|
$errors['option_value[' . $start . ']'] = ts('Duplicate Option values');
|
||
|
$errors['option_value[' . $nextIndex . ']'] = ts('Duplicate Option values');
|
||
|
$_flagOption = 1;
|
||
|
}
|
||
|
$nextIndex++;
|
||
|
}
|
||
|
$start++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//capture duplicate Custom Option label
|
||
|
if (!empty($fields['option_label'])) {
|
||
|
$countValue = count($fields['option_label']);
|
||
|
$uniqueCount = count(array_unique($fields['option_label']));
|
||
|
|
||
|
if ($countValue > $uniqueCount) {
|
||
|
$start = 1;
|
||
|
while ($start < self::NUM_OPTION) {
|
||
|
$nextIndex = $start + 1;
|
||
|
while ($nextIndex <= self::NUM_OPTION) {
|
||
|
if ($fields['option_label'][$start] == $fields['option_label'][$nextIndex] &&
|
||
|
!empty($fields['option_label'][$nextIndex])
|
||
|
) {
|
||
|
$errors['option_label[' . $start . ']'] = ts('Duplicate Option label');
|
||
|
$errors['option_label[' . $nextIndex . ']'] = ts('Duplicate Option label');
|
||
|
$_flagOption = 1;
|
||
|
}
|
||
|
$nextIndex++;
|
||
|
}
|
||
|
$start++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ($i = 1; $i <= self::NUM_OPTION; $i++) {
|
||
|
if (!$fields['option_label'][$i]) {
|
||
|
if ($fields['option_value'][$i]) {
|
||
|
$errors['option_label[' . $i . ']'] = ts('Option label cannot be empty');
|
||
|
$_flagOption = 1;
|
||
|
}
|
||
|
else {
|
||
|
$_emptyRow = 1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (!strlen(trim($fields['option_value'][$i]))) {
|
||
|
if (!$fields['option_value'][$i]) {
|
||
|
$errors['option_value[' . $i . ']'] = ts('Option value cannot be empty');
|
||
|
$_flagOption = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($fields['option_value'][$i] && $dataType != 'String') {
|
||
|
if ($dataType == 'Int') {
|
||
|
if (!CRM_Utils_Rule::integer($fields['option_value'][$i])) {
|
||
|
$_flagOption = 1;
|
||
|
$errors['option_value[' . $i . ']'] = ts('Please enter a valid integer.');
|
||
|
}
|
||
|
}
|
||
|
elseif ($dataType == 'Money') {
|
||
|
if (!CRM_Utils_Rule::money($fields['option_value'][$i])) {
|
||
|
$_flagOption = 1;
|
||
|
$errors['option_value[' . $i . ']'] = ts('Please enter a valid money value.');
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (!CRM_Utils_Rule::numeric($fields['option_value'][$i])) {
|
||
|
$_flagOption = 1;
|
||
|
$errors['option_value[' . $i . ']'] = ts('Please enter a valid number.');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$showBlocks = 'optionField_' . $i;
|
||
|
if ($_flagOption) {
|
||
|
$_showHide->addShow($showBlocks);
|
||
|
$_rowError = 1;
|
||
|
}
|
||
|
|
||
|
if (!empty($_emptyRow)) {
|
||
|
$_showHide->addHide($showBlocks);
|
||
|
}
|
||
|
else {
|
||
|
$_showHide->addShow($showBlocks);
|
||
|
}
|
||
|
if ($i == self::NUM_OPTION) {
|
||
|
$hideBlock = 'additionalOption';
|
||
|
$_showHide->addHide($hideBlock);
|
||
|
}
|
||
|
|
||
|
$_flagOption = $_emptyRow = 0;
|
||
|
}
|
||
|
}
|
||
|
elseif (isset($dataField) &&
|
||
|
in_array($dataField, $optionFields) &&
|
||
|
!in_array($dataType, array('Boolean', 'Country', 'StateProvince'))
|
||
|
) {
|
||
|
if (!$fields['option_group_id']) {
|
||
|
$errors['option_group_id'] = ts('You must select a Multiple Choice Option set if you chose Reuse an existing set.');
|
||
|
}
|
||
|
else {
|
||
|
$query = "
|
||
|
SELECT count(*)
|
||
|
FROM civicrm_custom_field
|
||
|
WHERE data_type != %1
|
||
|
AND option_group_id = %2";
|
||
|
$params = array(
|
||
|
1 => array(
|
||
|
self::$_dataTypeKeys[$fields['data_type'][0]],
|
||
|
'String',
|
||
|
),
|
||
|
2 => array($fields['option_group_id'], 'Integer'),
|
||
|
);
|
||
|
$count = CRM_Core_DAO::singleValueQuery($query, $params);
|
||
|
if ($count > 0) {
|
||
|
$errors['option_group_id'] = ts('The data type of the multiple choice option set you\'ve selected does not match the data type assigned to this field.');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$assignError = new CRM_Core_Page();
|
||
|
if ($_rowError) {
|
||
|
$_showHide->addToTemplate();
|
||
|
$assignError->assign('optionRowError', $_rowError);
|
||
|
}
|
||
|
else {
|
||
|
if (isset($fields['data_type'][1])) {
|
||
|
switch (self::$_dataToHTML[$fields['data_type'][0]][$fields['data_type'][1]]) {
|
||
|
case 'Radio':
|
||
|
$_fieldError = 1;
|
||
|
$assignError->assign('fieldError', $_fieldError);
|
||
|
break;
|
||
|
|
||
|
case 'Checkbox':
|
||
|
$_fieldError = 1;
|
||
|
$assignError->assign('fieldError', $_fieldError);
|
||
|
break;
|
||
|
|
||
|
case 'Select':
|
||
|
$_fieldError = 1;
|
||
|
$assignError->assign('fieldError', $_fieldError);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$_fieldError = 0;
|
||
|
$assignError->assign('fieldError', $_fieldError);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ($idx = 1; $idx <= self::NUM_OPTION; $idx++) {
|
||
|
$showBlocks = 'optionField_' . $idx;
|
||
|
if (!empty($fields['option_label'][$idx])) {
|
||
|
$_showHide->addShow($showBlocks);
|
||
|
}
|
||
|
else {
|
||
|
$_showHide->addHide($showBlocks);
|
||
|
}
|
||
|
}
|
||
|
$_showHide->addToTemplate();
|
||
|
}
|
||
|
|
||
|
// we can not set require and view at the same time.
|
||
|
if (!empty($fields['is_required']) && !empty($fields['is_view'])) {
|
||
|
$errors['is_view'] = ts('Can not set this field Required and View Only at the same time.');
|
||
|
}
|
||
|
|
||
|
return empty($errors) ? TRUE : $errors;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Process the form.
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function postProcess() {
|
||
|
// store the submitted values in an array
|
||
|
$params = $this->controller->exportValues($this->_name);
|
||
|
self::clearEmptyOptions($params);
|
||
|
if ($this->_action == CRM_Core_Action::UPDATE) {
|
||
|
$dataTypeKey = $this->_defaultDataType[0];
|
||
|
$params['data_type'] = self::$_dataTypeKeys[$this->_defaultDataType[0]];
|
||
|
$params['html_type'] = self::$_dataToHTML[$this->_defaultDataType[0]][$this->_defaultDataType[1]];
|
||
|
}
|
||
|
else {
|
||
|
$dataTypeKey = $params['data_type'][0];
|
||
|
$params['html_type'] = self::$_dataToHTML[$params['data_type'][0]][$params['data_type'][1]];
|
||
|
$params['data_type'] = self::$_dataTypeKeys[$params['data_type'][0]];
|
||
|
}
|
||
|
|
||
|
//fix for 'is_search_range' field.
|
||
|
if (in_array($dataTypeKey, array(
|
||
|
1,
|
||
|
2,
|
||
|
3,
|
||
|
5,
|
||
|
))) {
|
||
|
if (empty($params['is_searchable'])) {
|
||
|
$params['is_search_range'] = 0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$params['is_search_range'] = 0;
|
||
|
}
|
||
|
|
||
|
$filter = 'null';
|
||
|
if ($dataTypeKey == 11 && !empty($params['filter_selected'])) {
|
||
|
if ($params['filter_selected'] == 'Advance' && trim(CRM_Utils_Array::value('filter', $params))) {
|
||
|
$filter = trim($params['filter']);
|
||
|
}
|
||
|
elseif ($params['filter_selected'] == 'Group' && !empty($params['group_id'])) {
|
||
|
|
||
|
$filter = 'action=lookup&group=' . implode(',', $params['group_id']);
|
||
|
}
|
||
|
}
|
||
|
$params['filter'] = $filter;
|
||
|
|
||
|
// fix for CRM-316
|
||
|
$oldWeight = NULL;
|
||
|
if ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD)) {
|
||
|
$fieldValues = array('custom_group_id' => $this->_gid);
|
||
|
if ($this->_id) {
|
||
|
$oldWeight = $this->_values['weight'];
|
||
|
}
|
||
|
$params['weight'] = CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_CustomField', $oldWeight, $params['weight'], $fieldValues);
|
||
|
}
|
||
|
|
||
|
$strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
|
||
|
|
||
|
//store the primary key for State/Province or Country as default value.
|
||
|
if (strlen(trim($params['default_value']))) {
|
||
|
switch ($params['data_type']) {
|
||
|
case 'StateProvince':
|
||
|
$fieldStateProvince = $strtolower($params['default_value']);
|
||
|
|
||
|
// LOWER in query below roughly translates to 'hurt my database without deriving any benefit' See CRM-19811.
|
||
|
$query = "
|
||
|
SELECT id
|
||
|
FROM civicrm_state_province
|
||
|
WHERE LOWER(name) = '$fieldStateProvince'
|
||
|
OR abbreviation = '$fieldStateProvince'";
|
||
|
$dao = CRM_Core_DAO::executeQuery($query);
|
||
|
if ($dao->fetch()) {
|
||
|
$params['default_value'] = $dao->id;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'Country':
|
||
|
$fieldCountry = $strtolower($params['default_value']);
|
||
|
|
||
|
// LOWER in query below roughly translates to 'hurt my database without deriving any benefit' See CRM-19811.
|
||
|
$query = "
|
||
|
SELECT id
|
||
|
FROM civicrm_country
|
||
|
WHERE LOWER(name) = '$fieldCountry'
|
||
|
OR iso_code = '$fieldCountry'";
|
||
|
$dao = CRM_Core_DAO::executeQuery($query);
|
||
|
if ($dao->fetch()) {
|
||
|
$params['default_value'] = $dao->id;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The text_length attribute for Memo fields is in a different input as there
|
||
|
// are different label, help text and default value than for other type fields
|
||
|
if ($params['data_type'] == "Memo") {
|
||
|
$params['text_length'] = $params['note_length'];
|
||
|
}
|
||
|
|
||
|
// need the FKEY - custom group id
|
||
|
$params['custom_group_id'] = $this->_gid;
|
||
|
|
||
|
if ($this->_action & CRM_Core_Action::UPDATE) {
|
||
|
$params['id'] = $this->_id;
|
||
|
}
|
||
|
$customField = CRM_Core_BAO_CustomField::create($params);
|
||
|
$this->_id = $customField->id;
|
||
|
|
||
|
// reset the cache
|
||
|
CRM_Core_BAO_Cache::deleteGroup('contact fields');
|
||
|
|
||
|
$msg = '<p>' . ts("Custom field '%1' has been saved.", array(1 => $customField->label)) . '</p>';
|
||
|
|
||
|
$buttonName = $this->controller->getButtonName();
|
||
|
$session = CRM_Core_Session::singleton();
|
||
|
if ($buttonName == $this->getButtonName('next', 'new')) {
|
||
|
$msg .= '<p>' . ts("Ready to add another.") . '</p>';
|
||
|
$session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/custom/group/field/add',
|
||
|
'reset=1&action=add&gid=' . $this->_gid
|
||
|
));
|
||
|
}
|
||
|
else {
|
||
|
$session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/custom/group/field',
|
||
|
'reset=1&action=browse&gid=' . $this->_gid
|
||
|
));
|
||
|
}
|
||
|
$session->setStatus($msg, ts('Saved'), 'success');
|
||
|
|
||
|
// Add data when in ajax contect
|
||
|
$this->ajaxResponse['customField'] = $customField->toArray();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes value from fields with no label.
|
||
|
*
|
||
|
* This allows default values to be set in the form, but ignored in post-processing.
|
||
|
*
|
||
|
* @param array $fields
|
||
|
*/
|
||
|
public static function clearEmptyOptions(&$fields) {
|
||
|
foreach ($fields['option_label'] as $i => $label) {
|
||
|
if (!strlen(trim($label))) {
|
||
|
$fields['option_value'][$i] = '';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|