/** * Export a record set as defined by the given search expression and the table_num for this exporter. * This function wraps the record-level exports using the settings 'wrap_before' and 'wrap_after' if they are set. * @param string $ps_exporter_code defines the exporter to use * @param SearchResult $po_result An existing SearchResult object * @param string $ps_filename Destination filename (we can't keep everything in memory here) * @param array $pa_options * progressCallback = callback function for asynchronous UI status reporting * showCLIProgressBar = Show command-line progress bar. Default is false. * logDirectory = path to directory where logs should be written * logLevel = KLogger constant for minimum log level to record. Default is KLogger::INFO. Constants are, in descending order of shrillness: * KLogger::EMERG = Emergency messages (system is unusable) * KLogger::ALERT = Alert messages (action must be taken immediately) * KLogger::CRIT = Critical conditions * KLogger::ERR = Error conditions * KLogger::WARN = Warnings * KLogger::NOTICE = Notices (normal but significant conditions) * KLogger::INFO = Informational messages * KLogger::DEBUG = Debugging messages * @return boolean success state */ public static function exportRecordsFromSearchResult($ps_exporter_code, $po_result, $ps_filename, $pa_options = array()) { if (!$po_result instanceof SearchResult) { return false; } $vs_log_dir = caGetOption('logDirectory', $pa_options); if (!file_exists($vs_log_dir) || !is_writable($vs_log_dir)) { $vs_log_dir = caGetTempDirPath(); } if (!($vn_log_level = caGetOption('logLevel', $pa_options))) { $vn_log_level = KLogger::INFO; } $o_log = new KLogger($vs_log_dir, $vn_log_level); ca_data_exporters::$s_exporter_cache = array(); ca_data_exporters::$s_exporter_item_cache = array(); $vb_show_cli_progress_bar = isset($pa_options['showCLIProgressBar']) && $pa_options['showCLIProgressBar']; $po_request = caGetOption('request', $pa_options, null); $vb_have_request = $po_request instanceof RequestHTTP; if (!($t_mapping = ca_data_exporters::loadExporterByCode($ps_exporter_code))) { return false; } $va_errors = ca_data_exporters::checkMapping($ps_exporter_code); if (sizeof($va_errors) > 0) { if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, 0, -1, _t('Export failed: %1', join("; ", $va_errors)), 0, memory_get_usage(true), 0); } return false; } $o_log->logInfo(_t("Starting SearchResult-based multi-record export for mapping %1.", $ps_exporter_code)); $vn_start_time = time(); $vs_wrap_before = $t_mapping->getSetting('wrap_before'); $vs_wrap_after = $t_mapping->getSetting('wrap_after'); $t_instance = $t_mapping->getAppDatamodel()->getInstanceByTableNum($t_mapping->get('table_num')); $vn_num_items = $po_result->numHits(); $o_log->logInfo(_t("SearchResult contains %1 results. Now calling single-item export for each record.", $vn_num_items)); if ($vs_wrap_before) { file_put_contents($ps_filename, $vs_wrap_before . "\n", FILE_APPEND); } if ($vb_show_cli_progress_bar) { print CLIProgressBar::start($vn_num_items, _t('Processing search result')); } if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { if ($vn_num_items > 0) { $ps_callback($po_request, 0, $vn_num_items, _t("Exporting result"), time() - $vn_start_time, memory_get_usage(true), 0); } else { $ps_callback($po_request, 0, -1, _t('Found no records to export'), time() - $vn_start_time, memory_get_usage(true), 0); } } $vn_num_processed = 0; if ($t_mapping->getSetting('CSV_print_field_names')) { $va_header = $va_header_sources = array(); $va_mapping_items = $t_mapping->getItems(); foreach ($va_mapping_items as $vn_i => $va_mapping_item) { $va_settings = caUnserializeForDatabase($va_mapping_item['settings']); $va_header_sources[(int) $va_mapping_item['element']] = $va_settings['_id'] ? $va_settings['_id'] : $va_mapping_item['source']; } ksort($va_header_sources); foreach ($va_header_sources as $vn_element => $vs_source) { $va_tmp = explode(".", $vs_source); if ($t_table = $t_mapping->getAppDatamodel()->getInstanceByTableName($va_tmp[0], true)) { $va_header[] = $t_table->getDisplayLabel($vs_source); } else { $va_header[] = $vs_source; } } file_put_contents($ps_filename, join(",", $va_header) . "\n", FILE_APPEND); } $i = 0; while ($po_result->nextHit()) { // clear caches every once in a while. doesn't make much sense to keep them around while exporting if (++$i % 1000 == 0) { SearchResult::clearCaches(); ca_data_exporters::clearCaches(); } if ($vb_have_request) { if (!caCanRead($po_request->getUserID(), $t_instance->tableNum(), $po_result->get($t_instance->primaryKey()))) { continue; } } $vs_item_export = ca_data_exporters::exportRecord($ps_exporter_code, $po_result->get($t_instance->primaryKey()), array('logger' => $o_log)); file_put_contents($ps_filename, $vs_item_export . "\n", FILE_APPEND); if ($vb_show_cli_progress_bar) { print CLIProgressBar::next(1, _t("Exporting records ...")); } $vn_num_processed++; if ($vb_have_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, $vn_num_processed, $vn_num_items, _t("Exporting ... [%1/%2]", $vn_num_processed, $vn_num_items), time() - $vn_start_time, memory_get_usage(true), $vn_num_processed); } } if ($vs_wrap_after) { file_put_contents($ps_filename, $vs_wrap_after . "\n", FILE_APPEND); } if ($vb_show_cli_progress_bar) { print CLIProgressBar::finish(); } if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, $vn_num_items, $vn_num_items, _t('Export completed'), time() - $vn_start_time, memory_get_usage(true), $vn_num_processed); } return true; }