diff --git a/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php b/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php index 4759146..53d0e73 100644 --- a/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php +++ b/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php @@ -53,6 +53,7 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi $configuration += array( 'move' => FALSE, 'rename' => FALSE, + 'reuse' => FALSE, ); parent::__construct($configuration, $plugin_id, $plugin_definition); $this->streamWrapperManager = $stream_wrappers; @@ -130,8 +131,13 @@ protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLA if ($this->configuration['move']) { return file_unmanaged_move($source, $destination, $replace); } + // Check if there is a destination available for copying. If there isn't, + // it already exists at the destination and the replace flag tells us to not + // replace it. In that case, return the original destination. + if (!($final_destination = file_destination($destination, $replace))) { + return $destination; + } // We can't use file_unmanaged_copy because it will break with remote Urls. - $final_destination = file_destination($destination, $replace); if (@copy($source, $final_destination)) { return $final_destination; } @@ -142,13 +148,17 @@ protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLA * Determines how to handle file conflicts. * * @return int - * Either FILE_EXISTS_REPLACE (default) or FILE_EXISTS_RENAME, depending - * on the current configuration. + * FILE_EXISTS_REPLACE (default) FILE_EXISTS_RENAME, or FILE_EXISTS_ERROR + * depending on the current configuration. */ protected function getOverwriteMode() { if (!empty($this->configuration['rename'])) { return FILE_EXISTS_RENAME; } + if (!empty($this->configuration['reuse'])) { + return FILE_EXISTS_ERROR; + } + return FILE_EXISTS_REPLACE; } diff --git a/core/modules/migrate/tests/src/Kernel/process/CopyFileTest.php b/core/modules/migrate/tests/src/Kernel/process/CopyFileTest.php index 288ebfb..1a249bb 100644 --- a/core/modules/migrate/tests/src/Kernel/process/CopyFileTest.php +++ b/core/modules/migrate/tests/src/Kernel/process/CopyFileTest.php @@ -2,10 +2,12 @@ namespace Drupal\Tests\migrate\Kernel\process; +use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\StreamWrapperInterface; +use Drupal\Core\StreamWrapper\TemporaryStream; use Drupal\KernelTests\Core\File\FileTestBase; -use Drupal\migrate\Plugin\migrate\process\FileCopy; use Drupal\migrate\MigrateExecutableInterface; +use Drupal\migrate\Plugin\migrate\process\FileCopy; use Drupal\migrate\Row; /** @@ -71,6 +73,32 @@ public function testSuccessfulCopies() { } /** + * Test successful file reuse. + */ + public function testSuccessfulReuse() { + $source_path = $this->root . '/core/modules/simpletest/files/image-test.jpg'; + $destination_path = 'public://file1.jpg'; + $file_reuse = file_unmanaged_copy($source_path, $destination_path); + $timestamp = (new \SplFileInfo($file_reuse))->getMTime(); + $this->assertInternalType('int', $timestamp); + + // We need to make sure the modified timestamp on the file is sooner than + // the attempted migration. + sleep(1); + $configuration = ['reuse' => TRUE]; + $this->doImport($source_path, $destination_path, $configuration); + clearstatcache(TRUE, $destination_path); + $modified_timestamp = (new \SplFileInfo($destination_path))->getMTime(); + $this->assertEquals($timestamp, $modified_timestamp); + + $configuration = ['reuse' => FALSE]; + $this->doImport($source_path, $destination_path, $configuration); + clearstatcache(TRUE, $destination_path); + $modified_timestamp = (new \SplFileInfo($destination_path))->getMTime(); + $this->assertGreaterThan($timestamp, $modified_timestamp); + } + + /** * Test successful moves. */ public function testSuccessfulMoves() {