CRM-13966 - Add method to Core_Form for contactRef fields
[civicrm-core.git] / CRM / Core / Form.php
index a645499491f41e09f9efd1eed7445c3bc86e68b0..c604f97c563a6917c2acd0bd71824d33aedef71e 100644 (file)
@@ -105,6 +105,14 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
    */
   public $ajaxResponse = array();
 
+  /**
+   * Stores info about reference fields for preprocessing
+   * Public so that hooks can access it
+   *
+   * @var array
+   */
+  public $entityReferenceFields = array();
+
   /**
    * constants for attributes for various form elements
    * attempt to standardize on the number of variations that we
@@ -208,7 +216,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
    *               These are not default values
    * @param bool   is this a required field
    *
-   * @return object    html element, could be an error object
+   * @return HTML_QuickForm_Element could be an error object
    * @access public
    *
    */
@@ -399,6 +407,8 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     // the user can do both the form and set default values with this hook
     CRM_Utils_Hook::buildForm(get_class($this), $this);
 
+    $this->preprocessReferenceFields();
+
     $this->addRules();
   }
 
@@ -1196,6 +1206,88 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     $this->setDefaults(array($name => $defaultCurrency));
   }
 
+  /**
+   * Create a single or multiple contact ref field
+   * @param string $name
+   * @param string $label
+   * @param array $props mix of html and widget properties, including:
+   *   - required
+   *   - select - params to give to select2, notably "multiple"
+   *   - api - array of data for the api, keys include "entity", "action", "params", "search", "key", "label"
+   * @return HTML_QuickForm_Element
+   */
+  function addContactRef($name, $label, $props = array(), $required = FALSE) {
+    $props['class'] = isset($props['class']) ? $props['class'] . ' crm-select2' : 'crm-select2';
+
+    $props['select'] = CRM_Utils_Array::value('select', $props, array()) + array(
+      'minimumInputLength' => 1,
+      'multiple' => !empty($props['multiple']),
+      'placeholder' => CRM_Utils_Array::value('placeholder', $props, $required ? ts('- select -') : ts('- none -')),
+      'allowClear' => !$required,
+      // Disabled pending https://github.com/ivaynberg/select2/pull/2092
+      //'formatInputTooShort' => ts('Start typing a name or email address...'),
+      //'formatNoMatches' => ts('No contacts found.'),
+    );
+
+    $props['api'] = CRM_Utils_Array::value('api', $props, array()) + array(
+      'entity' => 'contact',
+      'action' => 'getquick',
+      'search' => 'name',
+      'label' => 'data',
+      'key' => 'id',
+    );
+
+    $this->entityReferenceFields[$name] = $props;
+    $this->formatReferenceFieldAttributes($props);
+    return $this->add('text', $name, $label, $props, $required);
+  }
+
+  /**
+   * @param $props
+   */
+  private function formatReferenceFieldAttributes(&$props) {
+    $props['data-select-params'] = json_encode($props['select']);
+    $props['data-api-params'] = json_encode($props['api']);
+    CRM_Utils_Array::remove($props, 'multiple', 'select', 'api');
+  }
+
+  private function preprocessReferenceFields() {
+    foreach ($this->entityReferenceFields as $name => $props) {
+      $val = $this->getElementValue($name);
+      $field = $this->getElement($name);
+      // Support array values
+      if (is_array($val)) {
+        $val = implode(',', $val);
+        $field->setValue($val);
+      }
+      if ($val) {
+        $data = $labels = array();
+        // Support serialized values
+        if (strpos($val, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) {
+          $val = str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($val, CRM_Core_DAO::VALUE_SEPARATOR));
+          $field->setValue($val);
+        }
+        foreach (explode(',', $val) as $v) {
+          $result = civicrm_api3($props['api']['entity'], $props['api']['action'], array('sequential' => 1, $props['api']['key'] => $v));
+          if (!empty($result['values'])) {
+            $data[] = array('id' => $v, 'text' => $result['values'][0][$props['api']['label']]);
+            $labels[] = $result['values'][0][$props['api']['label']];
+          }
+        }
+        if ($field->isFrozen()) {
+          $field->removeAttribute('class');
+          $field->setValue(implode(', ', $labels));
+        }
+        elseif ($data) {
+          if (empty($props['select']['multiple'])) {
+            $data = $data[0];
+          }
+          $field->setAttribute('data-entity-value', json_encode($data));
+        }
+      }
+    }
+  }
+
   /**
    * Convert all date fields within the params to mysql date ready for the
    * BAO layer. In this case fields are checked against the $_datefields defined for the form