Skip to content
Snippets Groups Projects
Commit 08985df1 authored by megachriz's avatar megachriz Committed by MegaChriz
Browse files

Issue #1171114 by drclaw, MegaChriz, twistor, impara, cgmonroe, Anas_maw,...

Issue #1171114 by drclaw, MegaChriz, twistor, impara, cgmonroe, Anas_maw, azinck, justanothermark, vinmassaro, rhouse, lwalley, patrik.hultgren, kenpeter, ufku, mahmost: Allow user to choose the method of file handling.
parent df1afad1
No related branches found
No related tags found
No related merge requests found
......@@ -651,6 +651,9 @@ function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targe
return array(
'#type' => 'container',
'#attributes' => array(
'class' => array('feeds-target-config'),
),
'settings' => $settings_form,
'save_settings' => $base_button + array(
'#type' => 'submit',
......
......@@ -104,3 +104,11 @@ ul.container-actions li form input {
#center table form {
margin: 0;
}
div.feeds-container-body .feeds-target-config div.item-list ul li {
list-style: outside none disc;
margin: 0 0 0.25em 1.5em;
}
.feeds-target-config .description {
white-space: normal;
}
......@@ -6,6 +6,26 @@
* image.module.
*/
/**
* Flag for dealing with existing files: Replace the existing file if it is
* different. Do nothing if the new file is exactly the same as the existing
* file.
*/
define('FEEDS_FILE_EXISTS_REPLACE_DIFFERENT', 3);
/**
* Flag for dealing with existing files: If the new file is different, rename
* it by appending a number until the name is unique. Do nothing if the new file
* is exactly the same as the existing file.
*/
define('FEEDS_FILE_EXISTS_RENAME_DIFFERENT', 4);
/**
* Flag for dealing with existing files: Do nothing if a file with the same name
* already exists.
*/
define('FEEDS_FILE_EXISTS_SKIP', 5);
/**
* Implements hook_feeds_processor_targets().
*/
......@@ -21,6 +41,8 @@ function file_feeds_processor_targets($entity_type, $bundle_name) {
'callback' => 'file_feeds_set_target',
'description' => t('The URI of the @label field.', array('@label' => $instance['label'])),
'real_target' => $name,
'summary_callbacks' => array('file_feeds_summary_callback'),
'form_callbacks' => array('file_feeds_form_callback'),
);
// Keep the old target name for backwards compatibility, but hide it from
......@@ -61,6 +83,7 @@ function file_feeds_processor_targets($entity_type, $bundle_name) {
*/
function file_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
$language = $mapping['language'];
$mapping += array('file_exists' => FILE_EXISTS_RENAME);
// Add default of uri for backwards compatibility.
list($field_name, $sub_field) = explode(':', $target . ':uri');
......@@ -70,7 +93,7 @@ function file_feeds_set_target(FeedsSource $source, $entity, $target, array $val
foreach ($values as $k => $v) {
if (!($v instanceof FeedsEnclosure)) {
if (is_string($v)) {
if (!empty($v) && is_string($v)) {
$values[$k] = new FeedsEnclosure($v, file_get_mimetype($v));
}
else {
......@@ -121,15 +144,53 @@ function file_feeds_set_target(FeedsSource $source, $entity, $target, array $val
break;
case 'uri':
$skip = FALSE;
if ($v) {
if ($mapping['file_exists'] == FEEDS_FILE_EXISTS_SKIP) {
if (file_exists($destination . '/' . basename($v->getValue()))) {
$skip = TRUE;
}
else {
// We already know the file doesn't exist so we don't have to
// worry about anything being renamed, but we do need a valid
// replace value for file_save().
$mapping['file_exists'] = FILE_EXISTS_RENAME;
}
}
if ($mapping['file_exists'] == FEEDS_FILE_EXISTS_REPLACE_DIFFERENT) {
if (file_exists($destination . '/' . basename($v->getValue())) && file_feeds_file_compare($v->getValue(), $destination . '/' . basename($v->getValue()))) {
$skip = TRUE;
}
else {
// Either the file doesn't exist or it does and it's different.
$mapping['file_exists'] = FILE_EXISTS_REPLACE;
}
}
if ($mapping['file_exists'] == FEEDS_FILE_EXISTS_RENAME_DIFFERENT) {
if (file_exists($destination . '/' . basename($v->getValue())) && file_feeds_file_compare($v->getValue(), $destination . '/' . basename($v->getValue()))) {
$skip = TRUE;
}
else {
// Either the file doesn't exist or it does and it's different.
$mapping['file_exists'] = FILE_EXISTS_RENAME;
}
}
if ($skip) {
// Create a new dummy feeds enclosure where the value is the file
// already in the file system (it will be skipped by getFile()).
$mapping['file_exists'] = FEEDS_FILE_EXISTS_SKIP;
$existing_path = $destination . '/' . basename($v->getValue());
$v = new FeedsEnclosure($existing_path, file_get_mimetype($existing_path));
}
try {
$v->setAllowedExtensions($instance_info['settings']['file_extensions']);
$field[$language][$delta] += (array) $v->getFile($destination);
$field[$language][$delta] += (array) $v->getFile($destination, $mapping['file_exists']);
// @todo: Figure out how to properly populate this field.
$field[$language][$delta]['display'] = 1;
}
catch (Exception $e) {
watchdog('feeds', check_plain($e->getMessage()));
continue;
}
}
break;
......@@ -140,3 +201,89 @@ function file_feeds_set_target(FeedsSource $source, $entity, $target, array $val
$entity->$field_name = $field;
}
/**
* Mapping configuration summary callback for file targets.
*/
function file_feeds_summary_callback($mapping, $target, $form, $form_state) {
$mapping += array('file_exists' => FILE_EXISTS_RENAME);
switch ($mapping['file_exists']) {
case FILE_EXISTS_REPLACE:
return t('Replace existing files');
case FILE_EXISTS_RENAME:
return t('Rename if file exists');
case FEEDS_FILE_EXISTS_REPLACE_DIFFERENT:
return t('Replace only if file exists, but is different');
case FEEDS_FILE_EXISTS_RENAME_DIFFERENT:
return t('Rename only if file exists, but is different');
case FEEDS_FILE_EXISTS_SKIP:
return t('Skip if file exists');
}
}
/**
* Mapping configuration form callback for file targets.
*/
function file_feeds_form_callback($mapping, $target, $form, $form_state) {
$description = array(
'#theme' => 'item_list',
'#items' => array(
t('Rename: files whose name is already in use are renamed.'),
t('Replace: files on the site with the same name are replaced.'),
t('Replace only if different: files on the site with the same name are replaced only if the file to import is different, in other cases the file will not be imported. Works only if the file to import is locally accessible.'),
t('Rename only if different: files on the site with the same name are renamed only if the file to import is different, in other cases the file will not be imported. Works only if the file to import is locally accessible.'),
t('Skip existing: files whose name is already in use are not imported.'),
),
);
return array(
'file_exists' => array(
'#type' => 'select',
'#title' => t('Replacement method'),
'#default_value' => !empty($mapping['file_exists']) ? $mapping['file_exists'] : FILE_EXISTS_RENAME,
'#options' => array(
FILE_EXISTS_RENAME => t('Rename'),
FILE_EXISTS_REPLACE => t('Replace'),
FEEDS_FILE_EXISTS_REPLACE_DIFFERENT => t('Replace only if different'),
FEEDS_FILE_EXISTS_RENAME_DIFFERENT => t('Rename only if different'),
FEEDS_FILE_EXISTS_SKIP => t('Skip existing'),
),
'#description' => t('New files are always copied. Files that have a name that is already in use on the site are handled based on this setting.') . drupal_render($description) . t('Note that this setting has no effect when using the File (Field) Paths module.'),
),
);
}
/**
* Compares two files to determine if they are the same.
*
* @param string $file1
* The path to the first file to compare.
*
* @param string $file2
* The path to the second file to compare.
*
* @return bool
* TRUE if the files are the same.
* FALSE otherwise.
*/
function file_feeds_file_compare($file1, $file2) {
// If the file size is different then assume they are different files.
// However, remote files may return FALSE from filesize() so only compare
// file sizes if both values are not empty.
$filesize1 = filesize($file1);
$filesize2 = filesize($file2);
if ($filesize1 !== FALSE && $filesize2 !== FALSE && $filesize1 !== $filesize2) {
return FALSE;
}
// File sizes are the same so check md5 hash of files.
if (md5_file($file1) != md5_file($file2)) {
return FALSE;
}
return TRUE;
}
......@@ -299,9 +299,9 @@ class FeedsEnclosure extends FeedsElement {
*
* @param string
*/
protected $mime_type;
protected $mime_type;
/**
/**
* The default list of allowed extensions.
*
* @param string
......@@ -443,31 +443,35 @@ class FeedsEnclosure extends FeedsElement {
/**
* Get a Drupal file object of the enclosed resource, download if necessary.
*
* @param $destination
* @param string $destination
* The path or uri specifying the target directory in which the file is
* expected. Don't use trailing slashes unless it's a streamwrapper scheme.
* @param int $replace
* Replace behavior when the destination file already exists.
* @see file_save_data()
*
* @return
* A Drupal temporary file object of the enclosed resource.
* @return stdClass|FALSE
* A Drupal temporary file object of the enclosed resource or FALSE if the
* value is empty.
*
* @throws Exception
* If file object could not be created.
*/
public function getFile($destination) {
$file = NULL;
public function getFile($destination, $replace = FILE_EXISTS_RENAME) {
$file = FALSE;
if ($this->getValue()) {
// Prepare destination directory.
file_prepare_directory($destination, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY);
// Copy or save file depending on whether it is remote or local.
if (drupal_realpath($this->getSanitizedUri())) {
$file = new stdClass();
$file->uid = 0;
$file->uri = $this->getSanitizedUri();
$file = new stdClass();
$file->uid = 0;
$file->uri = $this->getSanitizedUri();
$file->filemime = $this->getMIMEType();
$file->filename = $this->getSafeFilename();
if (drupal_dirname($file->uri) !== $destination) {
$file = file_copy($file, $destination);
$file = file_copy($file, $destination, $replace);
}
else {
// If file is not to be copied, check whether file already exists,
......@@ -476,6 +480,9 @@ class FeedsEnclosure extends FeedsElement {
$existing_files = file_load_multiple(array(), array('uri' => $file->uri));
if (count($existing_files)) {
$existing = reset($existing_files);
if ($replace == FEEDS_FILE_EXISTS_SKIP) {
return $existing;
}
$file->fid = $existing->fid;
$file->filename = $existing->filename;
}
......@@ -494,7 +501,7 @@ class FeedsEnclosure extends FeedsElement {
$filename = transliteration_clean_filename($filename);
}
$file = file_save_data($this->getContent(), $destination . $filename);
$file = file_save_data($this->getContent(), $destination . $filename, $replace);
}
catch (Exception $e) {
watchdog_exception('Feeds', $e, nl2br(check_plain($e)));
......
......@@ -591,12 +591,23 @@ class FeedsWebTestCase extends DrupalWebTestCase {
/**
* Copies a directory.
*
* @param string $source
* The path of the source directory, from which files should be copied.
* @param string $dest
* The path of the destination directory, where files should be copied to.
* @param array $mapping
* (optional) The files to rename in the process.
* To skip files from being copied, map filename to FALSE.
*/
public function copyDir($source, $dest) {
public function copyDir($source, $dest, array $mapping = array()) {
$result = file_prepare_directory($dest, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
foreach (@scandir($source) as $file) {
if (is_file("$source/$file")) {
$file = file_unmanaged_copy("$source/$file", "$dest/$file");
$new_name = isset($mapping[$file]) ? $mapping[$file] : $file;
if ($new_name !== FALSE) {
$file = file_unmanaged_copy("$source/$file", "$dest/$new_name");
}
}
}
}
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment