This is part of switching to testing the eventual output rather than the temp table created. In most cases the temp
table is not truly needed so testing the real output makes more sense
*/
class CRM_Core_Exception_PrematureExitException extends RuntimeException {
+ /**
+ * Construct the exception. Note: The message is NOT binary safe.
+ *
+ * @link https://php.net/manual/en/exception.construct.php
+ *
+ * @param string $message [optional] The Exception message to throw.
+ * @param array $errorData
+ * @param int $error_code
+ * @param throwable $previous [optional] The previous throwable used for the exception chaining.
+ */
+ public function __construct($message = "", $errorData = [], $error_code = 0, throwable $previous = NULL) {
+ parent::__construct($message, $error_code, $previous);
+ $this->errorData = $errorData + ['error_code' => $error_code];
+ }
+
}
$headerRows = $processor->getHeaderRows();
$sqlColumns = $processor->getSQLColumns();
- $exportTempTable = self::createTempTable($sqlColumns);
+ $processor->setTemporaryTable(self::createTempTable($sqlColumns));
$limitReached = FALSE;
while (!$limitReached) {
// output every $tempRowCount rows
if ($count % $tempRowCount == 0) {
- self::writeDetailsToTable($exportTempTable, $componentDetails, $sqlColumns);
+ self::writeDetailsToTable($processor, $componentDetails, $sqlColumns);
$componentDetails = [];
}
}
$offset += $rowCount;
}
- if ($exportTempTable) {
- self::writeDetailsToTable($exportTempTable, $componentDetails, $sqlColumns);
+ if ($processor->getTemporaryTable()) {
+ self::writeDetailsToTable($processor, $componentDetails, $sqlColumns);
// do merge same address and merge same household processing
if ($mergeSameAddress) {
- self::mergeSameAddress($exportTempTable, $sqlColumns, $exportParams);
+ self::mergeSameAddress($processor, $sqlColumns, $exportParams);
}
// call export hook
- CRM_Utils_Hook::export($exportTempTable, $headerRows, $sqlColumns, $exportMode, $componentTable, $ids);
+ $table = $processor->getTemporaryTable();
+ CRM_Utils_Hook::export($table, $headerRows, $sqlColumns, $exportMode, $componentTable, $ids);
+ if ($table !== $processor->getTemporaryTable()) {
+ CRM_Core_Error::deprecatedFunctionWarning('altering the export table in the hook is deprecated (in some flows the table itself will be)');
+ $processor->setTemporaryTable($table);
+ }
// In order to be able to write a unit test against this function we need to suppress
// the csv writing. In future hopefully the csv writing & the main processing will be in separate functions.
if (empty($exportParams['suppress_csv_for_testing'])) {
- self::writeCSVFromTable($exportTempTable, $headerRows, $sqlColumns, $processor);
+ self::writeCSVFromTable($headerRows, $sqlColumns, $processor);
}
else {
// return tableName sqlColumns headerRows in test context
- return [$exportTempTable, $sqlColumns, $headerRows, $processor];
+ return [$processor->getTemporaryTable(), $sqlColumns, $headerRows, $processor];
}
// delete the export temp table and component table
- $sql = "DROP TABLE IF EXISTS {$exportTempTable}";
+ $sql = "DROP TABLE IF EXISTS " . $processor->getTemporaryTable();
CRM_Core_DAO::executeQuery($sql);
CRM_Core_DAO::reenableFullGroupByMode();
- CRM_Utils_System::civiExit();
+ CRM_Utils_System::civiExit(0, ['processor' => $processor]);
}
else {
CRM_Core_DAO::reenableFullGroupByMode();
}
/**
- * @param string $tableName
+ * @param \CRM_Export_BAO_ExportProcessor $processor
* @param $details
* @param $sqlColumns
*/
- public static function writeDetailsToTable($tableName, $details, $sqlColumns) {
+ public static function writeDetailsToTable($processor, $details, $sqlColumns) {
+ $tableName = $processor->getTemporaryTable();
if (empty($details)) {
return;
}
}
/**
- * @param string $tableName
+ * @param \CRM_Export_BAO_ExportProcessor $processor
* @param $sqlColumns
* @param array $exportParams
*/
- public static function mergeSameAddress($tableName, &$sqlColumns, $exportParams) {
+ public static function mergeSameAddress($processor, &$sqlColumns, $exportParams) {
+ $tableName = $processor->getTemporaryTable();
// check if any records are present based on if they have used shared address feature,
// and not based on if city / state .. matches.
$sql = "
}
/**
- * @param $exportTempTable
* @param $headerRows
* @param $sqlColumns
* @param \CRM_Export_BAO_ExportProcessor $processor
*/
- public static function writeCSVFromTable($exportTempTable, $headerRows, $sqlColumns, $processor) {
+ public static function writeCSVFromTable($headerRows, $sqlColumns, $processor) {
+ $exportTempTable = $processor->getTemporaryTable();
$exportMode = $processor->getExportMode();
$writeHeader = TRUE;
$offset = 0;
*/
protected $outputSpecification = [];
+ /**
+ * Name of a temporary table created to hold the results.
+ *
+ * Current decision making on when to create a temp table is kinda bad so this might change
+ * a bit as it is reviewed but basically we need a temp table or similar to calculate merging
+ * addresses. Merging households is handled in php. We create a temp table even when we don't need them.
+ *
+ * @var string
+ */
+ protected $temporaryTable;
+
+ /**
+ * @return string
+ */
+ public function getTemporaryTable(): string {
+ return $this->temporaryTable;
+ }
+
+ /**
+ * @param string $temporaryTable
+ */
+ public function setTemporaryTable(string $temporaryTable) {
+ $this->temporaryTable = $temporaryTable;
+ }
+
/**
* CRM_Export_BAO_ExportProcessor constructor.
*
* @param int $status
* (optional) Code with which to exit.
*
- * @throws \CRM_Core_PrematureExit_Exception
+ * @param array $testParameters
*/
- public static function civiExit($status = 0) {
+ public static function civiExit($status = 0, $testParameters = []) {
if (CIVICRM_UF === 'UnitTests') {
- throw new CRM_Core_Exception_PrematureExitException('civiExit called');
+ throw new CRM_Core_Exception_PrematureExitException('civiExit called', $testParameters);
}
if ($status > 0) {
http_response_code(500);
*/
protected $activityIDs = [];
-
/**
* Contribution IDs created for testing.
*
protected $locationTypes = [];
+ /**
+ * Processor generated in test.
+ *
+ * @var \CRM_Export_BAO_ExportProcessor
+ */
+ protected $processor;
+
+ /**
+ * Cleanup data.
+ *
+ * @throws \Exception
+ */
public function tearDown() {
+ $this->quickCleanUpFinancialEntities();
$this->quickCleanup([
'civicrm_contact',
'civicrm_email',
'civicrm_case_contact',
'civicrm_case_activity',
]);
- $this->quickCleanUpFinancialEntities();
+
if (!empty($this->locationTypes)) {
$this->callAPISuccess('LocationType', 'delete', ['id' => $this->locationTypes['Whare Kai']['id']]);
$this->callAPISuccess('LocationType', 'create', ['id' => $this->locationTypes['Main']['id'], 'name' => 'Main']);
}
+ if ($this->processor && $this->processor->getTemporaryTable()) {
+ // delete the export temp table
+ CRM_Core_DAO::executeQuery("DROP TABLE IF EXISTS " . $this->processor->getTemporaryTable());
+ }
parent::tearDown();
}
* Basic test to ensure the exportComponents function completes without error.
*
* @throws \CRM_Core_Exception
+ * @throws \League\Csv\Exception
*/
public function testExportComponentsNull() {
- list($tableName) = CRM_Export_BAO_Export::exportComponents(
- TRUE,
- [],
- [],
- NULL,
- NULL,
- NULL,
- CRM_Export_Form_Select::CONTACT_EXPORT,
- NULL,
- NULL,
- FALSE,
- FALSE,
- [
- 'exportOption' => 1,
- 'suppress_csv_for_testing' => TRUE,
- ]
- );
-
- // delete the export temp table and component table
- $sql = "DROP TABLE IF EXISTS {$tableName}";
- CRM_Core_DAO::executeQuery($sql);
+ $this->startCapturingOutput();
+ try {
+ list($tableName) = CRM_Export_BAO_Export::exportComponents(
+ TRUE,
+ [],
+ [],
+ NULL,
+ NULL,
+ NULL,
+ CRM_Export_Form_Select::CONTACT_EXPORT,
+ NULL,
+ NULL,
+ FALSE,
+ FALSE,
+ [
+ 'exportOption' => 1,
+ ]
+ );
+ }
+ catch (CRM_Core_Exception_PrematureExitException $e) {
+ }
+ $this->processor = $e->errorData['processor'];
+ ob_end_clean();
}
/**
*/
use Civi\Payment\System;
+use League\Csv\Reader;
/**
* Include class definitions
return civicrm_api3('option_value', 'create', $params);
}
+ /**
+ * Start capturing browser output.
+ *
+ * The starts the process of browser output being captured, setting any variables needed for e-notice prevention.
+ */
+ protected function startCapturingOutput() {
+ ob_start();
+ $_SERVER['HTTP_USER_AGENT'] = 'unittest';
+ }
+
+ /**
+ * Stop capturing browser output and return as a csv.
+ *
+ * @param bool $isFirstRowHeaders
+ *
+ * @return \League\Csv\Reader
+ *
+ * @throws \League\Csv\Exception
+ */
+ protected function captureOutputToCSV($isFirstRowHeaders = TRUE) {
+ $output = ob_get_flush();
+ $stream = fopen('php://memory', 'r+');
+ fwrite($stream, $output);
+ rewind($stream);
+ $csv = Reader::createFromString($output);
+ if ($isFirstRowHeaders) {
+ $csv->setHeaderOffset(0);
+ }
+ ob_clean();
+ return $csv;
+ }
+
}