taxonomy_csv.export.api.inc in Taxonomy CSV import/export 6.3
Validate export options and manage export process.
File
export/taxonomy_csv.export.api.incView source
<?php
/**
* @file
* Validate export options and manage export process.
*/
/**
* Invoke associated include file.
* taxonomy_csv.export.admin.inc is invoked only if user wants to check input
* options.
* taxonomy_csv.export.result.inc is invoked only if user wants result messages.
*/
$module_dir = drupal_get_path('module', 'taxonomy_csv');
require_once "{$module_dir}/taxonomy_csv.api.inc";
require_once "{$module_dir}/taxonomy_csv.term.api.inc";
/**
* Process the export of a vocabulary.
*
* If not used in a form, don't forget to use batch_process().
*
* @param $options
* An associative array of options:
* - export_format : see _taxonomy_csv_values('export_format')
* - vocabulary_id : vocabulary id to export (default: 0, which means all)
* - delimiter : one character csv delimiter (default: ',')
* - enclosure : zero or one character csv enclosure (default: '"')
* - line_ending : 'Unix' (default), 'Mac' or 'MS-DOS'
* - order : order of terms: 'name' (default), 'tid' or 'weight'
* // Specific to def_links:
* - def_links_terms_ids : 'name_if_needed' (default), 'name' or 'tid'
* - def_links_vocabularies_ids : 'none' (default), 'name' or 'vid'
* // Level of result process infos.
* - check_options : boolean. check or not (default) this array of options
* - result_display: boolean. display or not (default). Only used with UI.
* - result_duplicates: boolean. display or not (default) duplicate terms.
* Only export_format is needed. Other options have default values.
* Warning: default values are different with UI.
*
* @return
* Array of errors or file object to download (need to execute batch process;
* result is logged in watchdog).
*/
function taxonomy_csv_export($options) {
// Complete $options with default values if needed.
// Default api and UI options are different.
$options += _taxonomy_csv_values('export_default_api');
// Presave a file in order to check access to temporary folder.
$messages = _taxonomy_csv_export_output_presave($options);
if (count($messages)) {
return $messages;
}
// Process export.
taxonomy_csv_vocabulary_export($options);
// File object.
return $options['file'];
}
/**
* Presave output.
*
* Check if there is write access and prepare file.
*
* @param $options
* Array. Same as taxonomy_csv_export.
*
* @return
* Array of messages errors if any.
* By reference options are cleaned and completed.
*/
function _taxonomy_csv_export_output_presave(&$options) {
$messages = array();
// Check if there is write access and prepare file.
// Set filename.
if ($options['vocabulary_id']) {
$vocabulary = taxonomy_vocabulary_load($options['vocabulary_id']);
$vocabulary_name = $vocabulary->name;
}
else {
$vocabulary_name = t('Taxonomy');
}
// Create file.
$filename = file_save_data('', "{$vocabulary_name}.csv", 'FILE_EXISTS_RENAME');
if (!$filename) {
$messages['file'] = t('Check access rights to temp directory : export needs permission to write and to read in it. Export failed.');
}
else {
$options['file'] = (object) array(
'filename' => basename($filename),
'filepath' => realpath($filename),
'filesize' => filesize($filename),
);
}
return $messages;
}
/**
* Prepare the export of a vocabulary.
* If not used in a form, don't forget to use batch_process().
*
* @param $options
* Array. Same as taxonomy_csv_export.
*
* @return
* Array of errors or nothing (batch process to execute).
*/
function taxonomy_csv_vocabulary_export($options) {
// Check options and return array of messages in case of errors.
if ($options['check_options']) {
// Invoke export admin file.
$module_dir = drupal_get_path('module', 'taxonomy_csv');
require_once "{$module_dir}/export/taxonomy_csv.export.admin.inc";
$result = _taxonomy_csv_export_check_options($options);
if (count($result)) {
return $result;
}
}
// Complete $options with some csv variables.
$options['separator'] = $options['enclosure'] . $options['delimiter'] . $options['enclosure'];
$line_ending = array(
'Unix' => "\n",
'Mac' => "\r",
'MSDOS' => "\r\n",
);
$options['end_of_line'] = $line_ending[$options['line_ending']];
// Calculates number of terms to be exported.
$options['total_terms'] = taxonomy_csv_term_count_in_vocabulary($options['vocabulary_id']);
// Prepare export batch.
$batch = array(
'title' => t('Exporting !total_terms terms to CSV file...', array(
'!total_terms' => $options['total_terms'],
)),
'init_message' => t('Starting downloading of datas...'),
'progress_message' => '',
'error_message' => t('An error occurred during the export.'),
'finished' => '_taxonomy_csv_vocabulary_export_finished',
'file' => drupal_get_path('module', 'taxonomy_csv') . '/export/taxonomy_csv.export.api.inc',
'progressive' => TRUE,
'operations' => array(
0 => array(
'_taxonomy_csv_vocabulary_export_process',
array(
$options,
),
),
),
);
batch_set($batch);
}
/**
* Batch process of vocabulary export.
*
* @todo Check if direct query and only tid save is really less memory
* intensive (with core taxonomy cache or not).
* @todo Don't remember terms, but load them one by one in order to decrease
* memory usage.
*
* @param $options
* Array of batch options.
* @param &$context
* Batch context to keep results and messages.
*
* @return
* NULL because use of &$context.
*/
function _taxonomy_csv_vocabulary_export_process($options, &$context) {
// First callback.
if (empty($context['sandbox'])) {
// Remember options as batch_set can't use form_storage.
// It allows too that first line in result is numbered 1 and not 0.
$context['results'][0] = $options;
// Initialize some variables.
$context['results'][0]['current_term'] = 0;
$context['results'][0]['current_name'] = '';
$context['results'][0]['worst_term'] = 0;
$context['results'][0]['worst_name'] = '';
$context['results'][0]['worst_message'] = 799;
// No pointer because new line is appended to file.
$context['results'][0]['handle'] = fopen($options['file']->filepath, 'a+');
$context['sandbox']['max'] = $options['total_terms'];
// Prepare terms to be exported.
$context['sandbox']['terms'] = taxonomy_csv_term_load_multiple(array(), array(
'vid' => $options['vocabulary_id'],
'order' => $options['order'],
));
// Prepare list of duplicate terms if needed.
$context['results'][0]['duplicate_terms'] = array();
if (in_array($options['export_format'], array(
TAXONOMY_CSV_FORMAT_DEFINITION_LINKS,
))) {
$context['results'][0]['duplicate_terms'] = taxonomy_csv_term_find_duplicate($options['vocabulary_id']);
}
}
elseif (!is_resource($context['results'][0]['handle'])) {
// Reopen file in case of memory out.
$context['results'][0]['handle'] = fopen($options['file']->filepath, 'a+');
}
// Load and process one term.
$worst_term =& $context['results'][0]['worst_term'];
$worst_name =& $context['results'][0]['worst_name'];
$worst_message =& $context['results'][0]['worst_message'];
$handle =& $context['results'][0]['handle'];
$duplicate_terms =& $context['results'][0]['duplicate_terms'];
$term_number =& $context['results'][0]['current_term'];
$current_name =& $context['results'][0]['current_name'];
$term = array_shift($context['sandbox']['terms']);
if ($term) {
$term_number++;
// Remember current name in case of error.
$current_name = $term->name;
// Process export of current term.
$result = taxonomy_csv_term_export($term, $options, $duplicate_terms);
$result['msg'] = taxonomy_csv_line_export($result['line'], $options, $handle, $result['msg']);
// Remember worst message of exported terms.
$worst_message_new = _taxonomy_csv_worst_message($result['msg']);
if ($worst_message > $worst_message_new) {
$worst_term = $term_number;
$worst_name = $current_name;
$worst_message = $worst_message_new;
}
// Remember messages. Currently useless because there isn't any warning or
// notice message (only error). A result level can be added here if needed.
if (count($result['msg'])) {
$context['results'][$line_number] = $result['msg'];
}
// Inform about progress.
$context['message'] = t('Term !term_number of !total_terms processed: %term', array(
'!term_number' => $term_number,
'!total_terms' => $options['total_terms'],
'%term' => $current_name,
));
// Check worst message of exported terms and update progress.
if ($worst_message >= TAXONOMY_CSV_PROCESS_WARNING) {
// Count should be <= 0.99 to avoid to display "100%" before end.
$context['finished'] = floor($term_number / $context['sandbox']['max'] * 100) / 100;
}
else {
$context['finished'] = 1;
}
}
}
/**
* Callback for finished batch export and display result informations.
*/
function _taxonomy_csv_vocabulary_export_finished($success, $results, $operations) {
$options =& $results[0];
unset($results[0]);
// Close exported file.
if ($options['handle']) {
fclose($options['handle']);
}
// Invoke export stats file if user wants to display results.
if ($options['result_display']) {
$module_dir = drupal_get_path('module', 'taxonomy_csv');
require_once "{$module_dir}/export/taxonomy_csv.export.result.inc";
}
// Short summary information is different if batch succeeded or not.
if ($success) {
$variables = array(
'!total_terms' => $options['total_terms'],
'!worst_count' => $options['worst_term'],
'@worst_name' => $options['worst_name'],
'!worst_msg' => $options['result_display'] ? _taxonomy_csv_message_text($options['worst_message']) : t('Message code') . ' = ' . $options['worst_message'],
);
$messages = array(
WATCHDOG_DEBUG => t('No error, warnings or notices have been reported during export process of !total_terms terms.', $variables),
WATCHDOG_INFO => t('No error, warnings or notices have been reported during export process of !total_terms terms.', $variables),
WATCHDOG_NOTICE => t('Notices have been reported during export process (bad formatted or empty terms). !total_terms terms processed. First notice occurred on term !worst_count (@worst_name) [!worst_msg].', $variables),
WATCHDOG_WARNING => t('Warnings have been reported during export process (bad formatted terms). !total_terms terms processed. First term skipped is term !worst_count (@worst_name) [!worst_msg].', $variables),
WATCHDOG_ERROR => t('Errors have been reported during export process. Process failed at term !worst_count (@worst_name) of a total of !total_terms [!worst_msg].', $variables),
);
$worst_level = intval($options['worst_message'] / 100);
$message = $messages[$worst_level];
}
else {
$message = t('Exportation failed. Export process was successful until the term !term_count (@term_name) of a total of !total_terms.', array(
'!term_count' => $options['current_term'],
'@term_name' => $options['current_name'],
'!total_terms' => $options['total_terms'],
)) . '<br />' . t('This issue is related to export process and may be caused by a memory overrun of the database. If not, you can reinstall module from a fresh release or submit an issue on <a href="!link">Taxonomy CSV import/export module</a>.', array(
'!link' => url('http://drupal.org/project/issues/taxonomy_csv/'),
));
$worst_level = WATCHDOG_ERROR;
}
// Set result message in watchdog and eventually in user interface.
// Use of a $message variable is unrecommended, but simpler and working.
// See http://drupal.org/node/323101
watchdog('taxonomy_csv', $message, NULL, $worst_level);
if ($options['result_display']) {
_taxonomy_csv_export_result($options, $worst_level, $message, $results);
}
}
/**
* Export a line.
*
* @param $line
* Array to be exported to a line.
* @param $options
* An associative array of export options:
* - 'separator' : string separator (formatted delimiter and enclosure).
* - 'enclosure' : item enclosure.
* - 'end_of_line': end of line string.
* @param $handle
* Handle of the open file where to save line.
* @param $result_message
* (Optional) Array of messages.
*
* @return Result array:
* Array of messages.
*/
function taxonomy_csv_line_export($line, $options, &$handle, $result = array()) {
// Check if separator, enclosure or line ending exist in line.
$check_line = implode('', $line);
if (strpos($check_line, $options['separator']) !== FALSE || $options['enclosure'] != '' && strpos($check_line, $options['enclosure']) !== FALSE || $options['enclosure'] == '' && strpos($check_line, $options['end_of_line']) !== FALSE) {
$result[] = 313;
// Error delimiter or enclosure.
}
else {
// Save line to file.
$line = $options['enclosure'] . implode($options['separator'], $line) . $options['enclosure'] . $options['end_of_line'];
if (fwrite($handle, $line) === FALSE) {
$result[] = 312;
// Unable to write to file.
}
}
return $result;
}
/**
* Export a term to a line matching the options.
*
* @param $term
* Full term object to export.
* @param $options
* An associative array of export options:
* - export_format : see _taxonomy_csv_values('export_format')
* // Specific to def_links:
* - def_links_terms_ids : 'name_if_needed' (default), 'name' or 'tid'
* - def_links_vocabularies_ids : 'none' (default), 'name' or 'vid'
* @param $duplicate_terms
* (Optional) Array of duplicate terms names indexed by tid.
* Duplicate terms are managed only with def_links.
*
* @return Result array:
* 'line' => array of exported items,
* 'msg' => array of messages arrays.
*/
function taxonomy_csv_term_export($term, $options, $duplicate_terms = array()) {
// Define default values.
$result = array(
'line' => array(),
'msg' => array(),
);
// Only count check because term and options are already checked.
if (count($term)) {
switch ($options['export_format']) {
case TAXONOMY_CSV_FORMAT_ALONE_TERMS:
$result['line'] = array(
$term->name,
);
break;
case TAXONOMY_CSV_FORMAT_DEFINITION_LINKS:
// Prepare identifiants of main term and links.
// Check if each term is a duplicate, because identifiants are names,
// except for duplicate terms. For them, tid is appended to name.
$terms = array(
'main' => array(
$term,
),
// Synonyms are included in term object in Drupal 6.
'parents' => taxonomy_get_parents($term->tid),
'children' => taxonomy_get_children($term->tid),
'relations' => taxonomy_get_related($term->tid),
);
foreach (array(
'main',
'parents',
'children',
'relations',
) as $link) {
$ids[$link] = array();
foreach ($terms[$link] as $item) {
// Option is to use term id.
if ($options['def_links_terms_ids'] == 'tid') {
$ids[$link][] = $item->tid;
}
elseif (isset($duplicate_terms[$item->tid])) {
$ids[$link][] = $item->name . ' ' . $item->tid;
}
else {
$ids[$link][] = $item->name;
}
}
}
// Prepare main term vocabulary identifiant.
// Vocabulary identifiant depends on def_links_vocabularies_ids.
$vocabulary = taxonomy_vocabulary_load($term->vid);
$vid = $options['def_links_vocabularies_ids'] == 'none' ? '' : $vocabulary->{$options}['def_links_vocabularies_ids'];
// Prepare vocabularies identifiants of related terms.
$relations_vocs = array();
// Option 'none' is impossible with multiple vocabularies, so use name.
$vocabulary_option = $options['def_links_vocabularies_ids'] == 'none' ? 'name' : $options['def_links_vocabularies_ids'];
foreach ($terms['relations'] as $item) {
// Check if related term vocabulary is main term vocabulary.
$vocabulary = taxonomy_vocabulary_load($item->vid);
$relations_vocs[] = $item->vid == $term->vid ? $vid : $vocabulary->{$vocabulary_option};
}
$result['line'] = array_merge(array(
$term->name,
// Main term identifiant: use tid, name or nothing.
$options['def_links_terms_ids'] == 'name_if_needed' && $term->name == $ids['main'][0] ? '' : $ids['main'][0],
$vid,
$term->description,
$term->weight,
count($term->synonyms),
count($ids['parents']),
count($ids['children']),
count($ids['relations']),
), $term->synonyms, $ids['parents'], $ids['children'], $ids['relations'], $relations_vocs);
break;
case TAXONOMY_CSV_FORMAT_TREE_STRUCTURE:
break;
case TAXONOMY_CSV_FORMAT_POLYHIERARCHY:
break;
case TAXONOMY_CSV_FORMAT_PARENTS:
$result['line'] = array_merge(array(
$term->name,
), taxonomy_csv_term_get_parents_names($term->tid));
break;
case TAXONOMY_CSV_FORMAT_CHILDREN:
$result['line'] = array_merge(array(
$term->name,
), taxonomy_csv_term_get_children_names($term->tid));
break;
case TAXONOMY_CSV_FORMAT_RELATIONS:
$result['line'] = array_merge(array(
$term->name,
), taxonomy_csv_term_get_relations_names($term->tid));
break;
case TAXONOMY_CSV_FORMAT_SYNONYMS:
$result['line'] = array_merge(array(
$term->name,
), $term->synonyms);
break;
case TAXONOMY_CSV_FORMAT_DEFINITIONS:
$result['line'] = array_merge(array(
$term->name,
$term->weight,
$term->description,
), $term->synonyms);
break;
case TAXONOMY_CSV_FORMAT_DESCRIPTIONS:
$result['line'] = array(
$term->name,
$term->description,
);
break;
case TAXONOMY_CSV_FORMAT_WEIGHTS:
$result['line'] = array(
$term->name,
$term->weight,
);
break;
case TAXONOMY_CSV_FORMAT_FIELDS:
// @todo Extra fields.
break;
default:
// Check external formats. Use it only if it works.
$funcname = "taxonomy_csv_term_export_{$options['export_format']}";
if (taxonomy_csv_format_check($options['export_format'], $funcname)) {
$result = $funcname($term, $options, $duplicate_terms);
}
else {
$result['msg'][] = 307;
// Error unknown export format.
}
}
}
else {
$result['msg'][] = 385;
// Error no term to process.
}
// Clean result.
$result['msg'] = array_unique($result['msg']);
sort($result['msg']);
return $result;
}
Functions
Name![]() |
Description |
---|---|
taxonomy_csv_export | Process the export of a vocabulary. |
taxonomy_csv_line_export | Export a line. |
taxonomy_csv_term_export | Export a term to a line matching the options. |
taxonomy_csv_vocabulary_export | Prepare the export of a vocabulary. If not used in a form, don't forget to use batch_process(). |
_taxonomy_csv_export_output_presave | Presave output. |
_taxonomy_csv_vocabulary_export_finished | Callback for finished batch export and display result informations. |
_taxonomy_csv_vocabulary_export_process | Batch process of vocabulary export. |