CRM-14165 - Add metadata-based quickform select
authorColeman Watts <coleman@civicrm.org>
Tue, 4 Feb 2014 04:41:19 +0000 (20:41 -0800)
committerColeman Watts <coleman@civicrm.org>
Tue, 4 Feb 2014 04:41:19 +0000 (20:41 -0800)
CRM/Activity/Form/Activity.php
CRM/Core/DAO.php
CRM/Core/Form.php
CRM/Core/Form/Renderer.php
CRM/Core/PseudoConstant.php

index 556e7016a222dace280d844e7e7cb6627d626de2..f4b28b9df9ae8d3a44c7b9c7c16be41e29383e95 100644 (file)
@@ -721,10 +721,7 @@ class CRM_Activity_Form_Activity extends CRM_Contact_Form_Task {
       CRM_Campaign_BAO_Campaign::accessCampaign()
     ) {
       $buildEngagementLevel = TRUE;
-      $this->add('select', 'engagement_level',
-        ts('Engagement Index'),
-        array('' => ts('- select -')) + CRM_Campaign_PseudoConstant::engagementLevel()
-      );
+      $this->addSelect('CRM_Activity_BAO_Activity', 'engagement_level');
       $this->addRule('engagement_level',
         ts('Please enter the engagement index as a number (integers only).'),
         'positiveInteger'
index 86f29ce35969b1c5de7a67f9f7f361020faac721..33346c19a1778d65cad6009d071526a8e4fa4ffc 100644 (file)
@@ -1841,6 +1841,26 @@ EOS;
     return $contexts;
   }
 
+  /**
+   * @param $fieldName
+   * @return bool|array
+   */
+  function getFieldSpec($fieldName) {
+    $fields = $this->fields();
+    $fieldKeys = $this->fieldKeys();
+
+    // Support "unique names" as well as sql names
+    $fieldKey = $fieldName;
+    if (empty($fields[$fieldKey])) {
+      $fieldKey = CRM_Utils_Array::value($fieldName, $fieldKeys);
+    }
+    // If neither worked then this field doesn't exist. Return false.
+    if (empty($fields[$fieldKey])) {
+      return FALSE;
+    }
+    return $fields[$fieldKey];
+  }
+
   /**
    * SQL version of api function to assign filters to the DAO based on the syntax
    * $field => array('IN' => array(4,6,9))
index 59997b62adb9fe0be1eaff335554316584ed6978..8b20d5c652df3684f973c47977f5f7197807ef7e 100644 (file)
@@ -901,25 +901,47 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     }
   }
 
-  function addSelect($name, $label, $prefix = NULL, $required = NULL, $extra = NULL, $select = '- select -') {
-    if ($prefix) {
-      $this->addElement('select', $name . '_id' . $prefix, $label,
-        array(
-          '' => $select) + CRM_Core_OptionGroup::values($name), $extra
-      );
-      if ($required) {
-        $this->addRule($name . '_id' . $prefix, ts('Please select %1', array(1 => $label)), 'required');
-      }
+  /**
+   * 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
+   * @param CRM_Core_DAO $baoName - string representing bao object
+   * @param $name
+   * @param array $props
+   * @param bool $required
+   * @throws CRM_Core_Exception
+   * @return HTML_QuickForm_Element
+   */
+  function addSelect($baoName, $name, $props = array(), $required = FALSE) {
+    $options = $baoName::buildOptions($name, 'create');
+    if ($options === FALSE) {
+      throw new CRM_Core_Exception('No option list for field ' . $name);
     }
+    if (!array_key_exists('placeholder', $props)) {
+      $props['placeholder'] = $required ? ts('- select -') : ts('- none -');
+    }
+    if (!empty($props['placeholder']) && empty($props['multiple'])) {
+      $options = array('' => '') + $options;
+    }
+    // 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);
+      $props['data-option-group'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', 'option_group_id', $id);
+    }
+    // Core field
     else {
-      $this->addElement('select', $name . '_id', $label,
-        array(
-          '' => $select) + CRM_Core_OptionGroup::values($name), $extra
-      );
-      if ($required) {
-        $this->addRule($name . '_id', ts('Please select %1', array(1 => $label)), 'required');
+      $bao = new $baoName;
+      $meta = $bao->getFieldSpec($name);
+      $bao->free();
+      // Todo: localize
+      $label = CRM_Utils_Array::value('label', $props, $meta['title']);
+      if (!empty($meta['pseudoconstant']['optionGroupName'])) {
+        $props['data-option-group'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $meta['pseudoconstant']['optionGroupName'], 'id', 'name');
       }
     }
+    $props['class'] = isset($props['class']) ? $props['class'] . ' ' : '';
+    $props['class'] .= "crm-select2";
+    return $this->add('select', $name, $label, $options, $required, $props);
   }
 
   /**
@@ -1289,6 +1311,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
           $val = str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($val, CRM_Core_DAO::VALUE_SEPARATOR));
           $field->setValue($val);
         }
+        // TODO: we could fetch multiple values with array(IN => $val) but not all apis support this
         foreach (explode(',', $val) as $v) {
           $result = civicrm_api3($api['entity'], $api['action'], array('sequential' => 1, $api['key'] => $v));
           if (!empty($result['values'])) {
index 17276b44c31110f4a9e142464a30f3f9f5499146..bc15901d886e484f20d6928c3ccdd1a56b784548 100644 (file)
@@ -117,6 +117,10 @@ class CRM_Core_Form_Renderer extends HTML_QuickForm_Renderer_ArraySmarty {
       }
     }
 
+    if ($element->getType() == 'select' && $element->getAttribute('data-option-group')) {
+      $this->addOptionsEditLink($el, $element);
+    }
+
     if (!empty($el['frozen'])) {
       if ($element->getAttribute('data-api-params') && $element->getAttribute('data-entity-value')) {
         $this->renderFrozenEntityRef($el, $element);
@@ -205,6 +209,16 @@ class CRM_Core_Form_Renderer extends HTML_QuickForm_Renderer_ArraySmarty {
 
     $el['html'] = implode('; ', $display) . '<input type="hidden" value="'. $field->getValue() . '" name="' . $field->getAttribute('name') . '">';
   }
+
+  /**
+   * @param array $el
+   * @param HTML_QuickForm_element $field
+   */
+  function addOptionsEditLink(&$el, $field) {
+    if (CRM_Core_Permission::check('administer CiviCRM')) {
+      $el['html'] .= ' &nbsp; <a href="#" class="crm-edit-optionvalue-link" title="' . ts('Edit Options') . '" data-option-group="' . $field->getAttribute('data-option-group') . '"><span class="batch-edit"></span></a>';
+    }
+  }
 }
 // end CRM_Core_Form_Renderer
 
index 321a6e85522fb73bea7e481c6b58906b71fa1116..8bbf859247bdc1f48890aa6c404cf2fd8240e4fb 100644 (file)
@@ -222,7 +222,7 @@ class CRM_Core_PseudoConstant {
    * - fresh      boolean ignore cache entries and go back to DB
    * @param String $context: Context string
    *
-   * @return Array on success, FALSE on error.
+   * @return Array|bool - array on success, FALSE on error.
    *
    * @static
    */
@@ -276,20 +276,12 @@ class CRM_Core_PseudoConstant {
 
     // Core field: load schema
     $dao = new $daoName;
-    $fields = $dao->fields();
-    $fieldKeys = $dao->fieldKeys();
+    $fieldSpec = $dao->getFieldSpec($fieldName);
     $dao->free();
-
-    // Support "unique names" as well as sql names
-    $fieldKey = $fieldName;
-    if (empty($fields[$fieldKey])) {
-      $fieldKey = CRM_Utils_Array::value($fieldName, $fieldKeys);
-    }
     // If neither worked then this field doesn't exist. Return false.
-    if (empty($fields[$fieldKey])) {
+    if (empty($fieldSpec)) {
       return FALSE;
     }
-    $fieldSpec = $fields[$fieldKey];
 
     // If the field is an enum, explode the enum definition and return the array.
     if (isset($fieldSpec['enumValues'])) {