Merge pull request #23227 from eileenmcnaughton/inbetween_4
authorcolemanw <coleman@civicrm.org>
Sun, 17 Apr 2022 23:02:19 +0000 (19:02 -0400)
committerGitHub <noreply@github.com>
Sun, 17 Apr 2022 23:02:19 +0000 (19:02 -0400)
[REF] [Import] Remove last in-between parser class

75 files changed:
.toxic.json
CRM/Activity/Import/Form/Preview.php
CRM/Activity/Import/Form/Summary.php
CRM/Activity/Import/Parser.php [deleted file]
CRM/Activity/Import/Parser/Activity.php
CRM/Contact/BAO/RelationshipType.php
CRM/Contact/Import/Form/DataSource.php
CRM/Contact/Import/Form/MapField.php
CRM/Contact/Import/Form/Preview.php
CRM/Contact/Import/Form/Summary.php
CRM/Contact/Import/ImportJob.php
CRM/Contact/Import/Parser.php [deleted file]
CRM/Contact/Import/Parser/Contact.php
CRM/Core/BAO/Job.php
CRM/Core/BAO/UserJob.php [new file with mode: 0644]
CRM/Core/DAO/AllCoreTables.data.php
CRM/Core/DAO/UserJob.php [new file with mode: 0644]
CRM/Custom/Import/Parser.php
CRM/Custom/Import/Parser/Api.php
CRM/Event/Form/Registration/Confirm.php
CRM/Member/Form/MembershipView.php
CRM/Member/Form/Task/Label.php
CRM/Upgrade/Incremental/sql/5.50.alpha1.mysql.tpl
Civi/Api4/UserJob.php [new file with mode: 0644]
Civi/Core/Container.php
Civi/Crypto/CryptoRegistry.php
templates/CRM/ACL/Page/EntityRole.tpl
templates/CRM/Activity/Form/Selector.tpl
templates/CRM/Activity/Selector/Activity.tpl
templates/CRM/Admin/Page/Access.tpl
templates/CRM/Admin/Page/ContactType.tpl
templates/CRM/Admin/Page/EventTemplate.tpl
templates/CRM/Admin/Page/Extensions/AddNew.tpl
templates/CRM/Admin/Page/Extensions/Main.tpl
templates/CRM/Admin/Page/Job.tpl
templates/CRM/Admin/Page/LabelFormats.tpl
templates/CRM/Admin/Page/LocationType.tpl
templates/CRM/Admin/Page/MailSettings.tpl
templates/CRM/Admin/Page/Mapping.tpl
templates/CRM/Admin/Page/MessageTemplates.tpl
templates/CRM/Admin/Page/Options.tpl
templates/CRM/Admin/Page/ParticipantStatusType.tpl
templates/CRM/Admin/Page/PaymentProcessor.tpl
templates/CRM/Admin/Page/PdfFormats.tpl
templates/CRM/Admin/Page/PreferencesDate.tpl
templates/CRM/Admin/Page/RelationshipType.tpl
templates/CRM/Admin/Page/Reminders.tpl
templates/CRM/Badge/Page/Layout.tpl
templates/CRM/Campaign/Page/SurveyType.tpl
templates/CRM/Case/Page/Tab.tpl
templates/CRM/Contact/Page/DedupeRules.tpl
templates/CRM/Contribute/Page/ContributionType.tpl
templates/CRM/Contribute/Page/ManagePremiums.tpl
templates/CRM/Contribute/Page/Tab.tpl
templates/CRM/Event/Page/Tab.tpl
templates/CRM/Financial/Page/FinancialAccount.tpl
templates/CRM/Financial/Page/FinancialType.tpl
templates/CRM/Financial/Page/FinancialTypeAccount.tpl
templates/CRM/Group/Form/Edit.tpl
templates/CRM/Group/Page/GroupRows.tpl
templates/CRM/Mailing/Page/Browse.tpl
templates/CRM/Mailing/Page/Component.tpl
templates/CRM/Member/Page/MembershipStatus.tpl
templates/CRM/Member/Page/MembershipType.tpl
templates/CRM/PCP/Page/PCP.tpl
templates/CRM/Price/Page/Field.tpl
templates/CRM/Price/Page/Option.tpl
templates/CRM/Price/Page/Set.tpl
templates/CRM/SMS/Page/Provider.tpl
templates/CRM/UF/Page/Field.tpl
templates/CRM/UF/Page/Group.tpl
tests/phpunit/CRM/Dedupe/MergerTest.php
tests/phpunit/E2E/Extern/CliRunnerTest.php
xml/schema/Core/UserJob.xml [new file with mode: 0644]
xml/schema/Core/files.xml

index f5f5c6fb2781baaf9e98c432112c0da8efdc6269..3886591fd1110dc7e88a1fed7ab3e2b713cc325e 100644 (file)
@@ -14,9 +14,9 @@
     "CRM_Contact_BAO_Relationship::relatedMemberships()": "toxicAlert",
     "CRM_Contact_Form_Contact::postProcess()": "toxicAlert",
     "CRM_Contact_Import_Form_MapField::buildQuickForm()": "toxicAlert",
-    "CRM_Contact_Import_Parser::formatCommonData()": "toxicAlert",
-    "CRM_Contact_Import_Parser::formatContactParameters()": "toxicAlert",
-    "CRM_Contact_Import_Parser::run()": "toxicAlert",
+    "CRM_Contact_Import_Parser_Contact::formatCommonData()": "toxicAlert",
+    "CRM_Contact_Import_Parser_Contact::formatContactParameters()": "toxicAlert",
+    "CRM_Contact_Import_Parser_Contact::run()": "toxicAlert",
     "CRM_Contact_Import_Parser_Contact::import()": "toxicAlert",
     "CRM_Contribute_BAO_Contribution::recordFinancialAccounts()": "toxicAlert",
     "CRM_Contribute_BAO_Contribution::transitionComponents()": "toxicAlert",
@@ -78,4 +78,4 @@
     "api_v3_JobTest::getMergeLocations()": "toxicAlert",
     "api_v3_JobTest::getMergeSets()": "toxicAlert"
   }
-}
\ No newline at end of file
+}
index 6ce5e0d849872833ca95a3afcdc3b6d866542ec4..75cd9db82effc20c4424dc3741e633dfa513a332 100644 (file)
@@ -42,17 +42,17 @@ class CRM_Activity_Import_Form_Preview extends CRM_Import_Form_Preview {
     $this->assign('savedMappingName', $mappingId ? $mapDAO->name : NULL);
 
     if ($invalidRowCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
     if ($conflictRowCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
     if ($mismatchCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
@@ -137,11 +137,11 @@ class CRM_Activity_Import_Form_Preview extends CRM_Import_Form_Preview {
       fclose($fd);
 
       $this->set('errorFile', $errorFile);
-      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
-      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
   }
index b8fc8327ab58253fa894a3617b6277025dcf6501..e2543665ccb6471e9201dfd64f1d5b0249da4dc2 100644 (file)
@@ -38,11 +38,11 @@ class CRM_Activity_Import_Form_Summary extends CRM_Import_Form_Summary {
     $onDuplicate = $this->get('onDuplicate');
     $mismatchCount = $this->get('unMatchCount');
     if ($duplicateRowCount > 0) {
-      $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadDuplicateRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
     elseif ($mismatchCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser_Activity';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
     else {
diff --git a/CRM/Activity/Import/Parser.php b/CRM/Activity/Import/Parser.php
deleted file mode 100644 (file)
index 6e4d290..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved.                        |
- |                                                                    |
- | This work is published under the GNU AGPLv3 license with some      |
- | permitted exceptions and without any warranty. For full license    |
- | and copyright information, see https://civicrm.org/licensing       |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- */
-abstract class CRM_Activity_Import_Parser extends CRM_Import_Parser {
-
-  protected $_fileName;
-
-  /**
-   * Imported file size.
-   * @var int
-   */
-  protected $_fileSize;
-
-  /**
-   * Separator being used.
-   * @var string
-   */
-  protected $_separator;
-
-  /**
-   * Total number of lines in file.
-   * @var int
-   */
-  protected $_lineCount;
-
-  /**
-   * Whether the file has a column header or not.
-   *
-   * @var bool
-   */
-  protected $_haveColumnHeader;
-
-  /**
-   * @param array $fileName
-   * @param string $separator
-   * @param $mapper
-   * @param bool $skipColumnHeader
-   * @param int $mode
-   * @param int $onDuplicate
-   * @param int $statusID
-   * @param int $totalRowCount
-   *
-   * @return mixed
-   * @throws Exception
-   */
-  public function run(
-    array $fileName,
-    $separator,
-    $mapper,
-    $skipColumnHeader = FALSE,
-    $mode = self::MODE_PREVIEW,
-    $onDuplicate = self::DUPLICATE_SKIP,
-    $statusID = NULL,
-    $totalRowCount = NULL
-  ) {
-
-    $fileName = $fileName['name'];
-
-    $this->init();
-
-    $this->_haveColumnHeader = $skipColumnHeader;
-
-    $this->_separator = $separator;
-
-    $fd = fopen($fileName, "r");
-    if (!$fd) {
-      return FALSE;
-    }
-
-    $this->_lineCount = $this->_warningCount = 0;
-    $this->_invalidRowCount = $this->_validCount = 0;
-    $this->_totalCount = $this->_conflictCount = 0;
-
-    $this->_errors = [];
-    $this->_warnings = [];
-    $this->_conflicts = [];
-
-    $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2);
-
-    if ($mode == self::MODE_MAPFIELD) {
-      $this->_rows = [];
-    }
-    else {
-      $this->_activeFieldCount = count($this->_activeFields);
-    }
-    if ($statusID) {
-      $this->progressImport($statusID);
-      $startTimestamp = $currTimestamp = $prevTimestamp = time();
-    }
-
-    while (!feof($fd)) {
-      $this->_lineCount++;
-
-      $values = fgetcsv($fd, 8192, $separator);
-      if (!$values) {
-        continue;
-      }
-
-      self::encloseScrub($values);
-
-      // skip column header if we're not in mapfield mode
-      if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) {
-        $skipColumnHeader = FALSE;
-        continue;
-      }
-
-      // Trim whitespace around the values.
-
-      $empty = TRUE;
-      foreach ($values as $k => $v) {
-        $values[$k] = trim($v, " \t\r\n");
-      }
-
-      if (CRM_Utils_System::isNull($values)) {
-        continue;
-      }
-
-      $this->_totalCount++;
-
-      if ($mode == self::MODE_MAPFIELD) {
-        $returnCode = $this->mapField($values);
-      }
-      elseif ($mode == self::MODE_PREVIEW) {
-        $returnCode = $this->preview($values);
-      }
-      elseif ($mode == self::MODE_SUMMARY) {
-        $returnCode = $this->summary($values);
-      }
-      elseif ($mode == self::MODE_IMPORT) {
-        $returnCode = $this->import($onDuplicate, $values);
-        if ($statusID && (($this->_lineCount % 50) == 0)) {
-          $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
-        }
-      }
-      else {
-        $returnCode = self::ERROR;
-      }
-
-      // note that a line could be valid but still produce a warning
-      if ($returnCode & self::VALID) {
-        $this->_validCount++;
-        if ($mode == self::MODE_MAPFIELD) {
-          $this->_rows[] = $values;
-          $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
-        }
-      }
-
-      if ($returnCode & self::WARNING) {
-        $this->_warningCount++;
-        if ($this->_warningCount < $this->_maxWarningCount) {
-          $this->_warningCount[] = $line;
-        }
-      }
-
-      if ($returnCode & self::ERROR) {
-        $this->_invalidRowCount++;
-        $recordNumber = $this->_lineCount;
-        if ($this->_haveColumnHeader) {
-          $recordNumber--;
-        }
-        array_unshift($values, $recordNumber);
-        $this->_errors[] = $values;
-      }
-
-      if ($returnCode & self::CONFLICT) {
-        $this->_conflictCount++;
-        $recordNumber = $this->_lineCount;
-        if ($this->_haveColumnHeader) {
-          $recordNumber--;
-        }
-        array_unshift($values, $recordNumber);
-        $this->_conflicts[] = $values;
-      }
-
-      if ($returnCode & self::DUPLICATE) {
-        $this->_duplicateCount++;
-        $recordNumber = $this->_lineCount;
-        if ($this->_haveColumnHeader) {
-          $recordNumber--;
-        }
-        array_unshift($values, $recordNumber);
-        $this->_duplicates[] = $values;
-        if ($onDuplicate != self::DUPLICATE_SKIP) {
-          $this->_validCount++;
-        }
-      }
-
-      // we give the derived class a way of aborting the process
-      // note that the return code could be multiple code or'ed together
-      if ($returnCode & self::STOP) {
-        break;
-      }
-
-      // if we are done processing the maxNumber of lines, break
-      if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
-        break;
-      }
-    }
-
-    fclose($fd);
-
-    if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
-      $customHeaders = $mapper;
-
-      $customfields = CRM_Core_BAO_CustomField::getFields('Activity');
-      foreach ($customHeaders as $key => $value) {
-        if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
-          $customHeaders[$key] = $customfields[$id][0];
-        }
-      }
-      if ($this->_invalidRowCount) {
-        // removed view url for invlaid contacts
-        $headers = array_merge(
-          [ts('Line Number'), ts('Reason')],
-          $customHeaders
-        );
-        $this->_errorFileName = self::errorFileName(self::ERROR);
-        self::exportCSV($this->_errorFileName, $headers, $this->_errors);
-      }
-      if ($this->_conflictCount) {
-        $headers = array_merge(
-          [ts('Line Number'), ts('Reason')],
-          $customHeaders
-        );
-        $this->_conflictFileName = self::errorFileName(self::CONFLICT);
-        self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
-      }
-      if ($this->_duplicateCount) {
-        $headers = array_merge(
-          [ts('Line Number'), ts('View Activity History URL')],
-          $customHeaders
-        );
-
-        $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
-        self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
-      }
-    }
-    return $this->fini();
-  }
-
-  /**
-   * Given a list of the importable field keys that the user has selected set the active fields array to this list.
-   *
-   * @param array $fieldKeys
-   */
-  public function setActiveFields($fieldKeys) {
-    $this->_activeFieldCount = count($fieldKeys);
-    foreach ($fieldKeys as $key) {
-      if (empty($this->_fields[$key])) {
-        $this->_activeFields[] = new CRM_Activity_Import_Field('', ts('- do not import -'));
-      }
-      else {
-        $this->_activeFields[] = clone($this->_fields[$key]);
-      }
-    }
-  }
-
-  /**
-   * @param string $name
-   * @param $title
-   * @param int $type
-   * @param string $headerPattern
-   * @param string $dataPattern
-   */
-  public function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') {
-    if (empty($name)) {
-      $this->_fields['doNotImport'] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
-    }
-    else {
-
-      $tempField = CRM_Contact_BAO_Contact::importableFields('Individual', NULL);
-      if (!array_key_exists($name, $tempField)) {
-        $this->_fields[$name] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
-      }
-      else {
-        $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, CRM_Utils_Array::value('hasLocationType', $tempField[$name]));
-      }
-    }
-  }
-
-  /**
-   * Store parser values.
-   *
-   * @param CRM_Core_Session $store
-   *
-   * @param int $mode
-   */
-  public function set($store, $mode = self::MODE_SUMMARY) {
-    $store->set('fileSize', $this->_fileSize);
-    $store->set('lineCount', $this->_lineCount);
-    $store->set('separator', $this->_separator);
-    $store->set('fields', $this->getSelectValues());
-
-    $store->set('headerPatterns', $this->getHeaderPatterns());
-    $store->set('dataPatterns', $this->getDataPatterns());
-    $store->set('columnCount', $this->_activeFieldCount);
-
-    $store->set('totalRowCount', $this->_totalCount);
-    $store->set('validRowCount', $this->_validCount);
-    $store->set('invalidRowCount', $this->_invalidRowCount);
-    $store->set('conflictRowCount', $this->_conflictCount);
-
-    if ($this->_invalidRowCount) {
-      $store->set('errorsFileName', $this->_errorFileName);
-    }
-    if ($this->_conflictCount) {
-      $store->set('conflictsFileName', $this->_conflictFileName);
-    }
-    if (isset($this->_rows) && !empty($this->_rows)) {
-      $store->set('dataValues', $this->_rows);
-    }
-
-    if ($mode == self::MODE_IMPORT) {
-      $store->set('duplicateRowCount', $this->_duplicateCount);
-      if ($this->_duplicateCount) {
-        $store->set('duplicatesFileName', $this->_duplicateFileName);
-      }
-    }
-  }
-
-  /**
-   * Export data to a CSV file.
-   *
-   * @param string $fileName
-   * @param array $header
-   * @param array $data
-   */
-  public static function exportCSV($fileName, $header, $data) {
-    $output = [];
-    $fd = fopen($fileName, 'w');
-
-    foreach ($header as $key => $value) {
-      $header[$key] = "\"$value\"";
-    }
-    $config = CRM_Core_Config::singleton();
-    $output[] = implode($config->fieldSeparator, $header);
-
-    foreach ($data as $datum) {
-      foreach ($datum as $key => $value) {
-        $datum[$key] = "\"$value\"";
-      }
-      $output[] = implode($config->fieldSeparator, $datum);
-    }
-    fwrite($fd, implode("\n", $output));
-    fclose($fd);
-  }
-
-}
index a1d3cdfa8bd4349b50ca3eaf8e662819322a7dd7..7014f313e1f30a1177c796ccfc7c7b1cb54c4d80 100644 (file)
@@ -19,7 +19,7 @@
 /**
  * Class to parse activity csv files.
  */
-class CRM_Activity_Import_Parser_Activity extends CRM_Activity_Import_Parser {
+class CRM_Activity_Import_Parser_Activity extends CRM_Import_Parser {
 
   protected $_mapperKeys;
 
@@ -32,6 +32,33 @@ class CRM_Activity_Import_Parser_Activity extends CRM_Activity_Import_Parser {
    */
   protected $_newActivity;
 
+  protected $_fileName;
+
+  /**
+   * Imported file size.
+   * @var int
+   */
+  protected $_fileSize;
+
+  /**
+   * Separator being used.
+   * @var string
+   */
+  protected $_separator;
+
+  /**
+   * Total number of lines in file.
+   * @var int
+   */
+  protected $_lineCount;
+
+  /**
+   * Whether the file has a column header or not.
+   *
+   * @var bool
+   */
+  protected $_haveColumnHeader;
+
   /**
    * Class constructor.
    *
@@ -436,4 +463,319 @@ class CRM_Activity_Import_Parser_Activity extends CRM_Activity_Import_Parser {
     return $params;
   }
 
+  /**
+   * @param array $fileName
+   * @param string $separator
+   * @param $mapper
+   * @param bool $skipColumnHeader
+   * @param int $mode
+   * @param int $onDuplicate
+   * @param int $statusID
+   * @param int $totalRowCount
+   *
+   * @return mixed
+   * @throws Exception
+   */
+  public function run(
+    array $fileName,
+          $separator,
+          $mapper,
+          $skipColumnHeader = FALSE,
+          $mode = self::MODE_PREVIEW,
+          $onDuplicate = self::DUPLICATE_SKIP,
+          $statusID = NULL,
+          $totalRowCount = NULL
+  ) {
+
+    $fileName = $fileName['name'];
+
+    $this->init();
+
+    $this->_haveColumnHeader = $skipColumnHeader;
+
+    $this->_separator = $separator;
+
+    $fd = fopen($fileName, "r");
+    if (!$fd) {
+      return FALSE;
+    }
+
+    $this->_lineCount = $this->_warningCount = 0;
+    $this->_invalidRowCount = $this->_validCount = 0;
+    $this->_totalCount = $this->_conflictCount = 0;
+
+    $this->_errors = [];
+    $this->_warnings = [];
+    $this->_conflicts = [];
+
+    $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2);
+
+    if ($mode == self::MODE_MAPFIELD) {
+      $this->_rows = [];
+    }
+    else {
+      $this->_activeFieldCount = count($this->_activeFields);
+    }
+    if ($statusID) {
+      $this->progressImport($statusID);
+      $startTimestamp = $currTimestamp = $prevTimestamp = time();
+    }
+
+    while (!feof($fd)) {
+      $this->_lineCount++;
+
+      $values = fgetcsv($fd, 8192, $separator);
+      if (!$values) {
+        continue;
+      }
+
+      self::encloseScrub($values);
+
+      // skip column header if we're not in mapfield mode
+      if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) {
+        $skipColumnHeader = FALSE;
+        continue;
+      }
+
+      // Trim whitespace around the values.
+
+      $empty = TRUE;
+      foreach ($values as $k => $v) {
+        $values[$k] = trim($v, " \t\r\n");
+      }
+
+      if (CRM_Utils_System::isNull($values)) {
+        continue;
+      }
+
+      $this->_totalCount++;
+
+      if ($mode == self::MODE_MAPFIELD) {
+        $returnCode = $this->mapField($values);
+      }
+      elseif ($mode == self::MODE_PREVIEW) {
+        $returnCode = $this->preview($values);
+      }
+      elseif ($mode == self::MODE_SUMMARY) {
+        $returnCode = $this->summary($values);
+      }
+      elseif ($mode == self::MODE_IMPORT) {
+        $returnCode = $this->import($onDuplicate, $values);
+        if ($statusID && (($this->_lineCount % 50) == 0)) {
+          $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
+        }
+      }
+      else {
+        $returnCode = self::ERROR;
+      }
+
+      // note that a line could be valid but still produce a warning
+      if ($returnCode & self::VALID) {
+        $this->_validCount++;
+        if ($mode == self::MODE_MAPFIELD) {
+          $this->_rows[] = $values;
+          $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
+        }
+      }
+
+      if ($returnCode & self::WARNING) {
+        $this->_warningCount++;
+        if ($this->_warningCount < $this->_maxWarningCount) {
+          $this->_warningCount[] = $line;
+        }
+      }
+
+      if ($returnCode & self::ERROR) {
+        $this->_invalidRowCount++;
+        $recordNumber = $this->_lineCount;
+        if ($this->_haveColumnHeader) {
+          $recordNumber--;
+        }
+        array_unshift($values, $recordNumber);
+        $this->_errors[] = $values;
+      }
+
+      if ($returnCode & self::CONFLICT) {
+        $this->_conflictCount++;
+        $recordNumber = $this->_lineCount;
+        if ($this->_haveColumnHeader) {
+          $recordNumber--;
+        }
+        array_unshift($values, $recordNumber);
+        $this->_conflicts[] = $values;
+      }
+
+      if ($returnCode & self::DUPLICATE) {
+        $this->_duplicateCount++;
+        $recordNumber = $this->_lineCount;
+        if ($this->_haveColumnHeader) {
+          $recordNumber--;
+        }
+        array_unshift($values, $recordNumber);
+        $this->_duplicates[] = $values;
+        if ($onDuplicate != self::DUPLICATE_SKIP) {
+          $this->_validCount++;
+        }
+      }
+
+      // we give the derived class a way of aborting the process
+      // note that the return code could be multiple code or'ed together
+      if ($returnCode & self::STOP) {
+        break;
+      }
+
+      // if we are done processing the maxNumber of lines, break
+      if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
+        break;
+      }
+    }
+
+    fclose($fd);
+
+    if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
+      $customHeaders = $mapper;
+
+      $customfields = CRM_Core_BAO_CustomField::getFields('Activity');
+      foreach ($customHeaders as $key => $value) {
+        if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
+          $customHeaders[$key] = $customfields[$id][0];
+        }
+      }
+      if ($this->_invalidRowCount) {
+        // removed view url for invlaid contacts
+        $headers = array_merge(
+          [ts('Line Number'), ts('Reason')],
+          $customHeaders
+        );
+        $this->_errorFileName = self::errorFileName(self::ERROR);
+        self::exportCSV($this->_errorFileName, $headers, $this->_errors);
+      }
+      if ($this->_conflictCount) {
+        $headers = array_merge(
+          [ts('Line Number'), ts('Reason')],
+          $customHeaders
+        );
+        $this->_conflictFileName = self::errorFileName(self::CONFLICT);
+        self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
+      }
+      if ($this->_duplicateCount) {
+        $headers = array_merge(
+          [ts('Line Number'), ts('View Activity History URL')],
+          $customHeaders
+        );
+
+        $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
+        self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
+      }
+    }
+    return $this->fini();
+  }
+
+  /**
+   * Given a list of the importable field keys that the user has selected set the active fields array to this list.
+   *
+   * @param array $fieldKeys
+   */
+  public function setActiveFields($fieldKeys) {
+    $this->_activeFieldCount = count($fieldKeys);
+    foreach ($fieldKeys as $key) {
+      if (empty($this->_fields[$key])) {
+        $this->_activeFields[] = new CRM_Activity_Import_Field('', ts('- do not import -'));
+      }
+      else {
+        $this->_activeFields[] = clone($this->_fields[$key]);
+      }
+    }
+  }
+
+  /**
+   * @param string $name
+   * @param $title
+   * @param int $type
+   * @param string $headerPattern
+   * @param string $dataPattern
+   */
+  public function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') {
+    if (empty($name)) {
+      $this->_fields['doNotImport'] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
+    }
+    else {
+
+      $tempField = CRM_Contact_BAO_Contact::importableFields('Individual', NULL);
+      if (!array_key_exists($name, $tempField)) {
+        $this->_fields[$name] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern);
+      }
+      else {
+        $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, CRM_Utils_Array::value('hasLocationType', $tempField[$name]));
+      }
+    }
+  }
+
+  /**
+   * Store parser values.
+   *
+   * @param CRM_Core_Session $store
+   *
+   * @param int $mode
+   */
+  public function set($store, $mode = self::MODE_SUMMARY) {
+    $store->set('fileSize', $this->_fileSize);
+    $store->set('lineCount', $this->_lineCount);
+    $store->set('separator', $this->_separator);
+    $store->set('fields', $this->getSelectValues());
+
+    $store->set('headerPatterns', $this->getHeaderPatterns());
+    $store->set('dataPatterns', $this->getDataPatterns());
+    $store->set('columnCount', $this->_activeFieldCount);
+
+    $store->set('totalRowCount', $this->_totalCount);
+    $store->set('validRowCount', $this->_validCount);
+    $store->set('invalidRowCount', $this->_invalidRowCount);
+    $store->set('conflictRowCount', $this->_conflictCount);
+
+    if ($this->_invalidRowCount) {
+      $store->set('errorsFileName', $this->_errorFileName);
+    }
+    if ($this->_conflictCount) {
+      $store->set('conflictsFileName', $this->_conflictFileName);
+    }
+    if (isset($this->_rows) && !empty($this->_rows)) {
+      $store->set('dataValues', $this->_rows);
+    }
+
+    if ($mode == self::MODE_IMPORT) {
+      $store->set('duplicateRowCount', $this->_duplicateCount);
+      if ($this->_duplicateCount) {
+        $store->set('duplicatesFileName', $this->_duplicateFileName);
+      }
+    }
+  }
+
+  /**
+   * Export data to a CSV file.
+   *
+   * @param string $fileName
+   * @param array $header
+   * @param array $data
+   */
+  public static function exportCSV($fileName, $header, $data) {
+    $output = [];
+    $fd = fopen($fileName, 'w');
+
+    foreach ($header as $key => $value) {
+      $header[$key] = "\"$value\"";
+    }
+    $config = CRM_Core_Config::singleton();
+    $output[] = implode($config->fieldSeparator, $header);
+
+    foreach ($data as $datum) {
+      foreach ($datum as $key => $value) {
+        $datum[$key] = "\"$value\"";
+      }
+      $output[] = implode($config->fieldSeparator, $datum);
+    }
+    fwrite($fd, implode("\n", $output));
+    fclose($fd);
+  }
+
 }
index 349b9d9991661a5ea6875d8982e6f5885b332f64..b2cc785173b2213c748212816e625271a38e5a76 100644 (file)
@@ -126,6 +126,8 @@ class CRM_Contact_BAO_RelationshipType extends CRM_Contact_DAO_RelationshipType
 
   /**
    * Get the id of the employee relationship, checking it is valid.
+   * We check that contact_type_a is Individual, but not contact_type_b because there's
+   * nowhere in the code that requires it to be Organization.
    *
    * @return int|string
    *
@@ -137,7 +139,6 @@ class CRM_Contact_BAO_RelationshipType extends CRM_Contact_DAO_RelationshipType
         $relationship = RelationshipType::get(FALSE)
           ->addWhere('name_a_b', '=', 'Employee of')
           ->addWhere('contact_type_a', '=', 'Individual')
-          ->addWhere('contact_type_b', '=', 'Organization')
           ->addSelect('id')->execute()->first();
         if (empty($relationship)) {
           throw new API_Exception('no valid relationship');
index 933648584199032c168ccd895dd053074ff837df..b9eb4dfb4dcd405156f4e195c488e0329156d655 100644 (file)
@@ -319,7 +319,7 @@ class CRM_Contact_Import_Form_DataSource extends CRM_Core_Form {
         $fieldNames['status'],
         CRM_Import_Parser::DUPLICATE_SKIP,
         NULL, NULL, FALSE,
-        CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+        CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
         $storeParams['contactSubType'],
         $storeParams['dedupe']
       );
index c85e9bbae852a84df44a7e4502d7b8e27be1b9fd..5471108423bd6e07c8a83a6c943d9673fc2de75a 100644 (file)
@@ -723,7 +723,7 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
       $statusFieldName,
       $this->_onDuplicate,
       NULL, NULL, FALSE,
-      CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+      CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
       $this->get('contactSubType'),
       $this->get('dedupe')
     );
index e8d082b64169f40b620afe92851123f267aa2455..85f91c877f253481b26c4310052eaee7efdfcec2 100644 (file)
@@ -63,17 +63,17 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
     }
 
     if ($invalidRowCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
     if ($conflictRowCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
     if ($mismatchCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
@@ -280,13 +280,13 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
 
       $this->set('errorFile', $errorFile);
 
-      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
 
-      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
 
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
 
@@ -416,7 +416,7 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
       $this->get('statusID'),
       $this->get('totalRowCount'),
       $doGeocodeAddress,
-      CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+      CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
       $this->get('contactSubType'),
       $this->get('dedupe')
     );
@@ -544,13 +544,13 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
 
       $this->set('errorFile', $errorFile);
 
-      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::ERROR . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlparams));
 
-      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::CONFLICT . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
 
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
   }
index dc94f8dcd87980c6856d6dee19d63b85fac0cd76..b21391fd0ed20181ae7e6553c1293c1b117fa8aa 100644 (file)
@@ -38,11 +38,11 @@ class CRM_Contact_Import_Form_Summary extends CRM_Import_Form_Summary {
     $mismatchCount = $this->get('unMatchCount');
     $unparsedAddressCount = $this->get('unparsedAddressCount');
     if ($duplicateRowCount > 0) {
-      $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::DUPLICATE . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadDuplicateRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
     elseif ($mismatchCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::NO_MATCH . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
     }
     else {
@@ -50,7 +50,7 @@ class CRM_Contact_Import_Form_Summary extends CRM_Import_Form_Summary {
       $this->set('duplicateRowCount', $duplicateRowCount);
     }
     if ($unparsedAddressCount) {
-      $urlParams = 'type=' . CRM_Import_Parser::UNPARSED_ADDRESS_WARNING . '&parser=CRM_Contact_Import_Parser';
+      $urlParams = 'type=' . CRM_Import_Parser::UNPARSED_ADDRESS_WARNING . '&parser=CRM_Contact_Import_Parser_Contact';
       $this->assign('downloadAddressRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams));
       $unparsedStreetAddressString = ts('Records imported successfully but unable to parse some of the street addresses');
       $this->assign('unparsedStreetAddressString', $unparsedStreetAddressString);
index 7e0bd84c6aad97b402b6b312d155bd62b324729f..838ee5ce836ce361529017eb25d3859363af73b8 100644 (file)
@@ -228,7 +228,7 @@ class CRM_Contact_Import_ImportJob {
       $this->_statusID,
       $this->_totalRowCount,
       $this->_doGeocodeAddress,
-      CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
+      CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
       $this->_contactSubType,
       $this->_dedupe
     );
diff --git a/CRM/Contact/Import/Parser.php b/CRM/Contact/Import/Parser.php
deleted file mode 100644 (file)
index 59068aa..0000000
+++ /dev/null
@@ -1,1092 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved.                        |
- |                                                                    |
- | This work is published under the GNU AGPLv3 license with some      |
- | permitted exceptions and without any warranty. For full license    |
- | and copyright information, see https://civicrm.org/licensing       |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- */
-abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
-
-  protected $_tableName;
-
-  /**
-   * Total number of lines in file
-   *
-   * @var int
-   */
-  protected $_rowCount;
-
-  /**
-   * Running total number of un-matched Contacts.
-   *
-   * @var int
-   */
-  protected $_unMatchCount;
-
-  /**
-   * Array of unmatched lines.
-   *
-   * @var array
-   */
-  protected $_unMatch;
-
-  /**
-   * Total number of contacts with unparsed addresses
-   * @var int
-   */
-  protected $_unparsedAddressCount;
-
-  /**
-   * Filename of mismatch data
-   *
-   * @var string
-   */
-  protected $_misMatchFilemName;
-
-  protected $_primaryKeyName;
-  protected $_statusFieldName;
-
-  protected $fieldMetadata = [];
-  /**
-   * On duplicate
-   *
-   * @var int
-   */
-  public $_onDuplicate;
-
-  /**
-   * Dedupe rule group id to use if set
-   *
-   * @var int
-   */
-  public $_dedupeRuleGroupID = NULL;
-
-  /**
-   * Run import.
-   *
-   * @param string $tableName
-   * @param array $mapper
-   * @param int $mode
-   * @param int $contactType
-   * @param string $primaryKeyName
-   * @param string $statusFieldName
-   * @param int $onDuplicate
-   * @param int $statusID
-   * @param int $totalRowCount
-   * @param bool $doGeocodeAddress
-   * @param int $timeout
-   * @param string $contactSubType
-   * @param int $dedupeRuleGroupID
-   *
-   * @return mixed
-   */
-  public function run(
-    $tableName,
-    $mapper = [],
-    $mode = self::MODE_PREVIEW,
-    $contactType = self::CONTACT_INDIVIDUAL,
-    $primaryKeyName = '_id',
-    $statusFieldName = '_status',
-    $onDuplicate = self::DUPLICATE_SKIP,
-    $statusID = NULL,
-    $totalRowCount = NULL,
-    $doGeocodeAddress = FALSE,
-    $timeout = CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
-    $contactSubType = NULL,
-    $dedupeRuleGroupID = NULL
-  ) {
-
-    // TODO: Make the timeout actually work
-    $this->_onDuplicate = $onDuplicate;
-    $this->_dedupeRuleGroupID = $dedupeRuleGroupID;
-
-    switch ($contactType) {
-      case CRM_Import_Parser::CONTACT_INDIVIDUAL:
-        $this->_contactType = 'Individual';
-        break;
-
-      case CRM_Import_Parser::CONTACT_HOUSEHOLD:
-        $this->_contactType = 'Household';
-        break;
-
-      case CRM_Import_Parser::CONTACT_ORGANIZATION:
-        $this->_contactType = 'Organization';
-    }
-
-    $this->_contactSubType = $contactSubType;
-
-    $this->init();
-
-    $this->_rowCount = $this->_warningCount = 0;
-    $this->_invalidRowCount = $this->_validCount = 0;
-    $this->_totalCount = $this->_conflictCount = 0;
-
-    $this->_errors = [];
-    $this->_warnings = [];
-    $this->_conflicts = [];
-    $this->_unparsedAddresses = [];
-
-    $this->_tableName = $tableName;
-    $this->_primaryKeyName = $primaryKeyName;
-    $this->_statusFieldName = $statusFieldName;
-
-    if ($mode == self::MODE_MAPFIELD) {
-      $this->_rows = [];
-    }
-    else {
-      $this->_activeFieldCount = count($this->_activeFields);
-    }
-
-    if ($mode == self::MODE_IMPORT) {
-      //get the key of email field
-      foreach ($mapper as $key => $value) {
-        if (strtolower($value) == 'email') {
-          $emailKey = $key;
-          break;
-        }
-      }
-    }
-
-    if ($statusID) {
-      $this->progressImport($statusID);
-      $startTimestamp = $currTimestamp = $prevTimestamp = time();
-    }
-    // get the contents of the temp. import table
-    $query = "SELECT * FROM $tableName";
-    if ($mode == self::MODE_IMPORT) {
-      $query .= " WHERE $statusFieldName = 'NEW'";
-    }
-
-    $result = CRM_Core_DAO::executeQuery($query);
-
-    while ($result->fetch()) {
-      $values = array_values($result->toArray());
-      $this->_rowCount++;
-
-      /* trim whitespace around the values */
-      foreach ($values as $k => $v) {
-        $values[$k] = trim($v, " \t\r\n");
-      }
-      if (CRM_Utils_System::isNull($values)) {
-        continue;
-      }
-
-      $this->_totalCount++;
-
-      if ($mode == self::MODE_MAPFIELD) {
-        $returnCode = $this->mapField($values);
-      }
-      elseif ($mode == self::MODE_PREVIEW) {
-        $returnCode = $this->preview($values);
-      }
-      elseif ($mode == self::MODE_SUMMARY) {
-        $returnCode = $this->summary($values);
-      }
-      elseif ($mode == self::MODE_IMPORT) {
-        //print "Running parser in import mode<br/>\n";
-        $returnCode = $this->import($onDuplicate, $values, $doGeocodeAddress);
-        if ($statusID && (($this->_rowCount % 50) == 0)) {
-          $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
-        }
-      }
-      else {
-        $returnCode = self::ERROR;
-      }
-
-      // note that a line could be valid but still produce a warning
-      if ($returnCode & self::VALID) {
-        $this->_validCount++;
-        if ($mode == self::MODE_MAPFIELD) {
-          $this->_rows[] = $values;
-          $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
-        }
-      }
-
-      if ($returnCode & self::WARNING) {
-        $this->_warningCount++;
-        if ($this->_warningCount < $this->_maxWarningCount) {
-          $this->_warningCount[] = $line;
-        }
-      }
-
-      if ($returnCode & self::ERROR) {
-        $this->_invalidRowCount++;
-        array_unshift($values, $this->_rowCount);
-        $this->_errors[] = $values;
-      }
-
-      if ($returnCode & self::CONFLICT) {
-        $this->_conflictCount++;
-        array_unshift($values, $this->_rowCount);
-        $this->_conflicts[] = $values;
-      }
-
-      if ($returnCode & self::NO_MATCH) {
-        $this->_unMatchCount++;
-        array_unshift($values, $this->_rowCount);
-        $this->_unMatch[] = $values;
-      }
-
-      if ($returnCode & self::DUPLICATE) {
-        $this->_duplicateCount++;
-        array_unshift($values, $this->_rowCount);
-        $this->_duplicates[] = $values;
-        if ($onDuplicate != self::DUPLICATE_SKIP) {
-          $this->_validCount++;
-        }
-      }
-
-      if ($returnCode & self::UNPARSED_ADDRESS_WARNING) {
-        $this->_unparsedAddressCount++;
-        array_unshift($values, $this->_rowCount);
-        $this->_unparsedAddresses[] = $values;
-      }
-      // we give the derived class a way of aborting the process
-      // note that the return code could be multiple code or'ed together
-      if ($returnCode & self::STOP) {
-        break;
-      }
-
-      // if we are done processing the maxNumber of lines, break
-      if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
-        break;
-      }
-
-      // see if we've hit our timeout yet
-      /* if ( $the_thing_with_the_stuff ) {
-      do_something( );
-      } */
-    }
-
-    if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
-      $customHeaders = $mapper;
-
-      $customfields = CRM_Core_BAO_CustomField::getFields($this->_contactType);
-      foreach ($customHeaders as $key => $value) {
-        if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
-          $customHeaders[$key] = $customfields[$id][0];
-        }
-      }
-
-      if ($this->_invalidRowCount) {
-        // removed view url for invlaid contacts
-        $headers = array_merge([
-          ts('Line Number'),
-          ts('Reason'),
-        ], $customHeaders);
-        $this->_errorFileName = self::errorFileName(self::ERROR);
-        self::exportCSV($this->_errorFileName, $headers, $this->_errors);
-      }
-      if ($this->_conflictCount) {
-        $headers = array_merge([
-          ts('Line Number'),
-          ts('Reason'),
-        ], $customHeaders);
-        $this->_conflictFileName = self::errorFileName(self::CONFLICT);
-        self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
-      }
-      if ($this->_duplicateCount) {
-        $headers = array_merge([
-          ts('Line Number'),
-          ts('View Contact URL'),
-        ], $customHeaders);
-
-        $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
-        self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
-      }
-      if ($this->_unMatchCount) {
-        $headers = array_merge([
-          ts('Line Number'),
-          ts('Reason'),
-        ], $customHeaders);
-
-        $this->_misMatchFilemName = self::errorFileName(self::NO_MATCH);
-        self::exportCSV($this->_misMatchFilemName, $headers, $this->_unMatch);
-      }
-      if ($this->_unparsedAddressCount) {
-        $headers = array_merge([
-          ts('Line Number'),
-          ts('Contact Edit URL'),
-        ], $customHeaders);
-        $this->_errorFileName = self::errorFileName(self::UNPARSED_ADDRESS_WARNING);
-        self::exportCSV($this->_errorFileName, $headers, $this->_unparsedAddresses);
-      }
-    }
-    //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
-    return $this->fini();
-  }
-
-  /**
-   * Given a list of the importable field keys that the user has selected.
-   * set the active fields array to this list
-   *
-   * @param array $fieldKeys
-   *   Mapped array of values.
-   */
-  public function setActiveFields($fieldKeys) {
-    $this->_activeFieldCount = count($fieldKeys);
-    foreach ($fieldKeys as $key) {
-      if (empty($this->_fields[$key])) {
-        $this->_activeFields[] = new CRM_Contact_Import_Field('', ts('- do not import -'));
-      }
-      else {
-        $this->_activeFields[] = clone($this->_fields[$key]);
-      }
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldLocationTypes($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_hasLocationType = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldPhoneTypes($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_phoneType = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldWebsiteTypes($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_websiteType = $elements[$i];
-    }
-  }
-
-  /**
-   * Set IM Service Provider type fields.
-   *
-   * @param array $elements
-   *   IM service provider type ids.
-   */
-  public function setActiveFieldImProviders($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_imProvider = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldRelated($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_related = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldRelatedContactType($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_relatedContactType = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldRelatedContactDetails($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_relatedContactDetails = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldRelatedContactLocType($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_relatedContactLocType = $elements[$i];
-    }
-  }
-
-  /**
-   * Set active field for related contact's phone type.
-   *
-   * @param array $elements
-   */
-  public function setActiveFieldRelatedContactPhoneType($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_relatedContactPhoneType = $elements[$i];
-    }
-  }
-
-  /**
-   * @param $elements
-   */
-  public function setActiveFieldRelatedContactWebsiteType($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_relatedContactWebsiteType = $elements[$i];
-    }
-  }
-
-  /**
-   * Set IM Service Provider type fields for related contacts.
-   *
-   * @param array $elements
-   *   IM service provider type ids of related contact.
-   */
-  public function setActiveFieldRelatedContactImProvider($elements) {
-    for ($i = 0; $i < count($elements); $i++) {
-      $this->_activeFields[$i]->_relatedContactImProvider = $elements[$i];
-    }
-  }
-
-  /**
-   * Format the field values for input to the api.
-   *
-   * @return array
-   *   (reference ) associative array of name/value pairs
-   */
-  public function &getActiveFieldParams() {
-    $params = [];
-
-    for ($i = 0; $i < $this->_activeFieldCount; $i++) {
-      if ($this->_activeFields[$i]->_name == 'do_not_import') {
-        continue;
-      }
-
-      if (isset($this->_activeFields[$i]->_value)) {
-        if (isset($this->_activeFields[$i]->_hasLocationType)) {
-          if (!isset($params[$this->_activeFields[$i]->_name])) {
-            $params[$this->_activeFields[$i]->_name] = [];
-          }
-
-          $value = [
-            $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
-            'location_type_id' => $this->_activeFields[$i]->_hasLocationType,
-          ];
-
-          if (isset($this->_activeFields[$i]->_phoneType)) {
-            $value['phone_type_id'] = $this->_activeFields[$i]->_phoneType;
-          }
-
-          // get IM service Provider type id
-          if (isset($this->_activeFields[$i]->_imProvider)) {
-            $value['provider_id'] = $this->_activeFields[$i]->_imProvider;
-          }
-
-          $params[$this->_activeFields[$i]->_name][] = $value;
-        }
-        elseif (isset($this->_activeFields[$i]->_websiteType)) {
-          $value = [
-            $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
-            'website_type_id' => $this->_activeFields[$i]->_websiteType,
-          ];
-
-          $params[$this->_activeFields[$i]->_name][] = $value;
-        }
-
-        if (!isset($params[$this->_activeFields[$i]->_name])) {
-          if (!isset($this->_activeFields[$i]->_related)) {
-            $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value;
-          }
-        }
-
-        //minor fix for CRM-4062
-        if (isset($this->_activeFields[$i]->_related)) {
-          if (!isset($params[$this->_activeFields[$i]->_related])) {
-            $params[$this->_activeFields[$i]->_related] = [];
-          }
-
-          if (!isset($params[$this->_activeFields[$i]->_related]['contact_type']) && !empty($this->_activeFields[$i]->_relatedContactType)) {
-            $params[$this->_activeFields[$i]->_related]['contact_type'] = $this->_activeFields[$i]->_relatedContactType;
-          }
-
-          if (isset($this->_activeFields[$i]->_relatedContactLocType) && !empty($this->_activeFields[$i]->_value)) {
-            if (!empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails]) &&
-              !is_array($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])
-            ) {
-              $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
-            }
-            $value = [
-              $this->_activeFields[$i]->_relatedContactDetails => $this->_activeFields[$i]->_value,
-              'location_type_id' => $this->_activeFields[$i]->_relatedContactLocType,
-            ];
-
-            if (isset($this->_activeFields[$i]->_relatedContactPhoneType)) {
-              $value['phone_type_id'] = $this->_activeFields[$i]->_relatedContactPhoneType;
-            }
-
-            // get IM service Provider type id for related contact
-            if (isset($this->_activeFields[$i]->_relatedContactImProvider)) {
-              $value['provider_id'] = $this->_activeFields[$i]->_relatedContactImProvider;
-            }
-
-            $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = $value;
-          }
-          elseif (isset($this->_activeFields[$i]->_relatedContactWebsiteType)) {
-            $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = [
-              'url' => $this->_activeFields[$i]->_value,
-              'website_type_id' => $this->_activeFields[$i]->_relatedContactWebsiteType,
-            ];
-          }
-          elseif (empty($this->_activeFields[$i]->_value) && isset($this->_activeFields[$i]->_relatedContactLocType)) {
-            if (empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])) {
-              $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
-            }
-          }
-          else {
-            $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = $this->_activeFields[$i]->_value;
-          }
-        }
-      }
-    }
-
-    return $params;
-  }
-
-  /**
-   * @param string $name
-   * @param $title
-   * @param int $type
-   * @param string $headerPattern
-   * @param string $dataPattern
-   * @param bool $hasLocationType
-   */
-  public function addField(
-    $name, $title, $type = CRM_Utils_Type::T_INT,
-    $headerPattern = '//', $dataPattern = '//',
-    $hasLocationType = FALSE
-  ) {
-    $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
-    if (empty($name)) {
-      $this->_fields['doNotImport'] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
-    }
-  }
-
-  /**
-   * Store parser values.
-   *
-   * @param CRM_Core_Session $store
-   *
-   * @param int $mode
-   */
-  public function set($store, $mode = self::MODE_SUMMARY) {
-    $store->set('rowCount', $this->_rowCount);
-    $store->set('fields', $this->getSelectValues());
-    $store->set('fieldTypes', $this->getSelectTypes());
-
-    $store->set('columnCount', $this->_activeFieldCount);
-
-    $store->set('totalRowCount', $this->_totalCount);
-    $store->set('validRowCount', $this->_validCount);
-    $store->set('invalidRowCount', $this->_invalidRowCount);
-    $store->set('conflictRowCount', $this->_conflictCount);
-    $store->set('unMatchCount', $this->_unMatchCount);
-
-    switch ($this->_contactType) {
-      case 'Individual':
-        $store->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
-        break;
-
-      case 'Household':
-        $store->set('contactType', CRM_Import_Parser::CONTACT_HOUSEHOLD);
-        break;
-
-      case 'Organization':
-        $store->set('contactType', CRM_Import_Parser::CONTACT_ORGANIZATION);
-    }
-
-    if ($this->_invalidRowCount) {
-      $store->set('errorsFileName', $this->_errorFileName);
-    }
-    if ($this->_conflictCount) {
-      $store->set('conflictsFileName', $this->_conflictFileName);
-    }
-    if (isset($this->_rows) && !empty($this->_rows)) {
-      $store->set('dataValues', $this->_rows);
-    }
-
-    if ($this->_unMatchCount) {
-      $store->set('mismatchFileName', $this->_misMatchFilemName);
-    }
-
-    if ($mode == self::MODE_IMPORT) {
-      $store->set('duplicateRowCount', $this->_duplicateCount);
-      $store->set('unparsedAddressCount', $this->_unparsedAddressCount);
-      if ($this->_duplicateCount) {
-        $store->set('duplicatesFileName', $this->_duplicateFileName);
-      }
-      if ($this->_unparsedAddressCount) {
-        $store->set('errorsFileName', $this->_errorFileName);
-      }
-    }
-    //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
-  }
-
-  /**
-   * Export data to a CSV file.
-   *
-   * @param string $fileName
-   * @param array $header
-   * @param array $data
-   */
-  public static function exportCSV($fileName, $header, $data) {
-
-    if (file_exists($fileName) && !is_writable($fileName)) {
-      CRM_Core_Error::movedSiteError($fileName);
-    }
-    //hack to remove '_status', '_statusMsg' and '_id' from error file
-    $errorValues = [];
-    $dbRecordStatus = ['IMPORTED', 'ERROR', 'DUPLICATE', 'INVALID', 'NEW'];
-    foreach ($data as $rowCount => $rowValues) {
-      $count = 0;
-      foreach ($rowValues as $key => $val) {
-        if (in_array($val, $dbRecordStatus) && $count == (count($rowValues) - 3)) {
-          break;
-        }
-        $errorValues[$rowCount][$key] = $val;
-        $count++;
-      }
-    }
-    $data = $errorValues;
-
-    $output = [];
-    $fd = fopen($fileName, 'w');
-
-    foreach ($header as $key => $value) {
-      $header[$key] = "\"$value\"";
-    }
-    $config = CRM_Core_Config::singleton();
-    $output[] = implode($config->fieldSeparator, $header);
-
-    foreach ($data as $datum) {
-      foreach ($datum as $key => $value) {
-        $datum[$key] = "\"$value\"";
-      }
-      $output[] = implode($config->fieldSeparator, $datum);
-    }
-    fwrite($fd, implode("\n", $output));
-    fclose($fd);
-  }
-
-  /**
-   * Update the record with PK $id in the import database table.
-   *
-   * @deprecated - call setImportStatus directly as the parameters are simpler,
-   *
-   * @param int $id
-   * @param array $params
-   */
-  public function updateImportRecord($id, $params): void {
-    $this->setImportStatus((int) $id, $params[$this->_statusFieldName] ?? '', $params["{$this->_statusFieldName}Msg"] ?? '');
-  }
-
-  /**
-   * Set the import status for the given record.
-   *
-   * If this is a sql import then the sql table will be used and the update
-   * will not happen as the relevant fields don't exist in the table - hence
-   * the checks that statusField & primary key are set.
-   *
-   * @param int $id
-   * @param string $status
-   * @param string $message
-   */
-  public function setImportStatus(int $id, string $status, string $message): void {
-    if ($this->_statusFieldName && $this->_primaryKeyName) {
-      CRM_Core_DAO::executeQuery("
-        UPDATE $this->_tableName
-        SET $this->_statusFieldName = %1,
-          {$this->_statusFieldName}Msg = %2
-        WHERE  $this->_primaryKeyName = %3
-      ", [
-        1 => [$status, 'String'],
-        2 => [$message, 'String'],
-        3 => [$id, 'Integer'],
-      ]);
-    }
-  }
-
-  /**
-   * Format contact parameters.
-   *
-   * @todo this function needs re-writing & re-merging into the main function.
-   *
-   * Here be dragons.
-   *
-   * @param array $values
-   * @param array $params
-   *
-   * @return bool
-   */
-  protected function formatContactParameters(&$values, &$params) {
-    // Crawl through the possible classes:
-    // Contact
-    //      Individual
-    //      Household
-    //      Organization
-    //          Location
-    //              Address
-    //              Email
-    //              Phone
-    //              IM
-    //      Note
-    //      Custom
-
-    // first add core contact values since for other Civi modules they are not added
-    $contactFields = CRM_Contact_DAO_Contact::fields();
-    _civicrm_api3_store_values($contactFields, $values, $params);
-
-    if (isset($values['contact_type'])) {
-      // we're an individual/household/org property
-
-      $fields[$values['contact_type']] = CRM_Contact_DAO_Contact::fields();
-
-      _civicrm_api3_store_values($fields[$values['contact_type']], $values, $params);
-      return TRUE;
-    }
-
-    // Cache the various object fields
-    // @todo - remove this after confirming this is just a compilation of other-wise-cached fields.
-    static $fields = [];
-
-    if (isset($values['individual_prefix'])) {
-      if (!empty($params['prefix_id'])) {
-        $prefixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id');
-        $params['prefix'] = $prefixes[$params['prefix_id']];
-      }
-      else {
-        $params['prefix'] = $values['individual_prefix'];
-      }
-      return TRUE;
-    }
-
-    if (isset($values['individual_suffix'])) {
-      if (!empty($params['suffix_id'])) {
-        $suffixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id');
-        $params['suffix'] = $suffixes[$params['suffix_id']];
-      }
-      else {
-        $params['suffix'] = $values['individual_suffix'];
-      }
-      return TRUE;
-    }
-
-    // CRM-4575
-    if (isset($values['email_greeting'])) {
-      if (!empty($params['email_greeting_id'])) {
-        $emailGreetingFilter = [
-          'contact_type' => $params['contact_type'] ?? NULL,
-          'greeting_type' => 'email_greeting',
-        ];
-        $emailGreetings = CRM_Core_PseudoConstant::greeting($emailGreetingFilter);
-        $params['email_greeting'] = $emailGreetings[$params['email_greeting_id']];
-      }
-      else {
-        $params['email_greeting'] = $values['email_greeting'];
-      }
-
-      return TRUE;
-    }
-
-    if (isset($values['postal_greeting'])) {
-      if (!empty($params['postal_greeting_id'])) {
-        $postalGreetingFilter = [
-          'contact_type' => $params['contact_type'] ?? NULL,
-          'greeting_type' => 'postal_greeting',
-        ];
-        $postalGreetings = CRM_Core_PseudoConstant::greeting($postalGreetingFilter);
-        $params['postal_greeting'] = $postalGreetings[$params['postal_greeting_id']];
-      }
-      else {
-        $params['postal_greeting'] = $values['postal_greeting'];
-      }
-      return TRUE;
-    }
-
-    if (isset($values['addressee'])) {
-      $params['addressee'] = $values['addressee'];
-      return TRUE;
-    }
-
-    if (isset($values['gender'])) {
-      if (!empty($params['gender_id'])) {
-        $genders = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id');
-        $params['gender'] = $genders[$params['gender_id']];
-      }
-      else {
-        $params['gender'] = $values['gender'];
-      }
-      return TRUE;
-    }
-
-    if (!empty($values['preferred_communication_method'])) {
-      $comm = [];
-      $pcm = array_change_key_case(array_flip(CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method')), CASE_LOWER);
-
-      $preffComm = explode(',', $values['preferred_communication_method']);
-      foreach ($preffComm as $v) {
-        $v = strtolower(trim($v));
-        if (array_key_exists($v, $pcm)) {
-          $comm[$pcm[$v]] = 1;
-        }
-      }
-
-      $params['preferred_communication_method'] = $comm;
-      return TRUE;
-    }
-
-    // format the website params.
-    if (!empty($values['url'])) {
-      static $websiteFields;
-      if (!is_array($websiteFields)) {
-        $websiteFields = CRM_Core_DAO_Website::fields();
-      }
-      if (!array_key_exists('website', $params) ||
-        !is_array($params['website'])
-      ) {
-        $params['website'] = [];
-      }
-
-      $websiteCount = count($params['website']);
-      _civicrm_api3_store_values($websiteFields, $values,
-        $params['website'][++$websiteCount]
-      );
-
-      return TRUE;
-    }
-
-    if (isset($values['note'])) {
-      // add a note field
-      if (!isset($params['note'])) {
-        $params['note'] = [];
-      }
-      $noteBlock = count($params['note']) + 1;
-
-      $params['note'][$noteBlock] = [];
-      if (!isset($fields['Note'])) {
-        $fields['Note'] = CRM_Core_DAO_Note::fields();
-      }
-
-      // get the current logged in civicrm user
-      $session = CRM_Core_Session::singleton();
-      $userID = $session->get('userID');
-
-      if ($userID) {
-        $values['contact_id'] = $userID;
-      }
-
-      _civicrm_api3_store_values($fields['Note'], $values, $params['note'][$noteBlock]);
-
-      return TRUE;
-    }
-
-    // Check for custom field values
-    $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $values),
-      FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE
-    );
-
-    foreach ($values as $key => $value) {
-      if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
-        // check if it's a valid custom field id
-
-        if (!array_key_exists($customFieldID, $customFields)) {
-          return civicrm_api3_create_error('Invalid custom field ID');
-        }
-        else {
-          $params[$key] = $value;
-        }
-      }
-    }
-    return TRUE;
-  }
-
-  /**
-   * Format location block ready for importing.
-   *
-   * There is some test coverage for this in CRM_Contact_Import_Parser_ContactTest
-   * e.g. testImportPrimaryAddress.
-   *
-   * @param array $values
-   * @param array $params
-   *
-   * @return bool
-   */
-  protected function formatLocationBlock(&$values, &$params) {
-    $blockTypes = [
-      'phone' => 'Phone',
-      'email' => 'Email',
-      'im' => 'IM',
-      'openid' => 'OpenID',
-      'phone_ext' => 'Phone',
-    ];
-    foreach ($blockTypes as $blockFieldName => $block) {
-      if (!array_key_exists($blockFieldName, $values)) {
-        continue;
-      }
-      $blockIndex = $values['location_type_id'] . (!empty($values['phone_type_id']) ? '_' . $values['phone_type_id'] : '');
-
-      // block present in value array.
-      if (!array_key_exists($blockFieldName, $params) || !is_array($params[$blockFieldName])) {
-        $params[$blockFieldName] = [];
-      }
-
-      $fields[$block] = $this->getMetadataForEntity($block);
-
-      // copy value to dao field name.
-      if ($blockFieldName == 'im') {
-        $values['name'] = $values[$blockFieldName];
-      }
-
-      _civicrm_api3_store_values($fields[$block], $values,
-        $params[$blockFieldName][$blockIndex]
-      );
-
-      $this->fillPrimary($params[$blockFieldName][$blockIndex], $values, $block, CRM_Utils_Array::value('id', $params));
-
-      if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
-        $params[$blockFieldName][$blockIndex]['is_primary'] = TRUE;
-      }
-
-      // we only process single block at a time.
-      return TRUE;
-    }
-
-    // handle address fields.
-    if (!array_key_exists('address', $params) || !is_array($params['address'])) {
-      $params['address'] = [];
-    }
-
-    // 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
-    if (!empty($values['location_type_id'])) {
-      static $customFields = [];
-      if (empty($customFields)) {
-        $customFields = CRM_Core_BAO_CustomField::getFields('Address');
-      }
-      // make a copy of values, as we going to make changes
-      $newValues = $values;
-      foreach ($values as $key => $val) {
-        $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key);
-        if ($customFieldID && array_key_exists($customFieldID, $customFields)) {
-
-          $htmlType = $customFields[$customFieldID]['html_type'] ?? NULL;
-          if (CRM_Core_BAO_CustomField::isSerialized($customFields[$customFieldID]) && $val) {
-            $mulValues = explode(',', $val);
-            $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE);
-            $newValues[$key] = [];
-            foreach ($mulValues as $v1) {
-              foreach ($customOption as $v2) {
-                if ((strtolower($v2['label']) == strtolower(trim($v1))) ||
-                  (strtolower($v2['value']) == strtolower(trim($v1)))
-                ) {
-                  if ($htmlType == 'CheckBox') {
-                    $newValues[$key][$v2['value']] = 1;
-                  }
-                  else {
-                    $newValues[$key][] = $v2['value'];
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-      // consider new values
-      $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 = [
-      'county',
-      'country',
-      'state_province',
-      'supplemental_address_1',
-      'supplemental_address_2',
-      'supplemental_address_3',
-      'StateProvince.name',
-    ];
-    foreach (array_keys($customFields) as $customFieldID) {
-      $addressFields[] = 'custom_' . $customFieldID;
-    }
-
-    foreach ($addressFields as $field) {
-      if (array_key_exists($field, $values)) {
-        if (!array_key_exists('address', $params)) {
-          $params['address'] = [];
-        }
-        $params['address'][$values['location_type_id']][$field] = $values[$field];
-      }
-    }
-
-    $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 ($contactID) {
-        $primary = civicrm_api3($entity, 'get', [
-          'return' => 'location_type_id',
-          'contact_id' => $contactID,
-          'is_primary' => 1,
-          'sequential' => 1,
-        ]);
-      }
-      $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
-      $params['location_type_id'] = (int) (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
-      $params['is_primary'] = 1;
-    }
-  }
-
-}
index c46a60338f9afacace83de426b8b31ea46db0b94..9c0fddb9881041b3d65704fc71126551b5e35d84 100644 (file)
@@ -23,7 +23,7 @@ require_once 'api/v3/utils.php';
 /**
  * class to parse contact csv files
  */
-class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser {
+class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser {
 
   use CRM_Contact_Import_MetadataTrait;
 
@@ -95,6 +95,60 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser {
    */
   protected $_unparsedStreetAddressContacts;
 
+  protected $_tableName;
+
+  /**
+   * Total number of lines in file
+   *
+   * @var int
+   */
+  protected $_rowCount;
+
+  /**
+   * Running total number of un-matched Contacts.
+   *
+   * @var int
+   */
+  protected $_unMatchCount;
+
+  /**
+   * Array of unmatched lines.
+   *
+   * @var array
+   */
+  protected $_unMatch;
+
+  /**
+   * Total number of contacts with unparsed addresses
+   * @var int
+   */
+  protected $_unparsedAddressCount;
+
+  /**
+   * Filename of mismatch data
+   *
+   * @var string
+   */
+  protected $_misMatchFilemName;
+
+  protected $_primaryKeyName;
+  protected $_statusFieldName;
+
+  protected $fieldMetadata = [];
+  /**
+   * On duplicate
+   *
+   * @var int
+   */
+  public $_onDuplicate;
+
+  /**
+   * Dedupe rule group id to use if set
+   *
+   * @var int
+   */
+  public $_dedupeRuleGroupID = NULL;
+
   /**
    * Class constructor.
    *
@@ -2495,4 +2549,1023 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser {
     }
   }
 
+  /**
+   * Run import.
+   *
+   * @param string $tableName
+   * @param array $mapper
+   * @param int $mode
+   * @param int $contactType
+   * @param string $primaryKeyName
+   * @param string $statusFieldName
+   * @param int $onDuplicate
+   * @param int $statusID
+   * @param int $totalRowCount
+   * @param bool $doGeocodeAddress
+   * @param int $timeout
+   * @param string $contactSubType
+   * @param int $dedupeRuleGroupID
+   *
+   * @return mixed
+   */
+  public function run(
+    $tableName,
+    $mapper = [],
+    $mode = self::MODE_PREVIEW,
+    $contactType = self::CONTACT_INDIVIDUAL,
+    $primaryKeyName = '_id',
+    $statusFieldName = '_status',
+    $onDuplicate = self::DUPLICATE_SKIP,
+    $statusID = NULL,
+    $totalRowCount = NULL,
+    $doGeocodeAddress = FALSE,
+    $timeout = CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
+    $contactSubType = NULL,
+    $dedupeRuleGroupID = NULL
+  ) {
+
+    // TODO: Make the timeout actually work
+    $this->_onDuplicate = $onDuplicate;
+    $this->_dedupeRuleGroupID = $dedupeRuleGroupID;
+
+    switch ($contactType) {
+      case CRM_Import_Parser::CONTACT_INDIVIDUAL:
+        $this->_contactType = 'Individual';
+        break;
+
+      case CRM_Import_Parser::CONTACT_HOUSEHOLD:
+        $this->_contactType = 'Household';
+        break;
+
+      case CRM_Import_Parser::CONTACT_ORGANIZATION:
+        $this->_contactType = 'Organization';
+    }
+
+    $this->_contactSubType = $contactSubType;
+
+    $this->init();
+
+    $this->_rowCount = $this->_warningCount = 0;
+    $this->_invalidRowCount = $this->_validCount = 0;
+    $this->_totalCount = $this->_conflictCount = 0;
+
+    $this->_errors = [];
+    $this->_warnings = [];
+    $this->_conflicts = [];
+    $this->_unparsedAddresses = [];
+
+    $this->_tableName = $tableName;
+    $this->_primaryKeyName = $primaryKeyName;
+    $this->_statusFieldName = $statusFieldName;
+
+    if ($mode == self::MODE_MAPFIELD) {
+      $this->_rows = [];
+    }
+    else {
+      $this->_activeFieldCount = count($this->_activeFields);
+    }
+
+    if ($mode == self::MODE_IMPORT) {
+      //get the key of email field
+      foreach ($mapper as $key => $value) {
+        if (strtolower($value) == 'email') {
+          $emailKey = $key;
+          break;
+        }
+      }
+    }
+
+    if ($statusID) {
+      $this->progressImport($statusID);
+      $startTimestamp = $currTimestamp = $prevTimestamp = time();
+    }
+    // get the contents of the temp. import table
+    $query = "SELECT * FROM $tableName";
+    if ($mode == self::MODE_IMPORT) {
+      $query .= " WHERE $statusFieldName = 'NEW'";
+    }
+
+    $result = CRM_Core_DAO::executeQuery($query);
+
+    while ($result->fetch()) {
+      $values = array_values($result->toArray());
+      $this->_rowCount++;
+
+      /* trim whitespace around the values */
+      foreach ($values as $k => $v) {
+        $values[$k] = trim($v, " \t\r\n");
+      }
+      if (CRM_Utils_System::isNull($values)) {
+        continue;
+      }
+
+      $this->_totalCount++;
+
+      if ($mode == self::MODE_MAPFIELD) {
+        $returnCode = $this->mapField($values);
+      }
+      elseif ($mode == self::MODE_PREVIEW) {
+        $returnCode = $this->preview($values);
+      }
+      elseif ($mode == self::MODE_SUMMARY) {
+        $returnCode = $this->summary($values);
+      }
+      elseif ($mode == self::MODE_IMPORT) {
+        //print "Running parser in import mode<br/>\n";
+        $returnCode = $this->import($onDuplicate, $values, $doGeocodeAddress);
+        if ($statusID && (($this->_rowCount % 50) == 0)) {
+          $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount);
+        }
+      }
+      else {
+        $returnCode = self::ERROR;
+      }
+
+      // note that a line could be valid but still produce a warning
+      if ($returnCode & self::VALID) {
+        $this->_validCount++;
+        if ($mode == self::MODE_MAPFIELD) {
+          $this->_rows[] = $values;
+          $this->_activeFieldCount = max($this->_activeFieldCount, count($values));
+        }
+      }
+
+      if ($returnCode & self::WARNING) {
+        $this->_warningCount++;
+        if ($this->_warningCount < $this->_maxWarningCount) {
+          $this->_warningCount[] = $line;
+        }
+      }
+
+      if ($returnCode & self::ERROR) {
+        $this->_invalidRowCount++;
+        array_unshift($values, $this->_rowCount);
+        $this->_errors[] = $values;
+      }
+
+      if ($returnCode & self::CONFLICT) {
+        $this->_conflictCount++;
+        array_unshift($values, $this->_rowCount);
+        $this->_conflicts[] = $values;
+      }
+
+      if ($returnCode & self::NO_MATCH) {
+        $this->_unMatchCount++;
+        array_unshift($values, $this->_rowCount);
+        $this->_unMatch[] = $values;
+      }
+
+      if ($returnCode & self::DUPLICATE) {
+        $this->_duplicateCount++;
+        array_unshift($values, $this->_rowCount);
+        $this->_duplicates[] = $values;
+        if ($onDuplicate != self::DUPLICATE_SKIP) {
+          $this->_validCount++;
+        }
+      }
+
+      if ($returnCode & self::UNPARSED_ADDRESS_WARNING) {
+        $this->_unparsedAddressCount++;
+        array_unshift($values, $this->_rowCount);
+        $this->_unparsedAddresses[] = $values;
+      }
+      // we give the derived class a way of aborting the process
+      // note that the return code could be multiple code or'ed together
+      if ($returnCode & self::STOP) {
+        break;
+      }
+
+      // if we are done processing the maxNumber of lines, break
+      if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) {
+        break;
+      }
+
+      // see if we've hit our timeout yet
+      /* if ( $the_thing_with_the_stuff ) {
+      do_something( );
+      } */
+    }
+
+    if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) {
+      $customHeaders = $mapper;
+
+      $customfields = CRM_Core_BAO_CustomField::getFields($this->_contactType);
+      foreach ($customHeaders as $key => $value) {
+        if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) {
+          $customHeaders[$key] = $customfields[$id][0];
+        }
+      }
+
+      if ($this->_invalidRowCount) {
+        // removed view url for invlaid contacts
+        $headers = array_merge([
+          ts('Line Number'),
+          ts('Reason'),
+        ], $customHeaders);
+        $this->_errorFileName = self::errorFileName(self::ERROR);
+        self::exportCSV($this->_errorFileName, $headers, $this->_errors);
+      }
+      if ($this->_conflictCount) {
+        $headers = array_merge([
+          ts('Line Number'),
+          ts('Reason'),
+        ], $customHeaders);
+        $this->_conflictFileName = self::errorFileName(self::CONFLICT);
+        self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
+      }
+      if ($this->_duplicateCount) {
+        $headers = array_merge([
+          ts('Line Number'),
+          ts('View Contact URL'),
+        ], $customHeaders);
+
+        $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
+        self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
+      }
+      if ($this->_unMatchCount) {
+        $headers = array_merge([
+          ts('Line Number'),
+          ts('Reason'),
+        ], $customHeaders);
+
+        $this->_misMatchFilemName = self::errorFileName(self::NO_MATCH);
+        self::exportCSV($this->_misMatchFilemName, $headers, $this->_unMatch);
+      }
+      if ($this->_unparsedAddressCount) {
+        $headers = array_merge([
+          ts('Line Number'),
+          ts('Contact Edit URL'),
+        ], $customHeaders);
+        $this->_errorFileName = self::errorFileName(self::UNPARSED_ADDRESS_WARNING);
+        self::exportCSV($this->_errorFileName, $headers, $this->_unparsedAddresses);
+      }
+    }
+    //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
+    return $this->fini();
+  }
+
+  /**
+   * Given a list of the importable field keys that the user has selected.
+   * set the active fields array to this list
+   *
+   * @param array $fieldKeys
+   *   Mapped array of values.
+   */
+  public function setActiveFields($fieldKeys) {
+    $this->_activeFieldCount = count($fieldKeys);
+    foreach ($fieldKeys as $key) {
+      if (empty($this->_fields[$key])) {
+        $this->_activeFields[] = new CRM_Contact_Import_Field('', ts('- do not import -'));
+      }
+      else {
+        $this->_activeFields[] = clone($this->_fields[$key]);
+      }
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldLocationTypes($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_hasLocationType = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldPhoneTypes($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_phoneType = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldWebsiteTypes($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_websiteType = $elements[$i];
+    }
+  }
+
+  /**
+   * Set IM Service Provider type fields.
+   *
+   * @param array $elements
+   *   IM service provider type ids.
+   */
+  public function setActiveFieldImProviders($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_imProvider = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldRelated($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_related = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldRelatedContactType($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_relatedContactType = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldRelatedContactDetails($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_relatedContactDetails = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldRelatedContactLocType($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_relatedContactLocType = $elements[$i];
+    }
+  }
+
+  /**
+   * Set active field for related contact's phone type.
+   *
+   * @param array $elements
+   */
+  public function setActiveFieldRelatedContactPhoneType($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_relatedContactPhoneType = $elements[$i];
+    }
+  }
+
+  /**
+   * @param $elements
+   */
+  public function setActiveFieldRelatedContactWebsiteType($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_relatedContactWebsiteType = $elements[$i];
+    }
+  }
+
+  /**
+   * Set IM Service Provider type fields for related contacts.
+   *
+   * @param array $elements
+   *   IM service provider type ids of related contact.
+   */
+  public function setActiveFieldRelatedContactImProvider($elements) {
+    for ($i = 0; $i < count($elements); $i++) {
+      $this->_activeFields[$i]->_relatedContactImProvider = $elements[$i];
+    }
+  }
+
+  /**
+   * Format the field values for input to the api.
+   *
+   * @return array
+   *   (reference ) associative array of name/value pairs
+   */
+  public function &getActiveFieldParams() {
+    $params = [];
+
+    for ($i = 0; $i < $this->_activeFieldCount; $i++) {
+      if ($this->_activeFields[$i]->_name == 'do_not_import') {
+        continue;
+      }
+
+      if (isset($this->_activeFields[$i]->_value)) {
+        if (isset($this->_activeFields[$i]->_hasLocationType)) {
+          if (!isset($params[$this->_activeFields[$i]->_name])) {
+            $params[$this->_activeFields[$i]->_name] = [];
+          }
+
+          $value = [
+            $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
+            'location_type_id' => $this->_activeFields[$i]->_hasLocationType,
+          ];
+
+          if (isset($this->_activeFields[$i]->_phoneType)) {
+            $value['phone_type_id'] = $this->_activeFields[$i]->_phoneType;
+          }
+
+          // get IM service Provider type id
+          if (isset($this->_activeFields[$i]->_imProvider)) {
+            $value['provider_id'] = $this->_activeFields[$i]->_imProvider;
+          }
+
+          $params[$this->_activeFields[$i]->_name][] = $value;
+        }
+        elseif (isset($this->_activeFields[$i]->_websiteType)) {
+          $value = [
+            $this->_activeFields[$i]->_name => $this->_activeFields[$i]->_value,
+            'website_type_id' => $this->_activeFields[$i]->_websiteType,
+          ];
+
+          $params[$this->_activeFields[$i]->_name][] = $value;
+        }
+
+        if (!isset($params[$this->_activeFields[$i]->_name])) {
+          if (!isset($this->_activeFields[$i]->_related)) {
+            $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value;
+          }
+        }
+
+        //minor fix for CRM-4062
+        if (isset($this->_activeFields[$i]->_related)) {
+          if (!isset($params[$this->_activeFields[$i]->_related])) {
+            $params[$this->_activeFields[$i]->_related] = [];
+          }
+
+          if (!isset($params[$this->_activeFields[$i]->_related]['contact_type']) && !empty($this->_activeFields[$i]->_relatedContactType)) {
+            $params[$this->_activeFields[$i]->_related]['contact_type'] = $this->_activeFields[$i]->_relatedContactType;
+          }
+
+          if (isset($this->_activeFields[$i]->_relatedContactLocType) && !empty($this->_activeFields[$i]->_value)) {
+            if (!empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails]) &&
+              !is_array($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])
+            ) {
+              $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
+            }
+            $value = [
+              $this->_activeFields[$i]->_relatedContactDetails => $this->_activeFields[$i]->_value,
+              'location_type_id' => $this->_activeFields[$i]->_relatedContactLocType,
+            ];
+
+            if (isset($this->_activeFields[$i]->_relatedContactPhoneType)) {
+              $value['phone_type_id'] = $this->_activeFields[$i]->_relatedContactPhoneType;
+            }
+
+            // get IM service Provider type id for related contact
+            if (isset($this->_activeFields[$i]->_relatedContactImProvider)) {
+              $value['provider_id'] = $this->_activeFields[$i]->_relatedContactImProvider;
+            }
+
+            $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = $value;
+          }
+          elseif (isset($this->_activeFields[$i]->_relatedContactWebsiteType)) {
+            $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails][] = [
+              'url' => $this->_activeFields[$i]->_value,
+              'website_type_id' => $this->_activeFields[$i]->_relatedContactWebsiteType,
+            ];
+          }
+          elseif (empty($this->_activeFields[$i]->_value) && isset($this->_activeFields[$i]->_relatedContactLocType)) {
+            if (empty($params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails])) {
+              $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = [];
+            }
+          }
+          else {
+            $params[$this->_activeFields[$i]->_related][$this->_activeFields[$i]->_relatedContactDetails] = $this->_activeFields[$i]->_value;
+          }
+        }
+      }
+    }
+
+    return $params;
+  }
+
+  /**
+   * @param string $name
+   * @param $title
+   * @param int $type
+   * @param string $headerPattern
+   * @param string $dataPattern
+   * @param bool $hasLocationType
+   */
+  public function addField(
+    $name, $title, $type = CRM_Utils_Type::T_INT,
+    $headerPattern = '//', $dataPattern = '//',
+    $hasLocationType = FALSE
+  ) {
+    $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
+    if (empty($name)) {
+      $this->_fields['doNotImport'] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, $hasLocationType);
+    }
+  }
+
+  /**
+   * Store parser values.
+   *
+   * @param CRM_Core_Session $store
+   *
+   * @param int $mode
+   */
+  public function set($store, $mode = self::MODE_SUMMARY) {
+    $store->set('rowCount', $this->_rowCount);
+    $store->set('fields', $this->getSelectValues());
+    $store->set('fieldTypes', $this->getSelectTypes());
+
+    $store->set('columnCount', $this->_activeFieldCount);
+
+    $store->set('totalRowCount', $this->_totalCount);
+    $store->set('validRowCount', $this->_validCount);
+    $store->set('invalidRowCount', $this->_invalidRowCount);
+    $store->set('conflictRowCount', $this->_conflictCount);
+    $store->set('unMatchCount', $this->_unMatchCount);
+
+    switch ($this->_contactType) {
+      case 'Individual':
+        $store->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
+        break;
+
+      case 'Household':
+        $store->set('contactType', CRM_Import_Parser::CONTACT_HOUSEHOLD);
+        break;
+
+      case 'Organization':
+        $store->set('contactType', CRM_Import_Parser::CONTACT_ORGANIZATION);
+    }
+
+    if ($this->_invalidRowCount) {
+      $store->set('errorsFileName', $this->_errorFileName);
+    }
+    if ($this->_conflictCount) {
+      $store->set('conflictsFileName', $this->_conflictFileName);
+    }
+    if (isset($this->_rows) && !empty($this->_rows)) {
+      $store->set('dataValues', $this->_rows);
+    }
+
+    if ($this->_unMatchCount) {
+      $store->set('mismatchFileName', $this->_misMatchFilemName);
+    }
+
+    if ($mode == self::MODE_IMPORT) {
+      $store->set('duplicateRowCount', $this->_duplicateCount);
+      $store->set('unparsedAddressCount', $this->_unparsedAddressCount);
+      if ($this->_duplicateCount) {
+        $store->set('duplicatesFileName', $this->_duplicateFileName);
+      }
+      if ($this->_unparsedAddressCount) {
+        $store->set('errorsFileName', $this->_errorFileName);
+      }
+    }
+    //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount";
+  }
+
+  /**
+   * Export data to a CSV file.
+   *
+   * @param string $fileName
+   * @param array $header
+   * @param array $data
+   */
+  public static function exportCSV($fileName, $header, $data) {
+
+    if (file_exists($fileName) && !is_writable($fileName)) {
+      CRM_Core_Error::movedSiteError($fileName);
+    }
+    //hack to remove '_status', '_statusMsg' and '_id' from error file
+    $errorValues = [];
+    $dbRecordStatus = ['IMPORTED', 'ERROR', 'DUPLICATE', 'INVALID', 'NEW'];
+    foreach ($data as $rowCount => $rowValues) {
+      $count = 0;
+      foreach ($rowValues as $key => $val) {
+        if (in_array($val, $dbRecordStatus) && $count == (count($rowValues) - 3)) {
+          break;
+        }
+        $errorValues[$rowCount][$key] = $val;
+        $count++;
+      }
+    }
+    $data = $errorValues;
+
+    $output = [];
+    $fd = fopen($fileName, 'w');
+
+    foreach ($header as $key => $value) {
+      $header[$key] = "\"$value\"";
+    }
+    $config = CRM_Core_Config::singleton();
+    $output[] = implode($config->fieldSeparator, $header);
+
+    foreach ($data as $datum) {
+      foreach ($datum as $key => $value) {
+        $datum[$key] = "\"$value\"";
+      }
+      $output[] = implode($config->fieldSeparator, $datum);
+    }
+    fwrite($fd, implode("\n", $output));
+    fclose($fd);
+  }
+
+  /**
+   * Update the record with PK $id in the import database table.
+   *
+   * @deprecated - call setImportStatus directly as the parameters are simpler,
+   *
+   * @param int $id
+   * @param array $params
+   */
+  public function updateImportRecord($id, $params): void {
+    $this->setImportStatus((int) $id, $params[$this->_statusFieldName] ?? '', $params["{$this->_statusFieldName}Msg"] ?? '');
+  }
+
+  /**
+   * Set the import status for the given record.
+   *
+   * If this is a sql import then the sql table will be used and the update
+   * will not happen as the relevant fields don't exist in the table - hence
+   * the checks that statusField & primary key are set.
+   *
+   * @param int $id
+   * @param string $status
+   * @param string $message
+   */
+  public function setImportStatus(int $id, string $status, string $message): void {
+    if ($this->_statusFieldName && $this->_primaryKeyName) {
+      CRM_Core_DAO::executeQuery("
+        UPDATE $this->_tableName
+        SET $this->_statusFieldName = %1,
+          {$this->_statusFieldName}Msg = %2
+        WHERE  $this->_primaryKeyName = %3
+      ", [
+        1 => [$status, 'String'],
+        2 => [$message, 'String'],
+        3 => [$id, 'Integer'],
+      ]);
+    }
+  }
+
+  /**
+   * Format contact parameters.
+   *
+   * @todo this function needs re-writing & re-merging into the main function.
+   *
+   * Here be dragons.
+   *
+   * @param array $values
+   * @param array $params
+   *
+   * @return bool
+   */
+  protected function formatContactParameters(&$values, &$params) {
+    // Crawl through the possible classes:
+    // Contact
+    //      Individual
+    //      Household
+    //      Organization
+    //          Location
+    //              Address
+    //              Email
+    //              Phone
+    //              IM
+    //      Note
+    //      Custom
+
+    // first add core contact values since for other Civi modules they are not added
+    $contactFields = CRM_Contact_DAO_Contact::fields();
+    _civicrm_api3_store_values($contactFields, $values, $params);
+
+    if (isset($values['contact_type'])) {
+      // we're an individual/household/org property
+
+      $fields[$values['contact_type']] = CRM_Contact_DAO_Contact::fields();
+
+      _civicrm_api3_store_values($fields[$values['contact_type']], $values, $params);
+      return TRUE;
+    }
+
+    // Cache the various object fields
+    // @todo - remove this after confirming this is just a compilation of other-wise-cached fields.
+    static $fields = [];
+
+    if (isset($values['individual_prefix'])) {
+      if (!empty($params['prefix_id'])) {
+        $prefixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id');
+        $params['prefix'] = $prefixes[$params['prefix_id']];
+      }
+      else {
+        $params['prefix'] = $values['individual_prefix'];
+      }
+      return TRUE;
+    }
+
+    if (isset($values['individual_suffix'])) {
+      if (!empty($params['suffix_id'])) {
+        $suffixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id');
+        $params['suffix'] = $suffixes[$params['suffix_id']];
+      }
+      else {
+        $params['suffix'] = $values['individual_suffix'];
+      }
+      return TRUE;
+    }
+
+    // CRM-4575
+    if (isset($values['email_greeting'])) {
+      if (!empty($params['email_greeting_id'])) {
+        $emailGreetingFilter = [
+          'contact_type' => $params['contact_type'] ?? NULL,
+          'greeting_type' => 'email_greeting',
+        ];
+        $emailGreetings = CRM_Core_PseudoConstant::greeting($emailGreetingFilter);
+        $params['email_greeting'] = $emailGreetings[$params['email_greeting_id']];
+      }
+      else {
+        $params['email_greeting'] = $values['email_greeting'];
+      }
+
+      return TRUE;
+    }
+
+    if (isset($values['postal_greeting'])) {
+      if (!empty($params['postal_greeting_id'])) {
+        $postalGreetingFilter = [
+          'contact_type' => $params['contact_type'] ?? NULL,
+          'greeting_type' => 'postal_greeting',
+        ];
+        $postalGreetings = CRM_Core_PseudoConstant::greeting($postalGreetingFilter);
+        $params['postal_greeting'] = $postalGreetings[$params['postal_greeting_id']];
+      }
+      else {
+        $params['postal_greeting'] = $values['postal_greeting'];
+      }
+      return TRUE;
+    }
+
+    if (isset($values['addressee'])) {
+      $params['addressee'] = $values['addressee'];
+      return TRUE;
+    }
+
+    if (isset($values['gender'])) {
+      if (!empty($params['gender_id'])) {
+        $genders = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id');
+        $params['gender'] = $genders[$params['gender_id']];
+      }
+      else {
+        $params['gender'] = $values['gender'];
+      }
+      return TRUE;
+    }
+
+    if (!empty($values['preferred_communication_method'])) {
+      $comm = [];
+      $pcm = array_change_key_case(array_flip(CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method')), CASE_LOWER);
+
+      $preffComm = explode(',', $values['preferred_communication_method']);
+      foreach ($preffComm as $v) {
+        $v = strtolower(trim($v));
+        if (array_key_exists($v, $pcm)) {
+          $comm[$pcm[$v]] = 1;
+        }
+      }
+
+      $params['preferred_communication_method'] = $comm;
+      return TRUE;
+    }
+
+    // format the website params.
+    if (!empty($values['url'])) {
+      static $websiteFields;
+      if (!is_array($websiteFields)) {
+        $websiteFields = CRM_Core_DAO_Website::fields();
+      }
+      if (!array_key_exists('website', $params) ||
+        !is_array($params['website'])
+      ) {
+        $params['website'] = [];
+      }
+
+      $websiteCount = count($params['website']);
+      _civicrm_api3_store_values($websiteFields, $values,
+        $params['website'][++$websiteCount]
+      );
+
+      return TRUE;
+    }
+
+    if (isset($values['note'])) {
+      // add a note field
+      if (!isset($params['note'])) {
+        $params['note'] = [];
+      }
+      $noteBlock = count($params['note']) + 1;
+
+      $params['note'][$noteBlock] = [];
+      if (!isset($fields['Note'])) {
+        $fields['Note'] = CRM_Core_DAO_Note::fields();
+      }
+
+      // get the current logged in civicrm user
+      $session = CRM_Core_Session::singleton();
+      $userID = $session->get('userID');
+
+      if ($userID) {
+        $values['contact_id'] = $userID;
+      }
+
+      _civicrm_api3_store_values($fields['Note'], $values, $params['note'][$noteBlock]);
+
+      return TRUE;
+    }
+
+    // Check for custom field values
+    $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $values),
+      FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE
+    );
+
+    foreach ($values as $key => $value) {
+      if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
+        // check if it's a valid custom field id
+
+        if (!array_key_exists($customFieldID, $customFields)) {
+          return civicrm_api3_create_error('Invalid custom field ID');
+        }
+        else {
+          $params[$key] = $value;
+        }
+      }
+    }
+    return TRUE;
+  }
+
+  /**
+   * Format location block ready for importing.
+   *
+   * There is some test coverage for this in CRM_Contact_Import_Parser_ContactTest
+   * e.g. testImportPrimaryAddress.
+   *
+   * @param array $values
+   * @param array $params
+   *
+   * @return bool
+   */
+  protected function formatLocationBlock(&$values, &$params) {
+    $blockTypes = [
+      'phone' => 'Phone',
+      'email' => 'Email',
+      'im' => 'IM',
+      'openid' => 'OpenID',
+      'phone_ext' => 'Phone',
+    ];
+    foreach ($blockTypes as $blockFieldName => $block) {
+      if (!array_key_exists($blockFieldName, $values)) {
+        continue;
+      }
+      $blockIndex = $values['location_type_id'] . (!empty($values['phone_type_id']) ? '_' . $values['phone_type_id'] : '');
+
+      // block present in value array.
+      if (!array_key_exists($blockFieldName, $params) || !is_array($params[$blockFieldName])) {
+        $params[$blockFieldName] = [];
+      }
+
+      $fields[$block] = $this->getMetadataForEntity($block);
+
+      // copy value to dao field name.
+      if ($blockFieldName == 'im') {
+        $values['name'] = $values[$blockFieldName];
+      }
+
+      _civicrm_api3_store_values($fields[$block], $values,
+        $params[$blockFieldName][$blockIndex]
+      );
+
+      $this->fillPrimary($params[$blockFieldName][$blockIndex], $values, $block, CRM_Utils_Array::value('id', $params));
+
+      if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
+        $params[$blockFieldName][$blockIndex]['is_primary'] = TRUE;
+      }
+
+      // we only process single block at a time.
+      return TRUE;
+    }
+
+    // handle address fields.
+    if (!array_key_exists('address', $params) || !is_array($params['address'])) {
+      $params['address'] = [];
+    }
+
+    // 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
+    if (!empty($values['location_type_id'])) {
+      static $customFields = [];
+      if (empty($customFields)) {
+        $customFields = CRM_Core_BAO_CustomField::getFields('Address');
+      }
+      // make a copy of values, as we going to make changes
+      $newValues = $values;
+      foreach ($values as $key => $val) {
+        $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key);
+        if ($customFieldID && array_key_exists($customFieldID, $customFields)) {
+
+          $htmlType = $customFields[$customFieldID]['html_type'] ?? NULL;
+          if (CRM_Core_BAO_CustomField::isSerialized($customFields[$customFieldID]) && $val) {
+            $mulValues = explode(',', $val);
+            $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE);
+            $newValues[$key] = [];
+            foreach ($mulValues as $v1) {
+              foreach ($customOption as $v2) {
+                if ((strtolower($v2['label']) == strtolower(trim($v1))) ||
+                  (strtolower($v2['value']) == strtolower(trim($v1)))
+                ) {
+                  if ($htmlType == 'CheckBox') {
+                    $newValues[$key][$v2['value']] = 1;
+                  }
+                  else {
+                    $newValues[$key][] = $v2['value'];
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      // consider new values
+      $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 = [
+      'county',
+      'country',
+      'state_province',
+      'supplemental_address_1',
+      'supplemental_address_2',
+      'supplemental_address_3',
+      'StateProvince.name',
+    ];
+    foreach (array_keys($customFields) as $customFieldID) {
+      $addressFields[] = 'custom_' . $customFieldID;
+    }
+
+    foreach ($addressFields as $field) {
+      if (array_key_exists($field, $values)) {
+        if (!array_key_exists('address', $params)) {
+          $params['address'] = [];
+        }
+        $params['address'][$values['location_type_id']][$field] = $values[$field];
+      }
+    }
+
+    $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 ($contactID) {
+        $primary = civicrm_api3($entity, 'get', [
+          'return' => 'location_type_id',
+          'contact_id' => $contactID,
+          'is_primary' => 1,
+          'sequential' => 1,
+        ]);
+      }
+      $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
+      $params['location_type_id'] = (int) (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
+      $params['is_primary'] = 1;
+    }
+  }
+
 }
index a8dbcdde44136b72eb8d49beadc2e1b0b5131a1a..e07d3b2398a8a79f8053670ef6b5f5fc87ce296f 100644 (file)
@@ -13,8 +13,6 @@
  *
  * @package CRM
  * @copyright CiviCRM LLC https://civicrm.org/licensing
- * $Id: $
- *
  */
 
 /**
diff --git a/CRM/Core/BAO/UserJob.php b/CRM/Core/BAO/UserJob.php
new file mode 100644 (file)
index 0000000..29e7a69
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+
+/**
+ * This class contains user jobs functionality.
+ */
+class CRM_Core_BAO_UserJob extends CRM_Core_DAO_UserJob {
+
+  /**
+   * Get the statuses for Import Jobs.
+   *
+   * @return array
+   */
+  public static function getStatuses(): array {
+    return [
+      [
+        'id' => 1,
+        'name' => 'completed',
+        'label' => ts('Completed'),
+      ],
+      [
+        'id' => 2,
+        'name' => 'scheduled',
+        'label' => ts('Scheduled'),
+      ],
+      [
+        'id' => 3,
+        'name' => 'in_progress',
+        'label' => ts('In Progress'),
+      ],
+    ];
+  }
+
+  /**
+   * Get the types Import Jobs.
+   *
+   * This is largely a placeholder at this stage. It will likely wind
+   * up as an option value so extensions can add different types.
+   *
+   * However, for now it just holds the one type being worked on.
+   *
+   * @return array
+   */
+  public static function getTypes(): array {
+    return [
+      [
+        'id' => 1,
+        'name' => 'contact_import',
+        'label' => ts('Contact Import'),
+      ],
+    ];
+  }
+
+}
index 5dd43a0831eb2637232db96998286477b30a97ab..872b1cddea28b99fa97c42fec3f159951548ff81 100644 (file)
@@ -367,6 +367,11 @@ return [
     'class' => 'CRM_Core_DAO_UFMatch',
     'table' => 'civicrm_uf_match',
   ],
+  'CRM_Core_DAO_UserJob' => [
+    'name' => 'UserJob',
+    'class' => 'CRM_Core_DAO_UserJob',
+    'table' => 'civicrm_user_job',
+  ],
   'CRM_Core_DAO_Timezone' => [
     'name' => 'Timezone',
     'class' => 'CRM_Core_DAO_Timezone',
diff --git a/CRM/Core/DAO/UserJob.php b/CRM/Core/DAO/UserJob.php
new file mode 100644 (file)
index 0000000..ebe7e1e
--- /dev/null
@@ -0,0 +1,436 @@
+<?php
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ *
+ * Generated from xml/schema/CRM/Core/UserJob.xml
+ * DO NOT EDIT.  Generated by CRM_Core_CodeGen
+ * (GenCodeChecksum:58e6fcaa028d157bfa074a073111239d)
+ */
+
+/**
+ * Database access object for the UserJob entity.
+ */
+class CRM_Core_DAO_UserJob extends CRM_Core_DAO {
+  const EXT = 'civicrm';
+  const TABLE_ADDED = '5.50';
+
+  /**
+   * Static instance to hold the table name.
+   *
+   * @var string
+   */
+  public static $_tableName = 'civicrm_user_job';
+
+  /**
+   * Should CiviCRM log any modifications to this table in the civicrm_log table.
+   *
+   * @var bool
+   */
+  public static $_log = FALSE;
+
+  /**
+   * Job ID
+   *
+   * @var int|string|null
+   *   (SQL type: int unsigned)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $id;
+
+  /**
+   * Unique name for job.
+   *
+   * @var string|null
+   *   (SQL type: varchar(64))
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $name;
+
+  /**
+   * FK to contact table.
+   *
+   * @var int|string|null
+   *   (SQL type: int unsigned)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $created_id;
+
+  /**
+   * Date and time this job was created.
+   *
+   * @var string
+   *   (SQL type: timestamp)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $created_date;
+
+  /**
+   * Date and time this import job started.
+   *
+   * @var string
+   *   (SQL type: timestamp)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $start_date;
+
+  /**
+   * Date and time this import job ended.
+   *
+   * @var string
+   *   (SQL type: timestamp)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $end_date;
+
+  /**
+   * Date and time to clean up after this import job (temp table deletion date).
+   *
+   * @var string
+   *   (SQL type: timestamp)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $expires_date;
+
+  /**
+   * @var int|string
+   *   (SQL type: int unsigned)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $status_id;
+
+  /**
+   * @var int|string
+   *   (SQL type: int unsigned)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $type_id;
+
+  /**
+   * FK to Queue
+   *
+   * @var int|string|null
+   *   (SQL type: int unsigned)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $queue_id;
+
+  /**
+   * Data pertaining to job configuration
+   *
+   * @var string|null
+   *   (SQL type: text)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $metadata;
+
+  /**
+   * Class constructor.
+   */
+  public function __construct() {
+    $this->__table = 'civicrm_user_job';
+    parent::__construct();
+  }
+
+  /**
+   * Returns localized title of this entity.
+   *
+   * @param bool $plural
+   *   Whether to return the plural version of the title.
+   */
+  public static function getEntityTitle($plural = FALSE) {
+    return $plural ? ts('User Jobs') : ts('User Job');
+  }
+
+  /**
+   * Returns foreign keys and entity references.
+   *
+   * @return array
+   *   [CRM_Core_Reference_Interface]
+   */
+  public static function getReferenceColumns() {
+    if (!isset(Civi::$statics[__CLASS__]['links'])) {
+      Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__);
+      Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), 'created_id', 'civicrm_contact', 'id');
+      Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), 'queue_id', 'civicrm_queue', 'id');
+      CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', Civi::$statics[__CLASS__]['links']);
+    }
+    return Civi::$statics[__CLASS__]['links'];
+  }
+
+  /**
+   * Returns all the column names of this table
+   *
+   * @return array
+   */
+  public static function &fields() {
+    if (!isset(Civi::$statics[__CLASS__]['fields'])) {
+      Civi::$statics[__CLASS__]['fields'] = [
+        'id' => [
+          'name' => 'id',
+          'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('User Job ID'),
+          'description' => ts('Job ID'),
+          'required' => TRUE,
+          'where' => 'civicrm_user_job.id',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'type' => 'Number',
+          ],
+          'readonly' => TRUE,
+          'add' => '5.50',
+        ],
+        'name' => [
+          'name' => 'name',
+          'type' => CRM_Utils_Type::T_STRING,
+          'title' => ts('User job name'),
+          'description' => ts('Unique name for job.'),
+          'maxlength' => 64,
+          'size' => CRM_Utils_Type::BIG,
+          'where' => 'civicrm_user_job.name',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'add' => '5.50',
+        ],
+        'created_id' => [
+          'name' => 'created_id',
+          'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('Created By Contact ID'),
+          'description' => ts('FK to contact table.'),
+          'where' => 'civicrm_user_job.created_id',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'FKClassName' => 'CRM_Contact_DAO_Contact',
+          'html' => [
+            'label' => ts("Created By"),
+          ],
+          'add' => '5.50',
+        ],
+        'created_date' => [
+          'name' => 'created_date',
+          'type' => CRM_Utils_Type::T_TIMESTAMP,
+          'title' => ts('Import Job Created Date'),
+          'description' => ts('Date and time this job was created.'),
+          'required' => TRUE,
+          'where' => 'civicrm_user_job.created_date',
+          'default' => 'CURRENT_TIMESTAMP',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'type' => 'Select Date',
+            'formatType' => 'activityDateTime',
+          ],
+          'readonly' => TRUE,
+          'add' => '5.50',
+        ],
+        'start_date' => [
+          'name' => 'start_date',
+          'type' => CRM_Utils_Type::T_TIMESTAMP,
+          'title' => ts('Import Job Started Date'),
+          'description' => ts('Date and time this import job started.'),
+          'required' => FALSE,
+          'where' => 'civicrm_user_job.start_date',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'type' => 'Select Date',
+            'formatType' => 'activityDateTime',
+          ],
+          'readonly' => TRUE,
+          'add' => '5.50',
+        ],
+        'end_date' => [
+          'name' => 'end_date',
+          'type' => CRM_Utils_Type::T_TIMESTAMP,
+          'title' => ts('Job Ended Date'),
+          'description' => ts('Date and time this import job ended.'),
+          'required' => FALSE,
+          'where' => 'civicrm_user_job.end_date',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'type' => 'Select Date',
+            'formatType' => 'activityDateTime',
+          ],
+          'add' => '5.50',
+        ],
+        'expires_date' => [
+          'name' => 'expires_date',
+          'type' => CRM_Utils_Type::T_TIMESTAMP,
+          'title' => ts('Import Job Expires Date'),
+          'description' => ts('Date and time to clean up after this import job (temp table deletion date).'),
+          'required' => FALSE,
+          'where' => 'civicrm_user_job.expires_date',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'type' => 'Select Date',
+            'formatType' => 'activityDateTime',
+          ],
+          'add' => '5.50',
+        ],
+        'status_id' => [
+          'name' => 'status_id',
+          'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('User Job Status ID'),
+          'required' => TRUE,
+          'where' => 'civicrm_user_job.status_id',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'label' => ts("Job Status"),
+          ],
+          'pseudoconstant' => [
+            'callback' => 'CRM_Core_BAO_UserJob::getStatuses',
+          ],
+          'add' => '5.50',
+        ],
+        'type_id' => [
+          'name' => 'type_id',
+          'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('User Job Type ID'),
+          'required' => TRUE,
+          'where' => 'civicrm_user_job.type_id',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'html' => [
+            'label' => ts("Job Type"),
+          ],
+          'pseudoconstant' => [
+            'callback' => 'CRM_Core_BAO_UserJob::getTypes',
+          ],
+          'add' => '5.50',
+        ],
+        'queue_id' => [
+          'name' => 'queue_id',
+          'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('Queue ID'),
+          'description' => ts('FK to Queue'),
+          'where' => 'civicrm_user_job.queue_id',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'FKClassName' => 'CRM_Queue_DAO_Queue',
+          'html' => [
+            'label' => ts("Queue"),
+          ],
+          'add' => NULL,
+        ],
+        'metadata' => [
+          'name' => 'metadata',
+          'type' => CRM_Utils_Type::T_TEXT,
+          'title' => ts('Job metadata'),
+          'description' => ts('Data pertaining to job configuration'),
+          'where' => 'civicrm_user_job.metadata',
+          'table_name' => 'civicrm_user_job',
+          'entity' => 'UserJob',
+          'bao' => 'CRM_Core_BAO_UserJob',
+          'localizable' => 0,
+          'serialize' => self::SERIALIZE_JSON,
+          'add' => '5.50',
+        ],
+      ];
+      CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']);
+    }
+    return Civi::$statics[__CLASS__]['fields'];
+  }
+
+  /**
+   * Return a mapping from field-name to the corresponding key (as used in fields()).
+   *
+   * @return array
+   *   Array(string $name => string $uniqueName).
+   */
+  public static function &fieldKeys() {
+    if (!isset(Civi::$statics[__CLASS__]['fieldKeys'])) {
+      Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(CRM_Utils_Array::collect('name', self::fields()));
+    }
+    return Civi::$statics[__CLASS__]['fieldKeys'];
+  }
+
+  /**
+   * Returns the names of this table
+   *
+   * @return string
+   */
+  public static function getTableName() {
+    return self::$_tableName;
+  }
+
+  /**
+   * Returns if this table needs to be logged
+   *
+   * @return bool
+   */
+  public function getLog() {
+    return self::$_log;
+  }
+
+  /**
+   * Returns the list of fields that can be imported
+   *
+   * @param bool $prefix
+   *
+   * @return array
+   */
+  public static function &import($prefix = FALSE) {
+    $r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'user_job', $prefix, []);
+    return $r;
+  }
+
+  /**
+   * Returns the list of fields that can be exported
+   *
+   * @param bool $prefix
+   *
+   * @return array
+   */
+  public static function &export($prefix = FALSE) {
+    $r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'user_job', $prefix, []);
+    return $r;
+  }
+
+  /**
+   * Returns the list of indices
+   *
+   * @param bool $localize
+   *
+   * @return array
+   */
+  public static function indices($localize = TRUE) {
+    $indices = [
+      'UI_name' => [
+        'name' => 'UI_name',
+        'field' => [
+          0 => 'name',
+        ],
+        'localizable' => FALSE,
+        'unique' => TRUE,
+        'sig' => 'civicrm_user_job::1::name',
+      ],
+    ];
+    return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
+  }
+
+}
index 7ac8b810bfeac8e75160d95a50aae730df47ce64..084937081f37a75786ef2525e7e9bb376946620e 100644 (file)
@@ -234,7 +234,7 @@ abstract class CRM_Custom_Import_Parser extends CRM_Import_Parser {
           ts('Reason'),
         ], $customHeaders);
         $this->_errorFileName = self::errorFileName(self::ERROR);
-        CRM_Contact_Import_Parser::exportCSV($this->_errorFileName, $headers, $this->_errors);
+        CRM_Contact_Import_Parser_Contact::exportCSV($this->_errorFileName, $headers, $this->_errors);
       }
       if ($this->_conflictCount) {
         $headers = array_merge([
@@ -242,7 +242,7 @@ abstract class CRM_Custom_Import_Parser extends CRM_Import_Parser {
           ts('Reason'),
         ], $customHeaders);
         $this->_conflictFileName = self::errorFileName(self::CONFLICT);
-        CRM_Contact_Import_Parser::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
+        CRM_Contact_Import_Parser_Contact::exportCSV($this->_conflictFileName, $headers, $this->_conflicts);
       }
       if ($this->_duplicateCount) {
         $headers = array_merge([
@@ -251,7 +251,7 @@ abstract class CRM_Custom_Import_Parser extends CRM_Import_Parser {
         ], $customHeaders);
 
         $this->_duplicateFileName = self::errorFileName(self::DUPLICATE);
-        CRM_Contact_Import_Parser::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
+        CRM_Contact_Import_Parser_Contact::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates);
       }
     }
     return $this->fini();
index 28320ca624cd7008bbc0769e17c0c859c8ddcbfc..9cd2baa4020e409cc374b2e458625ca5d41d8ce9 100644 (file)
@@ -186,7 +186,7 @@ class CRM_Custom_Import_Parser_Api extends CRM_Custom_Import_Parser {
   }
 
   /**
-   * Adapted from CRM_Contact_Import_Parser::formatCommonData
+   * Adapted from CRM_Contact_Import_Parser_Contact::formatCommonData
    *
    * TODO: Is this function even necessary? All values get passed to the api anyway.
    *
index ce672ee1ad57b7ddcc81a19481bc6e979342e934..1ea6e7360d97eec83cd5f1132ac515af74ef5545 100644 (file)
@@ -59,9 +59,7 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
 
     $this->_params[0]['is_pay_later'] = $this->get('is_pay_later');
     $this->assign('is_pay_later', $this->_params[0]['is_pay_later']);
-    if ($this->_params[0]['is_pay_later']) {
-      $this->assign('pay_later_receipt', $this->_values['event']['pay_later_receipt']);
-    }
+    $this->assign('pay_later_receipt', $this->_params[0]['is_pay_later'] ? $this->_values['event']['pay_later_receipt'] : NULL);
 
     CRM_Utils_Hook::eventDiscount($this, $this->_params);
 
index 8df997d5832368a559a61c782f14e93957f92540..a8af679e49da0ba2d3c85ffe58144404272a2f3e 100644 (file)
@@ -154,8 +154,22 @@ class CRM_Member_Form_MembershipView extends CRM_Core_Form {
     $this->assign('context', $context);
 
     if ($this->membershipID) {
-      $params = ['id' => $this->membershipID];
-      CRM_Member_BAO_Membership::retrieve($params, $values);
+      $values = \Civi\Api4\Membership::get()
+        ->addSelect('*', 'status_id:label', 'membership_type_id:label', 'membership_type_id.financial_type_id', 'status_id.is_current_member')
+        ->addWhere('id', '=', $this->membershipID)
+        ->execute()
+        ->first();
+
+      // Ensure keys expected by MembershipView.tpl are set correctly
+      // Some of these defaults are overwritten dependant on context below
+      $values['financialTypeId'] = $values['membership_type_id.financial_type_id'];
+      $values['membership_type'] = $values['membership_type_id:label'];
+      $values['status'] = $values['status_id:label'];
+      $values['active'] = $values['status_id.is_current_member'];
+      $values['owner_contact_id'] = FALSE;
+      $values['owner_display_name'] = FALSE;
+      $values['campaign'] = FALSE;
+
       if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
         $finTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'financial_type_id');
         $finType = CRM_Contribute_PseudoConstant::financialType($finTypeId);
index c6fddc7c0ba1fd1851cc14786e80cee878decdc3..ff618291956a135a165413832ccb78253b0b4c8a 100644 (file)
@@ -112,6 +112,7 @@ class CRM_Member_Form_Task_Label extends CRM_Member_Form_Task {
       $memberships = civicrm_api3('membership', 'get', [
         'id' => ['IN' => $this->_memberIds],
         'return' => 'contact_id',
+        'options' => ['limit' => 0],
       ]);
       foreach ($memberships['values'] as $id => $membership) {
         if (isset($rows[$membership['contact_id']])) {
index 70029629901350e43d54100d32bf9d21f0ba5de6..e85f239dc9a509cff77d873474ae8f0c03d0c841 100644 (file)
@@ -1 +1,20 @@
 {* file to handle db changes in 5.50.alpha1 during upgrade *}
+
+CREATE TABLE `civicrm_user_job` (
+`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Job ID',
+`name` varchar(64) COMMENT 'Unique name for job.',
+`created_id` int unsigned COMMENT 'FK to contact table.',
+`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date and time this job was created.',
+`start_date` timestamp NULL COMMENT 'Date and time this import job started.',
+`end_date` timestamp NULL COMMENT 'Date and time this import job ended.',
+`expires_date` timestamp NULL COMMENT 'Date and time to clean up after this import job (temp table deletion date).',
+`status_id` int unsigned NOT NULL,
+`type_id` int unsigned NOT NULL,
+`queue_id` int unsigned COMMENT 'FK to Queue',
+`metadata` text COMMENT 'Data pertaining to job configuration',
+PRIMARY KEY (`id`),
+UNIQUE INDEX `UI_name`(name),
+CONSTRAINT FK_civicrm_user_job_created_id FOREIGN KEY (`created_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE SET NULL,
+CONSTRAINT FK_civicrm_user_job_queue_id FOREIGN KEY (`queue_id`) REFERENCES `civicrm_queue`(`id`) ON DELETE SET NULL
+)
+ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
diff --git a/Civi/Api4/UserJob.php b/Civi/Api4/UserJob.php
new file mode 100644 (file)
index 0000000..8076139
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+namespace Civi\Api4;
+
+/**
+ * UserJob entity.
+ *
+ * This entity allows tracking of imports, including associated temp tables.
+ *
+ * @searchable secondary
+ * @since 5.50
+ * @package Civi\Api4
+ */
+class UserJob extends Generic\DAOEntity {
+
+}
index 92c9a9482d5d4546a8685356f273d84150e5d3e0..2c940faf46139ec0c04b52cf0730a5b7d98eae1b 100644 (file)
@@ -232,7 +232,7 @@ class Container {
     $container->setDefinition('pear_mail', new Definition('Mail'))
       ->setFactory('CRM_Utils_Mail::createMailer')->setPublic(TRUE);
 
-    $container->setDefinition('crypto.registry', new Definition('Civi\Crypto\CryptoService'))
+    $container->setDefinition('crypto.registry', new Definition('Civi\Crypto\CryptoRegistry'))
       ->setFactory('Civi\Crypto\CryptoRegistry::createDefaultRegistry')->setPublic(TRUE);
 
     $container->setDefinition('crypto.token', new Definition('Civi\Crypto\CryptoToken', []))
index 27f0a9de8f418bde414ebddcbc75d4c9b4c102cd..5c6fd958da83b7142c91d2207af531359607fde0 100644 (file)
@@ -61,7 +61,7 @@ class CryptoRegistry {
    * @throws \CRM_Core_Exception
    * @throws \Civi\Crypto\Exception\CryptoException
    */
-  public static function createDefaultRegistry() {
+  public static function createDefaultRegistry(): CryptoRegistry {
     $registry = new static();
     $registry->addCipherSuite(new \Civi\Crypto\PhpseclibCipherSuite());
 
index d76a8fc56fcb587893e6dc5ce4712f6e211a7248..9b82cb4793cc5249f9e61380a6607e53bddeeb83 100644 (file)
@@ -35,7 +35,7 @@
             <td class="crm-acl_entity_role-acl_role">{$row.acl_role}</td>
             <td class="crm-acl_entity_role-entity">{$row.entity}</td>
             <td class="crm-acl_entity_role-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-            <td>{$row.action|replace:'xx':$row.id}</td>
+            <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
           </tr>
         {/foreach}
         </tbody>
index 23989568317e9139269eff41494491d0e0571358..a6ad72efe513f982346c77c54e9f69ffa55d60cc 100644 (file)
 
     <td>
       {if (!empty($row.id))}
-        {$row.action|replace:'xx':$row.id}
+        {$row.action|smarty:nodefaults|replace:'xx':$row.id}
       {else}
         {$row.action}
       {/if}
index 6366cd59c941fad903c6ae58948f7cf5618e58af..8b18015daf33e1b24d661876a66afd5ec91b0d79 100644 (file)
@@ -83,7 +83,7 @@
 
         <td class="crm-activity-date_time">{$row.activity_date_time|crmDate}</td>
         <td class="crm-activity-status crm-activity-status_{$row.status_id}">{$row.status}</td>
-        <td>{$row.action|replace:'xx':$row.id}</td>
+        <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
       </tr>
       {/foreach}
 
index 54685bdf6767bfbc45ed100a1ae716c606335e86..db04f7f1c3492dded87738319ebafb8eae039dec 100644 (file)
     <p>{ts 1=$docLink}ACLs (Access Control Lists) allow you control access to CiviCRM data. An ACL consists of an <strong>Operation</strong> (e.g. 'View' or 'Edit'), a <strong>set of Data</strong> that the operation can be performed on (e.g. a group of contacts), and a <strong>Role</strong> that has permission to do this operation. Refer to the %1 for more info.{/ts}
     {if $config->userSystem->is_drupal EQ '1'}{ts}Note that a CiviCRM ACL Role is not related to the Drupal Role.{/ts}{/if}</p>
     <p>{ts}<strong>EXAMPLE:</strong> 'Team Leaders' (<em>ACL Role</em>) can 'Edit' (<em>Operation</em>) all contacts in the 'Active Volunteers Group' (<em>Data</em>).{/ts}</p>
-    <p>{ts 1=$ufAccessURL 2=$jAccessParams 3=$config->userFramework}Use <a href='%1' %2>%3 Access Control</a> to manage basic access to CiviCRM components and menu items. Use CiviCRM ACLs to control access to specific CiviCRM contact groups. You can also configure ACLs to grant or deny access to specific Events, Profiles, and/or Custom Data Fields.{/ts}</p>
+    <p>{ts 1=$ufAccessURL|smarty:nodefaults 2=$jAccessParams 3=$config->userFramework}Use <a href='%1' %2>%3 Access Control</a> to manage basic access to CiviCRM components and menu items. Use CiviCRM ACLs to control access to specific CiviCRM contact groups. You can also configure ACLs to grant or deny access to specific Events, Profiles, and/or Custom Data Fields.{/ts}</p>
    <p>{ts 1=$config->userFramework}Note that %1 Access Control permissions take precedence over CiviCRM ACLs. If you wish to use CiviCRM ACLs, first disable the related permission in %1 Access control for a user role, and then gradually add ACLs to replace that permission for certain groups of contacts.{/ts}
 </div>
 
     <table class="report">
         <tr>
-            <td class="nowrap"><a href="{$ufAccessURL}" {$jAccessParams} id="adminAccess"><i class="crm-i fa-chevron-right fa-fw" aria-hidden="true"></i> {ts 1=$config->userFramework}%1 Access Control{/ts}</a></td>
+            <td class="nowrap"><a href="{$ufAccessURL|smarty:nodefaults}" {$jAccessParams} id="adminAccess"><i class="crm-i fa-chevron-right fa-fw" aria-hidden="true"></i> {ts 1=$config->userFramework}%1 Access Control{/ts}</a></td>
             <td>{ts}Grant access to CiviCRM components and other CiviCRM permissions.{/ts}</td>
         </tr>
         <tr><td colspan="2" class="separator"><strong>{ts}Use following steps if you need to control View and/or Edit permissions for specific contact groups, specific profiles or specific custom data fields.{/ts}</strong></td></tr>
index ce86bc09ea51bc0cba99932e741574725d61d433..8428faa6f52979044e833a41096d5c9287589609 100644 (file)
@@ -36,7 +36,7 @@
         <td class="crm-contactType-label crm-editable" data-field="label">{ts}{$row.label}{/ts}</td>
         <td class="crm-contactType-parent">{if $row.parent}{ts}{$row.parent_label}{/ts}{else}{ts}(built-in){/ts}{/if}</td>
         <td class="crm-contactType-description crm-editable" data-field="description" data-type="textarea">{$row.description}</td>
-        <td>{$row.action|replace:'xx':$row.id}</td>
+        <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
     </tr>
     {/foreach}
     </table>
index b7a091b84706773bcbfc13dadb00be9a37e57095..7b19f4c72a542632a0aa3830caf7b3d8c173d42c 100644 (file)
@@ -46,7 +46,7 @@
               <td class="crm-event-is_monetary">{if $row.is_monetary eq 1}{ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
               <td class="crm-event-is_online_registration">{if $row.is_online_registration eq 1}{ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
               <td class="crm-event-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-              <td class="crm-event-action">{$row.action|replace:'xx':$row.id}</td>
+              <td class="crm-event-action">{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
           </tr>
         {/foreach}
       </table>
index e70a8a7e01d4428aed1f0d4aa95c94b8b6989e6d..396b72226df40013d1fecccd60bb4bbf1dc7970f 100644 (file)
@@ -26,7 +26,7 @@ Depends: CRM/common/enableDisableApi.tpl and CRM/common/jsortable.tpl
           </td>
           <td class="crm-extensions-version">{$row.version|escape}</td>
           <td class="crm-extensions-description">{$row.type|capitalize}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         <tr class="hiddenElement" id="crm-extensions-details-addnew-{$row.file}">
             <td>
index 0d98485964b621a6699ba64449cc0adadaf8b975..60d9f726097886b64b23dc4eda7a379806e07238 100644 (file)
@@ -35,7 +35,7 @@ Depends: CRM/common/enableDisableApi.tpl and CRM/common/jsortable.tpl
             {/if}
           </td>
           <td class="crm-extensions-description">{$row.type|escape|capitalize}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         <tr class="hiddenElement" id="crm-extensions-details-{$row.file|escape}">
             <td>
index c4ca2ad77ecde8cbce418c0af7c7fd86bece6d16..2ba136f5d7c7adc427924283e4761d9b03d3df01 100644 (file)
@@ -49,7 +49,7 @@
             <td class="crm-job-name">{if $row.parameters eq null}<em>{ts}no parameters{/ts}</em>{else}<pre>{$row.parameters}</pre>{/if}</td>
             <td class="crm-job-name">{if $row.last_run eq null}never{else}{$row.last_run|crmDate:$config->dateformatDatetime}{/if}</td>
             <td id="row_{$row.id}_status" class="crm-job-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index 5fc325d67333b6085842b71039f2b4dff976ba95..4fceb44fa811f9bd93ea5e40b0205fae442d62fc 100644 (file)
@@ -56,7 +56,7 @@
               <td class="crm-labelFormat-is_default">{icon condition=$row.is_default}{ts}Default{/ts}{/icon}&nbsp;</td>
               <td class="crm-labelFormat-is_reserved">{if $row.is_reserved eq 1}{ts}Yes{/ts}{else}{ts}No{/ts}{/if}
                 &nbsp;</td>
-              <td>{$row.action|replace:'xx':$row.id}</td>
+              <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
             </tr>
           {/foreach}
         </table>
index 3ce80083fb610fbd36cc30273189bd03ff395ad1..15fdd2fd5c6d87f35d657c9f7b8e5a0e91426036 100644 (file)
@@ -41,7 +41,7 @@
         <td class="crmf-description crm-editable">{$row.description}</td>
         <td id="row_{$row.id}_status" class="crmf-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
         <td class="crmf-is_default">{if $row.is_default}{icon condition=$row.is_default}{ts}Default{/ts}{/icon}&nbsp;{/if}</td>
-        <td>{$row.action|replace:'xx':$row.id}</td>
+        <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
     </tr>
     {/foreach}
     </table>
index fa655f76362de0da4086b05fdeff7abbad34f8da..8982d3d41db7516c37e29bc3bb05fafc8b337a92 100644 (file)
@@ -44,7 +44,7 @@
               <!--<td>{$row.port}</td>-->
               <td class="crm-mailSettings-is_ssl">{if $row.is_ssl eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
               <td class="crm-mailSettings-is_default">{if $row.is_default eq 1}{ts}Bounce Processing <strong>(Default)</strong>{/ts}{else}{ts}Email-to-Activity{/ts}{/if}&nbsp;</td>
-              <td>{$row.action|replace:'xx':$row.id}</td>
+              <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
           </tr>
         {/foreach}
       </table>
index d7b3ba0538c01c04a3fd7470fd191b95c4e4d007..bec5a96360e7a95ed92b88322c777833759d7d23 100644 (file)
@@ -31,7 +31,7 @@
                 <td class="crm-mapping-name">{$row.name}</td>
                 <td class="crm-mapping-description">{$row.description}</td>
                 <td class="crm-mapping-mapping_type">{$row.mapping_type}</td>
-                <td>{$row.action|replace:'xx':$row.id}</td>
+                <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
             </tr>
             {/foreach}
             </table>
index 96d38de5b1ce822ce9daba3d1009c16db2ebf4bc..aabb8a72c21201c90e568640277093ce8a51480c 100644 (file)
                         <td>{$row.msg_subject}</td>
                         <td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
                       {/if}
-                      <td>{$row.action|replace:'xx':$row.id}</td>
+                      <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
                     </tr>
                 {/foreach}
                 </tbody>
index ab1ee9f23d3f3a01d20107c6e9810342099737c7..dc3c371f91dc5044eea8e1afbde2d056303cc8ea 100644 (file)
             {/if}
             <td class="crm-admin-options-is_reserved">{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
             <td class="crm-admin-options-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-            <td>{$row.action|replace:'xx':$row.id}</td>
+            <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
           </tr>
         {/foreach}
         </tbody>
index b5b8aec35ae94bef1a792c0e13676f24468cfe92..8018311c4ad9a1d5e2cd9ec9fbd6027af514eb20 100644 (file)
@@ -38,7 +38,7 @@
           <td class="center crmf-is_counted">{icon condition=$row.is_counted}{ts}Counted{/ts}{/icon}</td>
           <td class="crmf-weight">{$row.weight|smarty:nodefaults}</td>
           <td class="crmf-visibility">{$row.visibility}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
       {/foreach}
     </table>
index 4e12846cfd8405643e8210ab14e893e4ae48d6f6..92dffc63a2a724f150886fb3b0f51454acaeea60 100644 (file)
@@ -44,7 +44,7 @@
             <td class="crmf-is_active center">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
             <td class="crmf-is_default center">{icon condition=$row.is_default}{ts}Default{/ts}{/icon}&nbsp;
             </td>
-            <td>{$row.action|replace:'xx':$row.id}</td>
+            <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index 6b6ac5a7de4d871e082cdd1a8c94895ba8eb3431..2cb18a1fa7528f7af23024e9cc9e30bbf5e73c5c 100644 (file)
@@ -52,7 +52,7 @@
             <td class="crm-pdfFormat-description">{$row.description}</td>
             <td class="crm-pdfFormat-is_default">{icon condition=$row.is_default}{ts}Default{/ts}{/icon}&nbsp;</td>
           <td class="crm-pdfFormat-order nowrap">{$row.weight|smarty:nodefaults}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index aa39aefd0a2f293b2fbb3bf879d689eb5dc0e83e..81a2423bdecdadce3f7ba12c86666de15426cad2 100644 (file)
@@ -31,7 +31,7 @@
                 <td class="nowrap">{if !$row.date_format}{ts}Default{/ts}{else}{$row.date_format}{/if}</td>
                 <td align="right">{$row.start}</td>
                 <td align="right">{$row.end}</td>
-                <td><span>{$row.action|replace:'xx':$row.id}</span></td>
+                <td><span>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</span></td>
             </tr>
             {/foreach}
         </table>
index f1f5c79bd53853e4a16a5f083168443648096420..0729752e9dfba6fbd2e199154ffbb6339367cb5f 100644 (file)
@@ -54,7 +54,7 @@
                 {if $row.contact_type_b_display} {$row.contact_type_b_display}
                 {if !empty($row.contact_sub_type_b)} - {$row.contact_sub_type_b}{/if} {else} {ts}All Contacts{/ts} {/if} </td>
             <td class="crm-relationship-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-            <td>{$row.action|replace:'xx':$row.id}</td>
+            <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index 3a08352e62acf213c3753709cf2eb5dc25358991..f4e225f4ef2bcca9c95ac2dbe873567d682a9da3 100644 (file)
@@ -35,7 +35,7 @@
           <td class="crm-scheduleReminders-title">{$row.status}</td>
           <td class="crm-scheduleReminders-is_repeat">{if $row.is_repeat eq 1}{ts}Yes{/ts}{else}{ts}No{/ts}{/if}&nbsp;</td>
           <td id="row_{$row.id}_status" class="crm-scheduleReminders-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
           <td class="hiddenElement"></td>
         </tr>
       {/foreach}
index c444e5cac7bd58517b0d3c1ff98686d52365f136..8a5f4c902d201532ad85411ca976b6ba4da17dda 100644 (file)
@@ -40,7 +40,7 @@
               </td>
               <td class="crm-badge-layout-is_default">{icon condition=$row.is_default}{ts}Default{/ts}{/icon}&nbsp;
               </td>
-              <td>{$row.action|replace:'xx':$row.id}</td>
+              <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
             </tr>
           {/foreach}
         </table>
index c467c9301ce6a3c4d3aa6ddcd2f05312fc5cc635..9fed46dd173e93f2cdf7f821ece86635a1e5d4d7 100644 (file)
@@ -35,7 +35,7 @@
           <td class="nowrap crm-admin-options-order">{$row.weight|smarty:nodefaults}</td>
           <td class="crm-admin-options-is_reserved">{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td class="crm-admin-options-is_active" id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index ac1a4e2b4413db0f36692226250e3498b3551555..9d54b54171fa4f8635d0ae3759e5fc0d23a3591a 100644 (file)
@@ -44,7 +44,7 @@
           call_user_func(array('CRM_Core_Permission','check'), 'add cases') ) AND
         $allowToAddNewCase}
         <div class="action-link">
-        <a accesskey="N" href="{$newCaseURL}" class="button no-popup"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Case{/ts}</span></a>
+        <a accesskey="N" href="{$newCaseURL|smarty:nodefaults}" class="button no-popup"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Case{/ts}</span></a>
         </div>
     {/if}
 
index 60c8cc87a44c3207614a633c68965216ffcd026f..eaef7441735f6f05185de8c713ea148b9ef6509b 100644 (file)
@@ -38,7 +38,7 @@
               <tr class="{cycle values="odd-row,even-row"}">
                 <td>{$row.title}</td>
                 <td>{$row.used_display}</td>
-                <td>{$row.action|replace:'xx':$row.id}</td>
+                <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
               </tr>
             {/foreach}
           </table>
index 8a824542249e921e21e05f7a744bf8343b974eaf..a73e848ddaed8a7682908aeb8decb2b1d2d9a55d 100644 (file)
@@ -39,7 +39,7 @@
           <td>{if $row.is_deductible eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
          </table>
index f80c43e5dcfb85f8b77c95bd690281240bdc9a59..9760a62a99368fe0e7d28af2b3a59aa4130bff5e 100644 (file)
@@ -51,7 +51,7 @@
           <td class="crm-contribution-form-block-cost">{$row.cost|crmMoney}</td>
           <td class="crm-contribution-form-block-financial_type">{$row.financial_type}</td>
           <td id="row_{$row.id}_status" >{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td id={$row.id}>{$row.action|replace:'xx':$row.id}</td>
+          <td id={$row.id}>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index e6b2ce8d71b1b3a0ea94e134ecf369105f0eca11..b02d5d4958c0a862cee02487b995463860d9102b 100644 (file)
           <div class="help">
             {if $permission EQ 'edit'}
               {capture assign=newContribURL}{crmURL p="civicrm/contact/view/contribution" q="reset=1&action=add&cid=`$contactId`&context=contribution"}{/capture}
-              {capture assign=link}class="action-item" href="{$newContribURL}"{/capture}
-              {ts 1=$link}Click <a %1>Record Contribution</a> to record a new contribution received from this contact.{/ts}
+              {capture assign=link}class="action-item" href="{$newContribURL|smarty:nodefaults}"{/capture}
+              {ts 1=$link|smarty:nodefaults}Click <a %1>Record Contribution</a> to record a new contribution received from this contact.{/ts}
               {if $newCredit}
                 {capture assign=newCreditURL}{crmURL p="civicrm/contact/view/contribution" q="reset=1&action=add&cid=`$contactId`&context=contribution&mode=live"}{/capture}
-                {capture assign=link}class="action-item" href="{$newCreditURL}"{/capture}
-                {ts 1=$link}Click <a %1>Submit Credit Card Contribution</a> to process a new contribution on behalf of the contributor using their credit card.{/ts}
+                {capture assign=link}class="action-item" href="{$newCreditURL|smarty:nodefaults}"{/capture}
+                {ts 1=$link|smarty:nodefaults}Click <a %1>Submit Credit Card Contribution</a> to process a new contribution on behalf of the contributor using their credit card.{/ts}
               {/if}
             {else}
               {ts 1=$displayName}Contributions received from %1 since inception.{/ts}
@@ -48,9 +48,9 @@
 
           {if $action eq 16 and $permission EQ 'edit'}
             <div class="action-link">
-              <a accesskey="N" href="{$newContribURL}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Record Contribution (Check, Cash, EFT ...){/ts}</span></a>
+              <a accesskey="N" href="{$newContribURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Record Contribution (Check, Cash, EFT ...){/ts}</span></a>
               {if $newCredit}
-                <a accesskey="N" href="{$newCreditURL}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Contribution{/ts}</span></a>
+                <a accesskey="N" href="{$newCreditURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Contribution{/ts}</span></a>
               {/if}
               <br /><br />
             </div>
index 56f95044a633532ee2713850e8fd3ecc5201b072..2f059efdaaa1ac98d57f32bc83a04b4715a7b7d3 100644 (file)
 
     <div class="help">
         <p>{ts 1=$displayName}This page lists all event registrations for %1 since inception.{/ts}
-        {capture assign="link"}class="action-item" href="{$newEventURL}"{/capture}
-        {if $permission EQ 'edit'}{ts 1=$link}Click <a %1>Add Event Registration</a> to register this contact for an event.{/ts}{/if}
+        {capture assign="link"}class="action-item" href="{$newEventURL|smarty:nodefaults}"{/capture}
+        {if $permission EQ 'edit'}{ts 1=$link|smarty:nodefaults}Click <a %1>Add Event Registration</a> to register this contact for an event.{/ts}{/if}
         {if $accessContribution and $newCredit}
             {capture assign=newCreditURL}{crmURL p="civicrm/contact/view/participant" q="reset=1&action=add&cid=`$contactId`&context=participant&mode=live"}{/capture}
-            {capture assign="link"}class="action-item" href="{$newCreditURL}"{/capture}
-            {ts 1=$link}Click <a %1>Submit Credit Card Event Registration</a> to process a new New Registration on behalf of the participant using their credit card.{/ts}
+            {capture assign="link"}class="action-item" href="{$newCreditURL|smarty:nodefaults}"{/capture}
+            {ts 1=$link|smarty:nodefaults}Click <a %1>Submit Credit Card Event Registration</a> to process a new New Registration on behalf of the participant using their credit card.{/ts}
         {/if}
         </p>
     </div>
     {if $action eq 16 and $permission EQ 'edit'}
        <div class="action-link">
-           <a accesskey="N" href="{$newEventURL}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Event Registration{/ts}</span></a>
+           <a accesskey="N" href="{$newEventURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-plus-circle" aria-hidden="true"></i> {ts}Add Event Registration{/ts}</span></a>
             {if $accessContribution and $newCredit}
-                <a accesskey="N" href="{$newCreditURL}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Event Registration{/ts}</a></span>
+                <a accesskey="N" href="{$newCreditURL|smarty:nodefaults}" class="button"><span><i class="crm-i fa-credit-card" aria-hidden="true"></i> {ts}Submit Credit Card Event Registration{/ts}</a></span>
             {/if}
-            <br/ ><br/ >
+            <br/><br/>
        </div>
    {/if}
 
index 65ebc0dc7fadd39b48ac778f5f6297ddf9f5c618..43252aa2082c2cba3761a6245c98aee7e5ecb520 100644 (file)
@@ -54,7 +54,7 @@
           <td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td>{icon condition=$row.is_default}{ts}Default{/ts}{/icon}</td>
           <td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
       </table>
index c4f55f03ea519e547a5438030ced2b10441ed17c..6ee791b70b8476cfe03c3e0a3b50ed358ea8993f 100644 (file)
@@ -44,7 +44,7 @@
           <td class="crm-editable" data-field="is_deductible" data-type="boolean">{if $row.is_deductible eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td>{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
          </table>
index c3af8775a1fa6886e956a13eba77cf1a1c68e344..7700c2d237c00fe79ca605bc8db9948c06d0e785 100644 (file)
@@ -40,7 +40,7 @@
           <td>{$row.financial_account_type}{if $row.account_type_code} ({$row.account_type_code}){/if}</td>
           <td>{$row.owned_by}</td>
           <td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
       </table>
index 52ca891e9d35ec3a5315dbf13b418d7257c85020..912a9f88f449b37c3ade4db8b81e517ec874f10d 100644 (file)
@@ -12,7 +12,7 @@
   <div class="help">
     {if $action eq 2}
       {capture assign=crmURL}class="no-popup" href="{crmURL p="civicrm/group/search" q="reset=1&force=1&context=smog&gid=`$group.id`"}"{/capture}
-      {ts 1=$crmURL}You can edit the Name and Description for this group here. Click <a %1>Contacts in this Group</a> to view, add or remove contacts in this group.{/ts}
+      {ts 1=$crmURL|smarty:nodefaults}You can edit the Name and Description for this group here. Click <a %1>Contacts in this Group</a> to view, add or remove contacts in this group.{/ts}
     {else}
       {ts}Enter a unique name and a description for your new group here. Then click 'Continue' to find contacts to add to your new group.{/ts}
     {/if}
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
   {if $action neq 1}
     <div class="action-link">
-      <a {$crmURL}><i class="crm-i fa-users" aria-hidden="true"></i> {ts}Contacts in this Group{/ts}</a>
+      <a {$crmURL|smarty:nodefaults}><i class="crm-i fa-users" aria-hidden="true"></i> {ts}Contacts in this Group{/ts}</a>
       {if $editSmartGroupURL}
         <br />
-        <a class="no-popup" href="{$editSmartGroupURL}"><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Smart Group Criteria{/ts}</a>
+        <a class="no-popup" href="{$editSmartGroupURL|smarty:nodefaults}"><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Smart Group Criteria{/ts}</a>
       {/if}
     </div>
   {/if}
index bf5323c9df4d1fd2de3f7301a0e274b13f7764e1..050fbf33778230136c68f7834ee9f449be80eaec 100644 (file)
@@ -16,6 +16,6 @@
     {$row.description|mb_truncate:80:"...":true}
     </td>
     <td>{$row.visibility}</td>
-    <td>{$row.action|replace:'xx':$row.id}</td>
+    <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
     </tr>
 {/foreach}
index ad5a0b8d41bedb41f0cad10790250cddf2713fc0..c0fdd64d5a360d55eba9555e07d64e077c325ec8 100644 (file)
@@ -70,7 +70,7 @@
        {if call_user_func(array('CRM_Campaign_BAO_Campaign','isCampaignEnable'))}
           <td class="crm-mailing-campaign">{$row.campaign}</td>
       {/if}
-        <td>{$row.action|replace:'xx':$row.id}</td>
+        <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
       </tr>
       {/foreach}
     </table>
index ccc1db657fd3b82f5f853da5352de3604d21b94f..0cae9fb8646da8b421784b69e5526e172b1680c2 100644 (file)
@@ -37,7 +37,7 @@
            <td>{$row.body_text|escape}</td>
            <td>{icon condition=$row.is_default}{ts}Default{/ts}{/icon}&nbsp;</td>
      <td id="row_{$row.id}_status">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-           <td>{$row.action|replace:'xx':$row.id}</td>
+           <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
        {/foreach}
        </table>
index 99decbbd24060008ba18a964ae20ef02b75455eb..fbfe13c56ff8a102f19f97198d0f6dcfc5ed13ca 100644 (file)
@@ -48,7 +48,7 @@
           <td class="crmf-is_admin crm-editable" data-type="boolean">{if $row.is_admin eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
           <td class="nowrap crmf-weight">{$row.weight|smarty:nodefaults}</td>
           <td class="crmf-is_reserved">{if $row.is_reserved eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{if !empty($row.action)}{$row.action|replace:'xx':$row.id}{/if}</td>
+          <td>{if !empty($row.action)}{$row.action|smarty:nodefaults|replace:'xx':$row.id}{/if}</td>
         </tr>
         {/foreach}
         </table>
index 09cd8792eb9925700d622d0d3ae40c17c30cfc4b..d9f0a0914ae09c7f49998d1386f5a551a2fd1c5c 100644 (file)
@@ -49,7 +49,7 @@
           <td class="crmf-visibility crm-editable" data-type="select">{$row.visibility}</td>
           <td class="nowrap crmf-weight">{$row.weight|smarty:nodefaults}</td>
           <td class="crmf-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
       {/foreach}
     </table>
index 9aca301ba37c5feff9fec06b9e45e92eb6fa9d23..343d6adef563fa4d103c34f09c7496e70113f873 100644 (file)
@@ -44,7 +44,7 @@
     <td>{$row.start_date|crmDate}</td>
     <td>{if $row.end_date}{$row.end_date|crmDate}{else}({ts}ongoing{/ts}){/if}</td>
     <td>{$row.status_id}</td>
-    <td id={$row.id}>{$row.action|replace:'xx':$row.id}</td>
+    <td id={$row.id}>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
   </tr>
   {/foreach}
   </tbody>
index 012c40138ac27f96bd0681850227b7703442b1d6..ff98309a5c1f57c43f78afd288cbc363e26ad1a9 100644 (file)
@@ -74,7 +74,7 @@
       </td>
             <td>{if $row.html_type eq "Text / Numeric Quantity" }{$row.tax_amount|crmMoney}{/if}</td>
         {/if}
-        <td class="field-action">{$row.action|replace:'xx':$row.id}</td>
+        <td class="field-action">{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
       </tr>
       {/foreach}
     </table>
index 99dcb4225854a136909d4b6a790f843c0786fd3f..dd04c1dda38e1de60e7d57fd2743a8d44328ff1b 100644 (file)
@@ -79,7 +79,7 @@
                 <td>{$row.tax_amount|crmMoney}</td>
               {/if}
               <td id="row_{$row.id}_status" class="crm-price-option-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-              <td>{$row.action|replace:'xx':$row.id}</td>
+              <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
             </tr>
           {/foreach}
           </tbody>
index 4b90dce429eec7138c1a1a687ed4820438c46c2a..bdd496f32b8d095efd1766732a4bf9d2ebe74b19 100644 (file)
@@ -52,7 +52,7 @@
           <td class="crmf-title crm-editable">{$row.title}</td>
           <td class="crmf-extends">{$row.extends}</td>
           <td class="crmf-is_active">{if $row.is_active eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index 3ebf7393f7686140766e764494e0070281cbc6b4..ccbf33995b865b6d89e94ebf55f28b4762c2c8ad 100644 (file)
@@ -38,7 +38,7 @@
         </td>
             <td class="crm-api-params">{if $row.api_params eq null}<em>{ts}no parameters{/ts}</em>{else}<pre>{$row.api_params}</pre>{/if}</td>
 
-          <td>{$row.action|replace:'xx':$row.id}</td>
+          <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
         </tr>
         {/foreach}
         </table>
index 78b812e5c8fcbb08ae240b349945357301a14039..f266f1fab1d634af2f1ab8b3e4e62804159ef67c 100644 (file)
@@ -53,7 +53,7 @@
                 <td class="crm-editable crmf-is_required" data-type="boolean">{if $row.is_required eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
                 <td class="crm-editable crmf-is_view" data-type="boolean">{if $row.is_view eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
                 <td>{if $row.is_reserved     eq 1} {ts}Yes{/ts} {else} {ts}No{/ts} {/if}</td>
-                <td>{$row.action|replace:'xx':$row.id}</td>
+                <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
             </tr>
             {/foreach}
         </table>
index 45e3c893ee7d7112ee86057ec88e96c168efb799..4bcd4185562e63b4b346ecdf94e667c31de38f5e 100644 (file)
@@ -81,7 +81,7 @@
                     <td>{$row.group_type}</td>
                     <td>{$row.id}</td>
                     <td>{$row.module}</td>
-                    <td>{$row.action|replace:'xx':$row.id}</td>
+                    <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
                   </tr>
                 {/if}
                 {/foreach}
                       <td>{$row.group_type}</td>
                       <td>{$row.id}</td>
                       <td>{$row.module}</td>
-                      <td>{$row.action|replace:'xx':$row.id}</td>
+                      <td>{$row.action|smarty:nodefaults|replace:'xx':$row.id}</td>
                     </tr>
                   {/if}
                 {/foreach}
index e4865b29b3c565b8529945933e4ddc07afa8d2cf..fae48c45960c5047f88e606e6e2732761c8d09c5 100644 (file)
@@ -1410,6 +1410,9 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
       'civicrm_uf_match' => [
         0 => 'contact_id',
       ],
+      'civicrm_user_job' => [
+        0 => 'created_id',
+      ],
       'civicrm_value_testgetcidref_1' => [
         0 => 'entity_id',
       ],
index 645a3f017cbfc954df668a5b47cc9814e8d1a10c..89242d5a334b78c66c259cf1379faea958478102 100644 (file)
@@ -96,7 +96,11 @@ class E2E_Extern_CliRunnerTest extends CiviEndToEndTestCase {
     if (CIVICRM_UF === 'WordPress') {
       $cliRunners['wp'] = ['wp', 'wp eval \'civicrm_initialize();\'@PHP'];
     }
-    if (CIVICRM_UF === 'Drupal' || CIVICRM_UF === 'Backdrop') {
+    if (CIVICRM_UF === 'Drupal') {
+      $cliRunners['drush'] = ['drush', 'drush ev \'civicrm_initialize();\'@PHP'];
+    }
+    if (CIVICRM_UF === 'Backdrop' && version_compare(PHP_VERSION, '8', '<')) {
+      // At time of writing, "drush ev" doesn't work on our php80+backdrop environments
       $cliRunners['drush'] = ['drush', 'drush ev \'civicrm_initialize();\'@PHP'];
     }
     // TODO: Drupal8 w/drush (doesn't use civicrm_initialize?)
diff --git a/xml/schema/Core/UserJob.xml b/xml/schema/Core/UserJob.xml
new file mode 100644 (file)
index 0000000..0c8113e
--- /dev/null
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+
+<table>
+  <base>CRM/Core</base>
+  <class>UserJob</class>
+  <name>civicrm_user_job</name>
+  <comment>Tracking for user jobs (eg. imports).</comment>
+  <add>5.50</add>
+  <log>false</log>
+  <field>
+    <name>id</name>
+    <title>User Job ID</title>
+    <type>int unsigned</type>
+    <required>true</required>
+    <comment>Job ID</comment>
+    <html>
+      <type>Number</type>
+    </html>
+    <add>5.50</add>
+  </field>
+  <primaryKey>
+    <name>id</name>
+    <autoincrement>true</autoincrement>
+  </primaryKey>
+  <field>
+    <name>name</name>
+    <title>User job name</title>
+    <type>varchar</type>
+    <length>64</length>
+    <comment>Unique name for job.</comment>
+    <add>5.50</add>
+  </field>
+  <index>
+    <name>UI_name</name>
+    <fieldName>name</fieldName>
+    <unique>true</unique>
+    <add>5.50</add>
+  </index>
+  <field>
+    <name>created_id</name>
+    <type>int unsigned</type>
+    <title>Created By Contact ID</title>
+    <comment>FK to contact table.</comment>
+    <html>
+      <label>Created By</label>
+    </html>
+    <add>5.50</add>
+  </field>
+  <foreignKey>
+    <name>created_id</name>
+    <table>civicrm_contact</table>
+    <key>id</key>
+    <add>5.50</add>
+    <onDelete>SET NULL</onDelete>
+  </foreignKey>
+  <field>
+    <name>created_date</name>
+    <type>timestamp</type>
+    <default>CURRENT_TIMESTAMP</default>
+    <required>true</required>
+    <title>Import Job Created Date</title>
+    <readonly>true</readonly>
+    <comment>Date and time this job was created.</comment>
+    <add>5.50</add>
+    <html>
+      <type>Select Date</type>
+      <formatType>activityDateTime</formatType>
+    </html>
+  </field>
+  <field>
+    <name>start_date</name>
+    <type>timestamp</type>
+    <required>false</required>
+    <title>Import Job Started Date</title>
+    <comment>Date and time this import job started.</comment>
+    <add>5.50</add>
+    <html>
+      <type>Select Date</type>
+      <formatType>activityDateTime</formatType>
+    </html>
+    <readonly>true</readonly>
+  </field>
+  <field>
+    <name>end_date</name>
+    <type>timestamp</type>
+    <required>false</required>
+    <title>Job Ended Date</title>
+    <comment>Date and time this import job ended.</comment>
+    <add>5.50</add>
+    <html>
+      <type>Select Date</type>
+      <formatType>activityDateTime</formatType>
+    </html>
+  </field>
+  <field>
+    <name>expires_date</name>
+    <type>timestamp</type>
+    <required>false</required>
+    <title>Import Job Expires Date</title>
+    <comment>Date and time to clean up after this import job (temp table deletion date).</comment>
+    <add>5.50</add>
+    <html>
+      <type>Select Date</type>
+      <formatType>activityDateTime</formatType>
+    </html>
+  </field>
+  <field>
+    <name>status_id</name>
+    <title>User Job Status ID</title>
+    <type>int unsigned</type>
+    <required>true</required>
+    <html>
+      <label>Job Status</label>
+    </html>
+    <pseudoconstant>
+      <callback>CRM_Core_BAO_UserJob::getStatuses</callback>
+    </pseudoconstant>
+    <add>5.50</add>
+  </field>
+  <field>
+    <name>type_id</name>
+    <title>User Job Type ID</title>
+    <type>int unsigned</type>
+    <required>true</required>
+    <html>
+      <label>Job Type</label>
+    </html>
+    <pseudoconstant>
+      <callback>CRM_Core_BAO_UserJob::getTypes</callback>
+    </pseudoconstant>
+    <add>5.50</add>
+  </field>
+  <field>
+    <name>queue_id</name>
+    <title>Queue ID</title>
+    <type>int unsigned</type>
+    <comment>FK to Queue</comment>
+    <html>
+      <label>Queue</label>
+    </html>
+  </field>
+  <foreignKey>
+    <name>queue_id</name>
+    <table>civicrm_queue</table>
+    <key>id</key>
+    <onDelete>SET NULL</onDelete>
+  </foreignKey>
+  <field>
+    <name>metadata</name>
+    <type>text</type>
+    <title>Job metadata</title>
+    <comment>Data pertaining to job configuration</comment>
+    <serialize>JSON</serialize>
+    <add>5.50</add>
+  </field>
+</table>
index 05ae0fac888778edd4abe1d166887ddbf8656a13..8c45d2cdb8ff9b93191009d826d0cf5278c11f9c 100644 (file)
@@ -42,6 +42,7 @@
   <xi:include href="UFField.xml"              parse="xml" />
   <xi:include href="UFMatch.xml"              parse="xml" />
   <xi:include href="UFJoin.xml"               parse="xml" />
+  <xi:include href="UserJob.xml"              parse="xml" />
   <xi:include href="Timezone.xml"             parse="xml" />
   <xi:include href="Worldregion.xml"          parse="xml" />
   <xi:include href="OpenID.xml"               parse="xml" />