public function dispatchLoopShutdown() { // // Force output to be sent - we need the client to have the page before // we start flushing progress bar updates // $app = AppController::getInstance(); $req = $app->getRequest(); $resp = $app->getResponse(); $resp->sendResponse(); $resp->clearContent(); // // Do export // if ($req->isLoggedIn()) { set_time_limit(3600 * 24); // if it takes more than 24 hours we're in trouble $vn_id = $req->getParameter('exporter_id', pInteger); $vs_search = $req->getParameter('search', pString); $t_exporter = new ca_data_exporters($vn_id); $vs_file = tempnam(caGetTempDirPath(), 'export'); if ($vn_set_id = $req->getParameter('set_id', pInteger)) { ca_data_exporters::exportRecordsFromSet($t_exporter->get('exporter_code'), $vn_set_id, $vs_file, array('request' => $req, 'progressCallback' => 'caIncrementBatchMetadataExportProgress')); } else { ca_data_exporters::exportRecordsFromSearchExpression($t_exporter->get('exporter_code'), $vs_search, $vs_file, array('request' => $req, 'progressCallback' => 'caIncrementBatchMetadataExportProgress')); } } // export done, move file to application tmp dir and create download link (separate action in the export controller) if (filesize($vs_file)) { $vs_new_filename = $vn_id . "_" . md5($vs_file); rename($vs_file, __CA_APP_DIR__ . '/tmp/' . $vs_new_filename); caExportAddDownloadLink($req, $vs_new_filename); } }
public function dispatchLoopShutdown() { // // Force output to be sent - we need the client to have the page before // we start flushing progress bar updates // $app = AppController::getInstance(); $req = $app->getRequest(); $resp = $app->getResponse(); $resp->sendResponse(); $resp->clearContent(); // // Do export // if (!$req->isLoggedIn()) { return; } set_time_limit(3600 * 24); // if it takes more than 24 hours we're in trouble $vn_id = $req->getParameter('exporter_id', pInteger); $t_exporter = new ca_data_exporters($vn_id); $vs_file = tempnam(__CA_APP_DIR__ . DIRECTORY_SEPARATOR . 'tmp', 'dataExport'); // we have 3 different sources for batch exports: search/browse result, sets and search expressions (deprecated) // they all operate on different parameters and on different static functions in ca_data_exporters if ($req->getParameter('caIsExportFromSearchOrBrowseResult', pInteger)) { // batch export from search or browse result $vs_find_type = $req->getParameter('find_type', pString); $vo_result_context = new ResultContext($req, $t_exporter->getTargetTableName(), $vs_find_type); $t_instance = $t_exporter->getTargetTableInstance(); $o_result = $t_instance->makeSearchResult($t_instance->tableName(), $vo_result_context->getResultList()); ca_data_exporters::exportRecordsFromSearchResult($t_exporter->get('exporter_code'), $o_result, $vs_file, array('request' => $req, 'progressCallback' => 'caIncrementBatchMetadataExportProgress')); } else { if ($vn_set_id = $req->getParameter('set_id', pInteger)) { // batch export from set ca_data_exporters::exportRecordsFromSet($t_exporter->get('exporter_code'), $vn_set_id, $vs_file, array('request' => $req, 'progressCallback' => 'caIncrementBatchMetadataExportProgress')); } else { // batch export from search expression (deprecated) $vs_search = $req->getParameter('search', pString); ca_data_exporters::exportRecordsFromSearchExpression($t_exporter->get('exporter_code'), $vs_search, $vs_file, array('request' => $req, 'progressCallback' => 'caIncrementBatchMetadataExportProgress')); } } // export done, record it in session for later usage in download/destination action if (filesize($vs_file)) { $o_session = $req->getSession(); $o_session->setVar('export_file', $vs_file); $o_session->setVar('export_content_type', $t_exporter->getContentType()); $o_session->setVar('exporter_id', $t_exporter->getPrimaryKey()); caExportAddDownloadLink($req); } }
protected function _genExportWithMapping($po_result, $pn_exporter_id) { // Can user batch export? if (!$this->request->user->canDoAction('can_batch_export_metadata')) { $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/3440?r=' . urlencode($this->request->getFullUrlPath())); return; } // Can user export records of this type? if (!$this->request->user->canDoAction('can_export_' . $this->ops_tablename)) { $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/3430?r=' . urlencode($this->request->getFullUrlPath())); return; } $t_exporter = new ca_data_exporters($pn_exporter_id); if (!($t_exporter->getPrimaryKey() > 0)) { $this->postError(3420, _t("Could not load export mapping"), "BaseFindController->_genExportWithMapping()"); return; } if (substr(get_class($this), 0, 6) == 'Browse') { $vs_export_filename = Configuration::load()->get($this->ops_tablename . '_batch_export_filename'); } else { $vs_export_filename = preg_replace("/[^\\p{L}\\p{N}\\-]/", '_', $this->opo_result_context->getSearchExpression()); $vs_export_filename = preg_replace("/[\\_]+/", '_', $vs_export_filename); } $vs_tmp_file = tempnam(caGetTempDirPath(), 'export'); ca_data_exporters::exportRecordsFromSearchResult($t_exporter->get('exporter_code'), $po_result, $vs_tmp_file); header('Content-Type: ' . $t_exporter->getContentType() . '; charset=UTF-8'); header('Content-Disposition: attachment; filename="' . $vs_export_filename . '.' . $t_exporter->getFileExtension() . '"'); header('Content-Transfer-Encoding: binary'); readfile($vs_tmp_file); @unlink($vs_tmp_file); exit; }
/** * Load exporter configuration from XLSX file * @param string $ps_source file path for source XLSX * @param array $pa_errors call-by-reference array to store and "return" error messages * @param array $pa_options options * @return ca_data_exporters BaseModel representation of the new exporter. false/null if there was an error. */ public static function loadExporterFromFile($ps_source, &$pa_errors, $pa_options = null) { global $g_ui_locale_id; $vn_locale_id = isset($pa_options['locale_id']) && (int) $pa_options['locale_id'] ? (int) $pa_options['locale_id'] : $g_ui_locale_id; $pa_errors = array(); $o_excel = PHPExcel_IOFactory::load($ps_source); $o_sheet = $o_excel->getSheet(0); $vn_row = 0; $va_settings = array(); $va_mappings = array(); $va_ids = array(); foreach ($o_sheet->getRowIterator() as $o_row) { if ($vn_row++ == 0) { // skip first row (headers) continue; } $vn_row_num = $o_row->getRowIndex(); $o_cell = $o_sheet->getCellByColumnAndRow(0, $vn_row_num); $vs_mode = (string) $o_cell->getValue(); switch ($vs_mode) { case 'Mapping': case 'Constant': case 'Variable': case 'RepeatMappings': $o_id = $o_sheet->getCellByColumnAndRow(1, $o_row->getRowIndex()); $o_parent = $o_sheet->getCellByColumnAndRow(2, $o_row->getRowIndex()); $o_element = $o_sheet->getCellByColumnAndRow(3, $o_row->getRowIndex()); $o_source = $o_sheet->getCellByColumnAndRow(4, $o_row->getRowIndex()); $o_options = $o_sheet->getCellByColumnAndRow(5, $o_row->getRowIndex()); if ($vs_id = trim((string) $o_id->getValue())) { $va_ids[] = $vs_id; } if ($vs_parent_id = trim((string) $o_parent->getValue())) { if (!in_array($vs_parent_id, $va_ids) && $vs_parent_id != $vs_id) { $pa_errors[] = _t("Warning: skipped mapping at row %1 because parent id was invalid", $vn_row); continue 2; } } if (!($vs_element = trim((string) $o_element->getValue()))) { $pa_errors[] = _t("Warning: skipped mapping at row %1 because element was not defined", $vn_row); continue 2; } $vs_source = trim((string) $o_source->getValue()); if ($vs_mode == 'Constant') { if (strlen($vs_source) < 1) { // ignore constant rows without value continue; } $vs_source = "_CONSTANT_:{$vs_source}"; } if ($vs_mode == 'Variable') { if (preg_match("/^[A-Za-z0-9\\_\\-]+\$/", $vs_element)) { $vs_element = "_VARIABLE_:{$vs_element}"; } else { $pa_errors[] = _t("Variable name %1 is invalid. It should only contain ASCII letters, numbers, hyphens and underscores. The variable was not created.", $vs_element); continue 2; } } $va_options = null; if ($vs_options_json = (string) $o_options->getValue()) { if (is_null($va_options = @json_decode($vs_options_json, true))) { $pa_errors[] = _t("Warning: options for element %1 are not in proper JSON", $vs_element); } } $va_options['_id'] = (string) $o_id->getValue(); // stash ID for future reference $vs_key = strlen($vs_id) > 0 ? $vs_id : md5($vn_row); $va_mapping[$vs_key] = array('parent_id' => $vs_parent_id, 'element' => $vs_element, 'source' => $vs_mode == "RepeatMappings" ? null : $vs_source, 'options' => $va_options); // allow mapping repetition if ($vs_mode == 'RepeatMappings') { if (strlen($vs_source) < 1) { // ignore repitition rows without value continue; } $va_new_items = array(); $va_mapping_items_to_repeat = explode(',', $vs_source); foreach ($va_mapping_items_to_repeat as $vs_mapping_item_to_repeat) { $vs_mapping_item_to_repeat = trim($vs_mapping_item_to_repeat); if (!is_array($va_mapping[$vs_mapping_item_to_repeat])) { $pa_errors[] = _t("Couldn't repeat mapping item %1", $vs_mapping_item_to_repeat); continue; } // add item to repeat under current item $va_new_items[$vs_key . "_:_" . $vs_mapping_item_to_repeat] = $va_mapping[$vs_mapping_item_to_repeat]; $va_new_items[$vs_key . "_:_" . $vs_mapping_item_to_repeat]['parent_id'] = $vs_key; // Find children of item to repeat (and their children) and add them as well, preserving the hierarchy // the code below banks on the fact that hierarchy children are always defined AFTER their parents // in the mapping document. $va_keys_to_lookup = array($vs_mapping_item_to_repeat); foreach ($va_mapping as $vs_item_key => $va_item) { if (in_array($va_item['parent_id'], $va_keys_to_lookup)) { $va_keys_to_lookup[] = $vs_item_key; $va_new_items[$vs_key . "_:_" . $vs_item_key] = $va_item; $va_new_items[$vs_key . "_:_" . $vs_item_key]['parent_id'] = $vs_key . ($va_item['parent_id'] ? "_:_" . $va_item['parent_id'] : ""); } } } $va_mapping = $va_mapping + $va_new_items; } break; case 'Setting': $o_setting_name = $o_sheet->getCellByColumnAndRow(1, $o_row->getRowIndex()); $o_setting_value = $o_sheet->getCellByColumnAndRow(2, $o_row->getRowIndex()); $va_settings[(string) $o_setting_name->getValue()] = (string) $o_setting_value->getValue(); break; default: // if 1st column is empty, skip continue 2; break; } } // try to extract replacements from 2nd sheet in file // PHPExcel will throw an exception if there's no such sheet try { $o_sheet = $o_excel->getSheet(1); $vn_row = 0; foreach ($o_sheet->getRowIterator() as $o_row) { if ($vn_row == 0) { // skip first row (headers) $vn_row++; continue; } $vn_row_num = $o_row->getRowIndex(); $o_cell = $o_sheet->getCellByColumnAndRow(0, $vn_row_num); $vs_mapping_num = trim((string) $o_cell->getValue()); if (strlen($vs_mapping_num) < 1) { continue; } $o_search = $o_sheet->getCellByColumnAndRow(1, $o_row->getRowIndex()); $o_replace = $o_sheet->getCellByColumnAndRow(2, $o_row->getRowIndex()); if (!isset($va_mapping[$vs_mapping_num])) { $pa_errors[] = _t("Warning: Replacement sheet references invalid mapping number '%1'. Ignoring row.", $vs_mapping_num); continue; } $vs_search = (string) $o_search->getValue(); $vs_replace = (string) $o_replace->getValue(); if (!$vs_search) { $pa_errors[] = _t("Warning: Search must be set for each row in the replacement sheet. Ignoring row for mapping '%1'", $vs_mapping_num); continue; } // look for replacements foreach ($va_mapping as $vs_k => &$va_v) { if (preg_match("!\\_\\:\\_" . $vs_mapping_num . "\$!", $vs_k)) { $va_v['options']['original_values'][] = $vs_search; $va_v['options']['replacement_values'][] = $vs_replace; } } $va_mapping[$vs_mapping_num]['options']['original_values'][] = $vs_search; $va_mapping[$vs_mapping_num]['options']['replacement_values'][] = $vs_replace; $vn_row++; } } catch (PHPExcel_Exception $e) { // noop, because we don't care: mappings without replacements are still valid } // Do checks on mapping if (!$va_settings['code']) { $pa_errors[] = _t("Error: You must set a code for your mapping!"); return; } $o_dm = Datamodel::load(); if (!($t_instance = $o_dm->getInstanceByTableName($va_settings['table']))) { $pa_errors[] = _t("Error: Mapping target table %1 is invalid!", $va_settings['table']); return; } if (!$va_settings['name']) { $va_settings['name'] = $va_settings['code']; } $t_exporter = new ca_data_exporters(); $t_exporter->setMode(ACCESS_WRITE); // Remove any existing mapping with this code if ($t_exporter->load(array('exporter_code' => $va_settings['code']))) { $t_exporter->delete(true, array('hard' => true)); if ($t_exporter->numErrors()) { $pa_errors[] = _t("Could not delete existing mapping for %1: %2", $va_settings['code'], join("; ", $t_exporter->getErrors())); return; } } // Create new mapping $t_exporter->set('exporter_code', $va_settings['code']); $t_exporter->set('table_num', $t_instance->tableNum()); $vs_name = $va_settings['name']; unset($va_settings['code']); unset($va_settings['table']); unset($va_settings['name']); foreach ($va_settings as $vs_k => $vs_v) { $t_exporter->setSetting($vs_k, $vs_v); } $t_exporter->insert(); if ($t_exporter->numErrors()) { $pa_errors[] = _t("Error creating exporter: %1", join("; ", $t_exporter->getErrors())); return; } $t_exporter->addLabel(array('name' => $vs_name), $vn_locale_id, null, true); if ($t_exporter->numErrors()) { $pa_errors[] = _t("Error creating exporter name: %1", join("; ", $t_exporter->getErrors())); return; } $va_id_map = array(); foreach ($va_mapping as $vs_mapping_id => $va_info) { $va_item_settings = array(); if (is_array($va_info['options'])) { foreach ($va_info['options'] as $vs_k => $vs_v) { switch ($vs_k) { case 'replacement_values': case 'original_values': if (sizeof($vs_v) > 0) { $va_item_settings[$vs_k] = join("\n", $vs_v); } break; default: $va_item_settings[$vs_k] = $vs_v; break; } } } $vn_parent_id = null; if ($va_info['parent_id']) { $vn_parent_id = $va_id_map[$va_info['parent_id']]; } $t_item = $t_exporter->addItem($vn_parent_id, $va_info['element'], $va_info['source'], $va_item_settings); if ($t_exporter->numErrors()) { $pa_errors[] = _t("Error adding item to exporter: %1", join("; ", $t_exporter->getErrors())); return; } $va_id_map[$vs_mapping_id] = $t_item->getPrimaryKey(); } $va_mapping_errors = ca_data_exporters::checkMapping($t_exporter->get('exporter_code')); if (is_array($va_mapping_errors) && sizeof($va_mapping_errors) > 0) { $pa_errors = array_merge($pa_errors, $va_mapping_errors); return false; } return $t_exporter; }
/** * Prepare export generated by ExportData action */ public function SetupBatchExport() { $o_conf = Configuration::load(); $o_session = $this->getRequest()->getSession(); if (!($vn_exporter_id = $o_session->getVar('exporter_id'))) { $this->getResponse()->setRedirect($this->getRequest()->config->get('error_display_url') . '/n/3420?r=' . urlencode($this->getRequest()->getFullUrlPath())); return; } $t_exporter = new ca_data_exporters($vn_exporter_id); if (!$t_exporter->getPrimaryKey()) { $this->getResponse()->setRedirect($this->getRequest()->config->get('error_display_url') . '/n/3420?r=' . urlencode($this->getRequest()->getFullUrlPath())); return; } $t_subject = $t_exporter->getAppDatamodel()->getInstanceByTableNum($t_exporter->get('table_num'), true); // alternate destinations $va_alt_dest = $o_conf->getAssoc('exporter_alternate_destinations'); $this->getView()->setVar('exporter_alternate_destinations', $va_alt_dest); // filename set via request wins $vs_filename = $this->getRequest()->getParameter('file_name', pString); // otherwise get from config file if (!$vs_filename) { if ($vs_filename = $o_conf->get($t_subject->tableName() . "_batch_export_filename")) { // config setting comes without file extension $vs_filename = $vs_filename . '.' . $t_exporter->getFileExtension(); } } // still no filename? -> go for hardcoded default if (!$vs_filename) { $vs_filename = 'batch_export.' . $t_exporter->getFileExtension(); } // pass to view $this->getView()->setVar('file_name', $vs_filename); $this->render('export/export_destination_html.php'); }