Example #1
0
 /**
  * Adds a field based on metadata.
  *
  * @param $name
  *   Field name to go on the form.
  * @param array $props
  *   Mix of html attributes and special properties, namely.
  *   - entity (api entity name, can usually be inferred automatically from the form class)
  *   - name (field name - only needed if different from name used on the form)
  *   - option_url - path to edit this option list - usually retrieved automatically - set to NULL to disable link
  *   - placeholder - set to NULL to disable
  *   - multiple - bool
  *   - context - @see CRM_Core_DAO::buildOptionsContext
  * @param bool $required
  * @throws \CiviCRM_API3_Exception
  * @throws \Exception
  * @return HTML_QuickForm_Element
  */
 public function addField($name, $props = array(), $required = FALSE)
 {
     // Resolve context.
     if (empty($props['context'])) {
         $props['context'] = $this->getDefaultContext();
     }
     $context = $props['context'];
     // Resolve entity.
     if (empty($props['entity'])) {
         $props['entity'] = $this->getDefaultEntity();
     }
     // Resolve field.
     if (empty($props['name'])) {
         $props['name'] = strrpos($name, '[') ? rtrim(substr($name, 1 + strrpos($name, '[')), ']') : $name;
     }
     // Resolve action.
     if (empty($props['action'])) {
         $props['action'] = $this->getApiAction();
     }
     // Handle custom fields
     if (strpos($name, 'custom_') === 0 && is_numeric($name[7])) {
         $fieldId = (int) substr($name, 7);
         return CRM_Core_BAO_CustomField::addQuickFormElement($this, $name, $fieldId, $required, $context == 'search', CRM_Utils_Array::value('label', $props));
     }
     // Core field - get metadata.
     $fieldSpec = civicrm_api3($props['entity'], 'getfield', $props);
     $fieldSpec = $fieldSpec['values'];
     $label = CRM_Utils_Array::value('label', $props, isset($fieldSpec['title']) ? $fieldSpec['title'] : NULL);
     $widget = isset($props['type']) ? $props['type'] : $fieldSpec['html']['type'];
     if ($widget == 'TextArea' && $context == 'search') {
         $widget = 'Text';
     }
     $isSelect = in_array($widget, array('Select', 'CheckBoxGroup', 'RadioGroup', 'Radio'));
     if ($isSelect) {
         // Fetch options from the api unless passed explicitly.
         if (isset($props['options'])) {
             $options = $props['options'];
         } else {
             $options = isset($fieldSpec['options']) ? $fieldSpec['options'] : NULL;
         }
         if ($context == 'search') {
             $widget = 'Select';
             $props['multiple'] = CRM_Utils_Array::value('multiple', $props, TRUE);
         }
         // Add data for popup link.
         if ((!empty($props['option_url']) || !array_key_exists('option_url', $props)) && ($context != 'search' && $widget == 'Select' && CRM_Core_Permission::check('administer CiviCRM'))) {
             $props['data-option-edit-path'] = !empty($props['option_url']) ? $props['option_url'] : CRM_Core_PseudoConstant::getOptionEditUrl($fieldSpec);
             $props['data-api-entity'] = $props['entity'];
             $props['data-api-field'] = $props['name'];
         }
     }
     $props += CRM_Utils_Array::value('html', $fieldSpec, array());
     CRM_Utils_Array::remove($props, 'entity', 'name', 'context', 'label', 'action', 'type', 'option_url', 'options');
     // TODO: refactor switch statement, to separate methods.
     switch ($widget) {
         case 'Text':
         case 'Url':
         case 'Number':
         case 'Email':
             //TODO: Autodetect ranges
             $props['size'] = isset($props['size']) ? $props['size'] : 60;
             return $this->add(strtolower($widget), $name, $label, $props, $required);
         case 'hidden':
             return $this->add('hidden', $name, NULL, $props, $required);
         case 'TextArea':
             //Set default columns and rows for textarea.
             $props['rows'] = isset($props['rows']) ? $props['rows'] : 4;
             $props['cols'] = isset($props['cols']) ? $props['cols'] : 60;
             return $this->add('textarea', $name, $label, $props, $required);
         case 'Select Date':
             //TODO: add range support
             //TODO: Add date formats
             //TODO: Add javascript template for dates.
             return $this->addDate($name, $label, $required, $props);
         case 'Radio':
             $separator = isset($props['separator']) ? $props['separator'] : NULL;
             unset($props['separator']);
             if (!isset($props['allowClear'])) {
                 $props['allowClear'] = !$required;
             }
             return $this->addRadio($name, $label, $options, $props, $separator, $required);
         case 'ChainSelect':
             $props += array('required' => $required, 'label' => $label, 'multiple' => $context == 'search');
             return $this->addChainSelect($name, $props);
         case 'Select':
             $props['class'] = CRM_Utils_Array::value('class', $props, 'big') . ' crm-select2';
             if (!array_key_exists('placeholder', $props)) {
                 $props['placeholder'] = $required ? ts('- select -') : ($context == 'search' ? ts('- any -') : ts('- none -'));
             }
             // TODO: Add and/or option for fields that store multiple values
             return $this->add('select', $name, $label, $options, $required, $props);
         case 'CheckBoxGroup':
             return $this->addCheckBox($name, $label, array_flip($options), $required, $props);
         case 'RadioGroup':
             return $this->addRadio($name, $label, $options, $props, NULL, $required);
         case 'CheckBox':
             $text = isset($props['text']) ? $props['text'] : NULL;
             unset($props['text']);
             return $this->addElement('checkbox', $name, $label, $text, $props);
             //add support for 'Advcheckbox' field
         //add support for 'Advcheckbox' field
         case 'advcheckbox':
             $text = isset($props['text']) ? $props['text'] : NULL;
             unset($props['text']);
             return $this->addElement('advcheckbox', $name, $label, $text, $props);
         case 'File':
             // We should not build upload file in search mode.
             if ($context == 'search') {
                 return;
             }
             $file = $this->add('file', $name, $label, $props, $required);
             $this->addUploadElement($name);
             return $file;
         case 'RichTextEditor':
             return $this->add('wysiwyg', $name, $label, $props, $required);
         case 'EntityRef':
             return $this->addEntityRef($name, $label, $props, $required);
             // Check datatypes of fields
             // case 'Int':
             //case 'Float':
             //case 'Money':
             //case read only fields
         // Check datatypes of fields
         // case 'Int':
         //case 'Float':
         //case 'Money':
         //case read only fields
         default:
             throw new Exception("Unsupported html-element " . $widget);
     }
 }
Example #2
0
 /**
  * Adds a field based on metadata.
  *
  * @param $name
  *   Field name to go on the form.
  * @param array $props
  *   Mix of html attributes and special properties, namely.
  *   - entity (api entity name, can usually be inferred automatically from the form class)
  *   - name (field name - only needed if different from name used on the form)
  *   - option_url - path to edit this option list - usually retrieved automatically - set to NULL to disable link
  *   - placeholder - set to NULL to disable
  *   - multiple - bool
  *   - context - @see CRM_Core_DAO::buildOptionsContext
  * @param bool $required
  * @throws \CiviCRM_API3_Exception
  * @throws \Exception
  * @return HTML_QuickForm_Element
  */
 public function addField($name, $props = array(), $required = FALSE)
 {
     // TODO: Handle custom field
     if (strpos($name, 'custom_') === 0 && is_numeric($name[7])) {
         throw new Exception("Custom fields are not supported by the addField method. ");
     }
     // Resolve context.
     if (!isset($props['context'])) {
         $props['context'] = $this->getDefaultContext();
     }
     // Resolve entity.
     if (!isset($props['entity'])) {
         $props['entity'] = $this->getDefaultEntity();
     }
     // Resolve field.
     if (!isset($props['name'])) {
         $props['name'] = strrpos($name, '[') ? rtrim(substr($name, 1 + strrpos($name, '[')), ']') : $name;
     }
     // Resolve action.
     if (!isset($props['action'])) {
         $props['action'] = $this->getApiAction();
     }
     // Get field metadata.
     $fieldSpec = civicrm_api3($props['entity'], 'getfield', $props);
     $fieldSpec = $fieldSpec['values'];
     $label = CRM_Utils_Array::value('label', $props, isset($fieldSpec['title']) ? $fieldSpec['title'] : NULL);
     $widget = isset($props['type']) ? $props['type'] : $fieldSpec['html']['type'];
     if ($widget == 'TextArea' && $props['context'] == 'search') {
         $widget = 'Text';
     }
     $isSelect = in_array($widget, array('Select', 'Multi-Select', 'Select State/Province', 'Multi-Select State/Province', 'Select Country', 'Multi-Select Country', 'AdvMulti-Select', 'CheckBoxGroup', 'RadioGroup', 'Radio'));
     if ($isSelect) {
         // Fetch options from the api unless passed explicitly.
         if (isset($props['options'])) {
             $options = $props['options'];
             // Else this get passed to the form->add method.
             unset($props['options']);
         } else {
             $options = isset($fieldSpec['options']) ? $fieldSpec['options'] : NULL;
         }
         //@TODO AdvMulti-Select is deprecated, drop support.
         if ($props['context'] == 'search' || $widget !== 'AdvMulti-Select' && strpos($widget, 'Select') !== FALSE) {
             $widget = 'Select';
         }
         // Set default options-url value.
         if (!isset($props['options-url'])) {
             $props['options-url'] = TRUE;
         }
         // Add data for popup link.
         if (isset($props['options-url']) && $props['options-url'] && ($props['context'] != 'search' && $widget == 'Select' && CRM_Core_Permission::check('administer CiviCRM'))) {
             $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : ($props['data-option-edit-path'] = CRM_Core_PseudoConstant::getOptionEditUrl($fieldSpec));
             $props['data-api-entity'] = $props['entity'];
             $props['data-api-field'] = $props['name'];
             if (isset($props['options-url'])) {
                 unset($props['options-url']);
             }
         }
     }
     //Use select2 library for following widgets.
     $isSelect2 = in_array($widget, array('Select', 'Multi-Select', 'Select State/Province', 'Multi-Select State/Province', 'Select Country', 'Multi-Select Country'));
     if ($isSelect2) {
         $props['class'] = (isset($props['class']) ? $props['class'] . ' ' : '') . "crm-select2";
         if ($props['context'] == 'search' || strpos($widget, 'Multi') !== FALSE) {
             $props['class'] .= ' huge';
             $props['multiple'] = 'multiple';
         }
         // The placeholder is only used for select-elements.
         if (!array_key_exists('placeholder', $props)) {
             $props['placeholder'] = $required ? ts('- select -') : $props['context'] == 'search' ? ts('- any -') : ts('- none -');
         }
     }
     $props += CRM_Utils_Array::value('html', $fieldSpec, array());
     CRM_Utils_Array::remove($props, 'entity', 'name', 'context', 'label', 'action', 'type');
     // TODO: refactor switch statement, to separate methods.
     switch ($widget) {
         case 'Text':
         case 'Link':
             //TODO: Autodetect ranges
             $props['size'] = isset($props['size']) ? $props['size'] : 60;
             return $this->add('text', $name, $label, $props, $required);
         case 'hidden':
             return $this->add('hidden', $name, NULL, $props, $required);
         case 'TextArea':
             //Set default columns and rows for textarea.
             $props['rows'] = isset($props['rows']) ? $props['rows'] : 4;
             $props['cols'] = isset($props['cols']) ? $props['cols'] : 60;
             return $this->addElement('textarea', $name, $label, $props, $required);
         case 'Select Date':
             //TODO: add range support
             //TODO: Add date formats
             //TODO: Add javascript template for dates.
             return $this->addDate($name, $label, $required, $props);
         case 'Radio':
             $separator = isset($props['separator']) ? $props['separator'] : NULL;
             unset($props['separator']);
             if (!isset($props['allowClear'])) {
                 $props['allowClear'] = !$required;
             }
             return $this->addRadio($name, $label, $options, $props, $separator, $required);
         case 'Select':
             if (empty($props['multiple'])) {
                 $options = array('' => $props['placeholder']) + $options;
             }
             if (!empty($props['data-api-field']) && in_array($props['data-api-field'], array('state_province_id', 'county_id'))) {
                 return $this->addChainSelect($name, $props);
             }
             // TODO: Add and/or option for fields that store multiple values
             return $this->add('select', $name, $label, $options, $required, $props);
         case 'CheckBoxGroup':
             return $this->addCheckBox($name, $label, array_flip($options), $required, $props);
         case 'RadioGroup':
             return $this->addRadio($name, $label, $options, $props, NULL, $required);
             //case 'AdvMulti-Select':
         //case 'AdvMulti-Select':
         case 'CheckBox':
             $text = isset($props['text']) ? $props['text'] : NULL;
             unset($props['text']);
             return $this->addElement('checkbox', $name, $label, $text, $props);
         case 'File':
             // We should not build upload file in search mode.
             if (isset($props['context']) && $props['context'] == 'search') {
                 return;
             }
             $file = $this->add('file', $name, $label, $props, $required);
             $this->addUploadElement($name);
             return $file;
             //case 'RichTextEditor':
             //TODO: Add javascript template for wysiwyg.
         //case 'RichTextEditor':
         //TODO: Add javascript template for wysiwyg.
         case 'Autocomplete-Select':
         case 'EntityRef':
             return $this->addEntityRef($name, $label, $props, $required);
             // Check datatypes of fields
             // case 'Int':
             //case 'Float':
             //case 'Money':
             //case 'Link':
             //case read only fields
         // Check datatypes of fields
         // case 'Int':
         //case 'Float':
         //case 'Money':
         //case 'Link':
         //case read only fields
         default:
             throw new Exception("Unsupported html-element " . $widget);
     }
 }
Example #3
0
 /**
  * Adds a select based on field metadata.
  * TODO: This could be even more generic and widget type (select in this case) could also be read from metadata
  * Perhaps a method like $form->bind($name) which would look up all metadata for named field
  * @param $name
  *   Field name to go on the form.
  * @param array $props
  *   Mix of html attributes and special properties, namely.
  *   - entity (api entity name, can usually be inferred automatically from the form class)
  *   - field (field name - only needed if different from name used on the form)
  *   - option_url - path to edit this option list - usually retrieved automatically - set to NULL to disable link
  *   - placeholder - set to NULL to disable
  *   - multiple - bool
  *   - context - @see CRM_Core_DAO::buildOptionsContext
  * @param bool $required
  * @throws CRM_Core_Exception
  * @return HTML_QuickForm_Element
  */
 public function addSelect($name, $props = array(), $required = FALSE)
 {
     if (!isset($props['entity'])) {
         $props['entity'] = CRM_Utils_Api::getEntityName($this);
     }
     if (!isset($props['field'])) {
         $props['field'] = strrpos($name, '[') ? rtrim(substr($name, 1 + strrpos($name, '[')), ']') : $name;
     }
     // Fetch options from the api unless passed explicitly
     if (isset($props['options'])) {
         $options = $props['options'];
     } else {
         $info = civicrm_api3($props['entity'], 'getoptions', $props);
         $options = $info['values'];
     }
     if (!array_key_exists('placeholder', $props)) {
         $props['placeholder'] = $required ? ts('- select -') : CRM_Utils_Array::value('context', $props) == 'search' ? ts('- any -') : ts('- none -');
     }
     // Handle custom field
     if (strpos($name, 'custom_') === 0 && is_numeric($name[7])) {
         list(, $id) = explode('_', $name);
         $label = isset($props['label']) ? $props['label'] : CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', 'label', $id);
         $gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', 'option_group_id', $id);
         if (CRM_Utils_Array::value('context', $props) != 'search') {
             $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $gid);
         }
     } else {
         $info = civicrm_api3($props['entity'], 'getfields');
         foreach ($info['values'] as $uniqueName => $fieldSpec) {
             if ($uniqueName === $props['field'] || CRM_Utils_Array::value('name', $fieldSpec) === $props['field'] || in_array($props['field'], CRM_Utils_Array::value('api.aliases', $fieldSpec, array()))) {
                 break;
             }
         }
         $label = isset($props['label']) ? $props['label'] : $fieldSpec['title'];
         if (CRM_Utils_Array::value('context', $props) != 'search') {
             $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : ($props['data-option-edit-path'] = CRM_Core_PseudoConstant::getOptionEditUrl($fieldSpec));
         }
     }
     $props['class'] = (isset($props['class']) ? $props['class'] . ' ' : '') . "crm-select2";
     $props['data-api-entity'] = $props['entity'];
     $props['data-api-field'] = $props['field'];
     CRM_Utils_Array::remove($props, 'label', 'entity', 'field', 'option_url', 'options', 'context');
     return $this->add('select', $name, $label, $options, $required, $props);
 }