Merge pull request #14706 from ixiam/dev-SmartyCompiled
[civicrm-core.git] / CRM / Contact / Import / Parser.php
index ec054e8688b8af8438491f1f5ecbee841544641f..c8cfc0a84f82e9ead67314306b95a1cc45a58957 100644 (file)
@@ -37,18 +37,20 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
   /**
    * Total number of lines in file
    *
-   * @var integer
+   * @var int
    */
   protected $_rowCount;
 
   /**
    * Running total number of un-matched Contacts.
+   *
    * @var int
    */
   protected $_unMatchCount;
 
   /**
-   * Array of unmatched lines
+   * Array of unmatched lines.
+   *
    * @var array
    */
   protected $_unMatch;
@@ -69,6 +71,7 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
   protected $_primaryKeyName;
   protected $_statusFieldName;
 
+  protected $fieldMetadata = [];
   /**
    * On duplicate
    *
@@ -846,7 +849,13 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
           }
 
           if (!$break) {
-            $this->formatContactParameters($value, $formatted);
+            if (!empty($value['location_type_id'])) {
+              $this->formatLocationBlock($value, $formatted);
+            }
+            else {
+              CRM_Core_Error::deprecatedFunctionWarning('this is not expected to be reachable now');
+              $this->formatContactParameters($value, $formatted);
+            }
           }
         }
         if (!$isAddressCustomField) {
@@ -1129,7 +1138,8 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
 
     // get the formatted location blocks into params - w/ 3.0 format, CRM-4605
     if (!empty($values['location_type_id'])) {
-      return $this->formatLocationBlock($values, $params, $fields);
+      CRM_Core_Error::deprecatedFunctionWarning('this is not expected to be reachable now');
+      return $this->formatLocationBlock($values, $params);
     }
 
     if (isset($values['note'])) {
@@ -1188,14 +1198,10 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
    *
    * @param array $values
    * @param array $params
-   * @param array $fields
    *
    * @return bool
    */
-  protected function formatLocationBlock(&$values, &$params, $fields) {
-    if (empty($values['location_type_id'])) {
-      return FALSE;
-    }
+  protected function formatLocationBlock(&$values, &$params) {
     $blockTypes = [
       'phone' => 'Phone',
       'email' => 'Email',
@@ -1213,12 +1219,7 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
         $params[$blockFieldName] = [];
       }
 
-      if (!array_key_exists($block, $fields)) {
-        $className = "CRM_Core_DAO_$block";
-        $fields[$block] = $className::fields();
-      }
-
-      $blockCnt = count($params[$blockFieldName]);
+      $fields[$block] = $this->getMetadataForEntity($block);
 
       // copy value to dao field name.
       if ($blockFieldName == 'im') {
@@ -1226,25 +1227,13 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       }
 
       _civicrm_api3_store_values($fields[$block], $values,
-        $params[$blockFieldName][++$blockCnt]
+        $params[$blockFieldName][$values['location_type_id']]
       );
 
-      if ($values['location_type_id'] === 'Primary') {
-        if (!empty($params['id'])) {
-          $primary = civicrm_api3($block, 'get', [
-            'return' => 'location_type_id',
-            'contact_id' => $params['id'],
-            'is_primary' => 1,
-            'sequential' => 1
-          ]);
-        }
-        $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
-        $values['location_type_id'] = (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
-        $values['is_primary'] = 1;
-      }
+      $this->fillPrimary($params[$blockFieldName][$values['location_type_id']], $values, $block, CRM_Utils_Array::value('id', $params));
 
-      if (empty($params['id']) && ($blockCnt == 1)) {
-        $params[$blockFieldName][$blockCnt]['is_primary'] = TRUE;
+      if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
+        $params[$blockFieldName][$values['location_type_id']]['is_primary'] = TRUE;
       }
 
       // we only process single block at a time.
@@ -1256,10 +1245,6 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       $params['address'] = [];
     }
 
-    if (!array_key_exists('Address', $fields)) {
-      $fields['Address'] = CRM_Core_DAO_Address::fields();
-    }
-
     // Note: we doing multiple value formatting here for address custom fields, plus putting into right format.
     // The actual formatting (like date, country ..etc) for address custom fields is taken care of while saving
     // the address in CRM_Core_BAO_Address::create method
@@ -1273,8 +1258,6 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       foreach ($values as $key => $val) {
         $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key);
         if ($customFieldID && array_key_exists($customFieldID, $customFields)) {
-          // mark an entry in fields array since we want the value of custom field to be copied
-          $fields['Address'][$key] = NULL;
 
           $htmlType = CRM_Utils_Array::value('html_type', $customFields[$customFieldID]);
           switch ($htmlType) {
@@ -1307,6 +1290,8 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       $values = $newValues;
     }
 
+    $fields['Address'] = $this->getMetadataForEntity('Address');
+    // @todo this is kinda replicated below....
     _civicrm_api3_store_values($fields['Address'], $values, $params['address'][$values['location_type_id']]);
 
     $addressFields = [
@@ -1318,6 +1303,9 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       'supplemental_address_3',
       'StateProvince.name',
     ];
+    foreach (array_keys($customFields) as $customFieldID) {
+      $addressFields[] = 'custom_' . $customFieldID;
+    }
 
     foreach ($addressFields as $field) {
       if (array_key_exists($field, $values)) {
@@ -1328,21 +1316,55 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       }
     }
 
+    $this->fillPrimary($params['address'][$values['location_type_id']], $values, 'address', CRM_Utils_Array::value('id', $params));
+    return TRUE;
+  }
+
+  /**
+   * Get the field metadata for the relevant entity.
+   *
+   * @param string $entity
+   *
+   * @return array
+   */
+  protected function getMetadataForEntity($entity) {
+    if (!isset($this->fieldMetadata[$entity])) {
+      $className = "CRM_Core_DAO_$entity";
+      $this->fieldMetadata[$entity] = $className::fields();
+    }
+    return $this->fieldMetadata[$entity];
+  }
+
+  /**
+   * Fill in the primary location.
+   *
+   * If the contact has a primary address we update it. Otherwise
+   * we add an address of the default location type.
+   *
+   * @param array $params
+   *   Address block parameters
+   * @param array $values
+   *   Input values
+   * @param string $entity
+   *  - address, email, phone
+   * @param int|null $contactID
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  protected function fillPrimary(&$params, $values, $entity, $contactID) {
     if ($values['location_type_id'] === 'Primary') {
-      if (!empty($params['id'])) {
-        $primary = civicrm_api3('Address', 'get', [
+      if ($contactID) {
+        $primary = civicrm_api3($entity, 'get', [
           'return' => 'location_type_id',
-          'contact_id' => $params['id'],
+          'contact_id' => $contactID,
           'is_primary' => 1,
-          'sequential' => 1
+          'sequential' => 1,
         ]);
       }
       $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
-      $params['address'][$values['location_type_id']]['location_type_id'] = (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
-      $params['address'][$values['location_type_id']]['is_primary'] = 1;
-
+      $params['location_type_id'] = (int) (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
+      $params['is_primary'] = 1;
     }
-    return TRUE;
   }
 
 }