_settings. * * @return array */ protected function getSettingsMetaData() { if (empty($this->settingsMetadata)) { $allSettingMetaData = civicrm_api3('setting', 'getfields', []); $this->settingsMetadata = array_intersect_key($allSettingMetaData['values'], $this->_settings); // This array_merge re-orders to the key order of $this->_settings. $this->settingsMetadata = array_merge($this->_settings, $this->settingsMetadata); } return $this->settingsMetadata; } /** * Get the settings which can be stored based on metadata. * * @param array $params * @return array */ protected function getSettingsToSetByMetadata($params) { $setValues = array_intersect_key($params, $this->_settings); // Checkboxes will be unset rather than empty so we need to add them back in. // Handle quickform hateability just once, right here right now. $unsetValues = array_diff_key($this->_settings, $params); foreach ($unsetValues as $key => $unsetValue) { if ($this->getQuickFormType($this->getSettingMetadata($key)) === 'CheckBox') { $setValues[$key] = [$key => 0]; } } return $setValues; } /** * @param $params */ protected function filterParamsSetByMetadata(&$params) { foreach ($this->getSettingsToSetByMetadata($params) as $setting => $settingGroup) { //@todo array_diff this unset($params[$setting]); } } /** * Get the metadata for a particular field. * * @param $setting * @return mixed */ protected function getSettingMetadata($setting) { return $this->getSettingsMetaData()[$setting]; } /** * Get the metadata for a particular field for a particular item. * * e.g get 'serialize' key, if exists, for a field. * * @param $setting * @return mixed */ protected function getSettingMetadataItem($setting, $item) { return CRM_Utils_Array::value($item, $this->getSettingsMetaData()[$setting]); } /** * Add fields in the metadata to the template. */ protected function addFieldsDefinedInSettingsMetadata() { $settingMetaData = $this->getSettingsMetaData(); $descriptions = []; foreach ($settingMetaData as $setting => $props) { $quickFormType = $this->getQuickFormType($props); if (isset($quickFormType)) { $options = CRM_Utils_Array::value('options', $props); if (isset($props['pseudoconstant'])) { $options = civicrm_api3('Setting', 'getoptions', [ 'field' => $setting, ])['values']; } if ($props['type'] === 'Boolean') { $options = [$props['title'] => $props['name']]; } //Load input as readonly whose values are overridden in civicrm.settings.php. if (Civi::settings()->getMandatory($setting)) { $props['html_attributes']['readonly'] = TRUE; $this->includesReadOnlyFields = TRUE; } $add = 'add' . $quickFormType; if ($add == 'addElement') { $this->$add( $props['html_type'], $setting, ts($props['title']), ($options !== NULL) ? $options : CRM_Utils_Array::value('html_attributes', $props, []), ($options !== NULL) ? CRM_Utils_Array::value('html_attributes', $props, []) : NULL ); } elseif ($add == 'addSelect') { $this->addElement('select', $setting, ts($props['title']), $options, CRM_Utils_Array::value('html_attributes', $props)); } elseif ($add == 'addCheckBox') { $this->addCheckBox($setting, '', $options, NULL, CRM_Utils_Array::value('html_attributes', $props), NULL, NULL, ['  ']); } elseif ($add == 'addCheckBoxes') { $options = array_flip($options); $newOptions = []; foreach ($options as $key => $val) { $newOptions[$key] = $val; } $this->addCheckBox($setting, $props['title'], $newOptions, NULL, NULL, NULL, NULL, ['  ', '  ', '
'] ); } elseif ($add == 'addChainSelect') { $this->addChainSelect($setting, [ 'label' => ts($props['title']), ]); } elseif ($add == 'addMonthDay') { $this->add('date', $setting, ts($props['title']), CRM_Core_SelectValues::date(NULL, 'M d')); } elseif ($add === 'addEntityRef') { $this->$add($setting, ts($props['title']), $props['entity_reference_options']); } elseif ($add === 'addYesNo' && ($props['type'] === 'Boolean')) { $this->addRadio($setting, ts($props['title']), array(1 => 'Yes', 0 => 'No'), NULL, '  '); } else { $this->$add($setting, ts($props['title']), $options); } // Migrate to using an array as easier in smart... $description = CRM_Utils_Array::value('description', $props); $descriptions[$setting] = $description; $this->assign("{$setting}_description", $description); if ($setting == 'max_attachments') { //temp hack @todo fix to get from metadata $this->addRule('max_attachments', ts('Value should be a positive number'), 'positiveInteger'); } if ($setting == 'maxFileSize') { //temp hack $this->addRule('maxFileSize', ts('Value should be a positive number'), 'positiveInteger'); } } } // setting_description should be deprecated - see Mail.tpl for metadata based tpl. $this->assign('setting_descriptions', $descriptions); $this->assign('settings_fields', $settingMetaData); $this->assign('fields', $settingMetaData); } /** * Get the quickform type for the given html type. * * @param array $spec * * @return string */ protected function getQuickFormType($spec) { if (isset($spec['quick_form_type']) && !($spec['quick_form_type'] === 'Element' && !empty($spec['html_type']))) { // This is kinda transitional return $spec['quick_form_type']; } // The spec for settings has been updated for consistency - we provide deprecation notices for sites that have // not made this change. $htmlType = $spec['html_type']; if ($htmlType !== strtolower($htmlType)) { CRM_Core_Error::deprecatedFunctionWarning(ts('Settings fields html_type should be lower case - see https://docs.civicrm.org/dev/en/latest/framework/setting/ - this needs to be fixed for ' . $spec['name'])); $htmlType = strtolower($spec['html_type']); } $mapping = [ 'checkboxes' => 'CheckBoxes', 'checkbox' => 'CheckBox', 'radio' => 'Radio', 'select' => 'Select', 'textarea' => 'Element', 'text' => 'Element', 'entity_reference' => 'EntityRef', 'advmultiselect' => 'Element', ]; return $mapping[$htmlType]; } /** * Get the defaults for all fields defined in the metadata. * * All others are pending conversion. */ protected function setDefaultsForMetadataDefinedFields() { CRM_Core_BAO_ConfigSetting::retrieve($this->_defaults); foreach (array_keys($this->_settings) as $setting) { $this->_defaults[$setting] = civicrm_api3('setting', 'getvalue', ['name' => $setting]); $spec = $this->getSettingsMetadata()[$setting]; if (!empty($spec['serialize'])) { $this->_defaults[$setting] = CRM_Core_DAO::unSerializeField($this->_defaults[$setting], $spec['serialize']); } if ($this->getQuickFormType($spec) === 'CheckBoxes') { $this->_defaults[$setting] = array_fill_keys($this->_defaults[$setting], 1); } if ($this->getQuickFormType($spec) === 'CheckBox') { $this->_defaults[$setting] = [$setting => $this->_defaults[$setting]]; } } } /** * @param $params * */ protected function saveMetadataDefinedSettings($params) { $settings = $this->getSettingsToSetByMetadata($params); foreach ($settings as $setting => $settingValue) { if ($this->getQuickFormType($this->getSettingMetadata($setting)) === 'CheckBoxes') { $settings[$setting] = array_keys($settingValue); } if ($this->getQuickFormType($this->getSettingMetadata($setting)) === 'CheckBox') { // This will be an array with one value. $settings[$setting] = (int) reset($settings[$setting]); } } civicrm_api3('setting', 'create', $settings); } }