Merge pull request #14840 from MegaphoneJon/core-1130
[civicrm-core.git] / CRM / Core / BAO / UFField.php
index 37ee29e17aeceeef784817e13befe0a834545281..4549d78d3b0a1f5963dc5dcffaa611c75ed47f0e 100644 (file)
@@ -38,6 +38,7 @@ class CRM_Core_BAO_UFField extends CRM_Core_DAO_UFField {
 
   /**
    * Batch entry fields.
+   * @var array
    */
   private static $_contriBatchEntryFields = NULL;
   private static $_memberBatchEntryFields = NULL;
@@ -51,91 +52,79 @@ class CRM_Core_BAO_UFField extends CRM_Core_DAO_UFField {
    * @return \CRM_Core_BAO_UFField
    * @throws \API_Exception
    */
-  public static function create(&$params) {
-    // CRM-14756: kind of a hack-ish fix. If the user gives the id, uf_group_id is retrieved and then set.
-    if (isset($params['id'])) {
-      $groupId = civicrm_api3('UFField', 'getvalue', [
-        'return' => 'uf_group_id',
-        'id' => $params['id'],
-      ]);
-    }
-    else {
-      $groupId = CRM_Utils_Array::value('uf_group_id', $params);
-    }
+  public static function create($params) {
+    $id = CRM_Utils_Array::value('id', $params);
 
-    $field_name = CRM_Utils_Array::value('field_name', $params);
+    // Merge in data from existing field
+    if (!empty($id)) {
+      $UFField = new CRM_Core_BAO_UFField();
+      $UFField->id = $params['id'];
+      if ($UFField->find(TRUE)) {
+        $defaults = $UFField->toArray();
+        // This will be calculated based on field name
+        unset($defaults['field_type']);
+        $params += $defaults;
+      }
+      else {
+        throw new API_Exception("UFFIeld id {$params['id']} not found.");
+      }
+    }
 
-    if (strpos($field_name, 'formatting') !== 0 && !CRM_Core_BAO_UFField::isValidFieldName($field_name)) {
+    // Validate field_name
+    if (strpos($params['field_name'], 'formatting') !== 0 && !CRM_Core_BAO_UFField::isValidFieldName($params['field_name'])) {
       throw new API_Exception('The field_name is not valid');
     }
 
-    if (!(CRM_Utils_Array::value('group_id', $params))) {
-      $params['group_id'] = $groupId;
+    // Supply default label if not set
+    if (empty($id) && !isset($params['label'])) {
+      $params['label'] = self::getAvailableFieldTitles()[$params['field_name']];
     }
 
-    $fieldId = CRM_Utils_Array::value('id', $params);
-    if (!empty($fieldId)) {
-      $UFField = new CRM_Core_BAO_UFField();
-      $UFField->id = $fieldId;
-      if ($UFField->find(TRUE)) {
-        if (!(CRM_Utils_Array::value('group_id', $params))) {
-          // this copied here from previous api function - not sure if required
-          $params['group_id'] = $UFField->uf_group_id;
-        }
-      }
-      else {
-        throw new API_Exception("there is no field for this fieldId");
-      }
+    // Supply field_type if not set
+    if (empty($params['field_type']) && strpos($params['field_name'], 'formatting') !== 0) {
+      $params['field_type'] = CRM_Utils_Array::pathGet(self::getAvailableFieldsFlat(), [$params['field_name'], 'field_type']);
+    }
+    elseif (empty($params['field_type'])) {
+      $params['field_type'] = 'Formatting';
     }
-    $params['uf_group_id'] = $params['group_id'];
 
-    if (CRM_Core_BAO_UFField::duplicateField($params)) {
+    // Generate unique name for formatting fields
+    if ($params['field_name'] === 'formatting') {
+      $params['field_name'] = 'formatting_' . substr(uniqid(), -4);
+    }
+
+    if (self::duplicateField($params)) {
       throw new API_Exception("The field was not added. It already exists in this profile.");
     }
 
-    // @todo fix BAO to be less weird.
-    $field_type       = CRM_Utils_Array::value('field_type', $params);
-    $location_type_id = CRM_Utils_Array::value('location_type_id', $params, CRM_Utils_Array::value('website_type_id', $params));
-    $phone_type       = CRM_Utils_Array::value('phone_type_id', $params, CRM_Utils_Array::value('phone_type', $params));
-    $params['field_name'] = [$field_type, $field_name, $location_type_id, $phone_type];
     //@todo why is this even optional? Surely weight should just be 'managed' ??
     if (CRM_Utils_Array::value('option.autoweight', $params, TRUE)) {
       $params['weight'] = CRM_Core_BAO_UFField::autoWeight($params);
     }
-    // set values for uf field properties and save
+
+    // Set values for uf field properties and save
     $ufField = new CRM_Core_DAO_UFField();
     $ufField->copyValues($params);
-    $ufField->field_type = $params['field_name'][0];
-    $ufField->field_name = $params['field_name'][1];
 
-    //should not set location type id for Primary
-    $locationTypeId = NULL;
-    if ($params['field_name'][1] == 'url') {
-      $ufField->website_type_id = CRM_Utils_Array::value(2, $params['field_name']);
+    if ($params['field_name'] == 'url') {
+      $ufField->location_type_id = 'null';
     }
     else {
-      $locationTypeId = CRM_Utils_Array::value(2, $params['field_name']);
-      $ufField->website_type_id = NULL;
+      $ufField->website_type_id = 'null';
     }
-    if ($locationTypeId) {
-      $ufField->location_type_id = $locationTypeId;
+    if (!strstr($params['field_name'], 'phone')) {
+      $ufField->phone_type_id = 'null';
     }
-    else {
-      $ufField->location_type_id = 'null';
-    }
-
-    $ufField->phone_type_id = CRM_Utils_Array::value(3, $params['field_name'], 'NULL');
 
     $ufField->save();
 
-    $fieldsType = CRM_Core_BAO_UFGroup::calculateGroupType($groupId, TRUE);
-    CRM_Core_BAO_UFGroup::updateGroupTypes($groupId, $fieldsType);
+    $fieldsType = CRM_Core_BAO_UFGroup::calculateGroupType($ufField->uf_group_id, TRUE);
+    CRM_Core_BAO_UFGroup::updateGroupTypes($ufField->uf_group_id, $fieldsType);
 
     civicrm_api3('profile', 'getfields', ['cache_clear' => TRUE]);
     return $ufField;
   }
 
-
   /**
    * Fetch object based on array of properties.
    *
@@ -204,8 +193,8 @@ class CRM_Core_BAO_UFField extends CRM_Core_DAO_UFField {
   public static function duplicateField($params) {
     $ufField = new CRM_Core_DAO_UFField();
     $ufField->uf_group_id = CRM_Utils_Array::value('uf_group_id', $params);
-    $ufField->field_type = $params['field_type'];
-    $ufField->field_name = $params['field_name'];
+    $ufField->field_type = CRM_Utils_Array::value('field_type', $params);
+    $ufField->field_name = CRM_Utils_Array::value('field_name', $params);
     $ufField->website_type_id = CRM_Utils_Array::value('website_type_id', $params);
     if (is_null(CRM_Utils_Array::value('location_type_id', $params, ''))) {
       // primary location type have NULL value in DB
@@ -220,7 +209,7 @@ class CRM_Core_BAO_UFField extends CRM_Core_DAO_UFField {
       $ufField->whereAdd("id <> " . $params['id']);
     }
 
-    return ($ufField->find(TRUE) ? 1 : 0);
+    return (bool) $ufField->find(TRUE);
   }
 
   /**
@@ -280,10 +269,10 @@ WHERE cf.id IN (" . $customFieldIds . ") AND is_multiple = 1 LIMIT 0,1";
     // fix for CRM-316
     $oldWeight = NULL;
 
-    if (!empty($params['field_id'])) {
-      $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', $params['field_id'], 'weight', 'id');
+    if (!empty($params['field_id']) || !empty($params['id'])) {
+      $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', !empty($params['id']) ? $params['id'] : $params['field_id'], 'weight', 'id');
     }
-    $fieldValues = ['uf_group_id' => $params['group_id']];
+    $fieldValues = ['uf_group_id' => !empty($params['uf_group_id']) ? $params['uf_group_id'] : $params['group_id']];
     return CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_UFField', $oldWeight, CRM_Utils_Array::value('weight', $params, 0), $fieldValues);
   }
 
@@ -1061,24 +1050,33 @@ SELECT  id
    *
    * @param bool $force
    *
-   * @return array, multidimensional; e.g. $result['field_name']['label']
+   * @return array
+   *   e.g. $result['field_name']['label']
    */
   public static function getAvailableFieldsFlat($force = FALSE) {
-    // FIXME reset when data model changes
-    static $result = NULL;
-    if ($result === NULL || $force) {
-      $fieldTree = self::getAvailableFields();
-      $result = [];
-      foreach ($fieldTree as $field_type => $fields) {
-        foreach ($fields as $field_name => $field) {
-          if (!isset($result[$field_name])) {
-            $field['field_type'] = $field_type;
-            $result[$field_name] = $field;
+    if (!isset(Civi::$statics['UFFieldsFlat']) || $force) {
+      Civi::$statics['UFFieldsFlat'] = [];
+      foreach (self::getAvailableFields() as $fieldType => $fields) {
+        foreach ($fields as $fieldName => $field) {
+          if (!isset(Civi::$statics['UFFieldsFlat'][$fieldName])) {
+            $field['field_type'] = $fieldType;
+            Civi::$statics['UFFieldsFlat'][$fieldName] = $field;
           }
         }
       }
     }
-    return $result;
+    return Civi::$statics['UFFieldsFlat'];
+  }
+
+  /**
+   * Get a list of fields which can be added to profiles in the format [name => title]
+   *
+   * @return array
+   */
+  public static function getAvailableFieldTitles() {
+    $fields = self::getAvailableFieldsFlat();
+    $fields['formatting'] = ['title' => ts('Formatting')];
+    return CRM_Utils_Array::collect('title', $fields);
   }
 
   /**