diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityFile.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityFile.php
index b338fba64f8..77b471f115d 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityFile.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityFile.php
@@ -50,6 +50,11 @@ class EntityFile extends EntityContentBase {
// already absolute.
$source = $this->isTempFile($destination) ? $file : $this->configuration['source_base_path'] . $file;
+ $dirname = drupal_dirname($destination);
+ if (!file_prepare_directory($dirname, FILE_CREATE_DIRECTORY)) {
+ throw new MigrateException(t('Could not create directory %dirname', array('%dirname' => $dirname)));
+ }
+
// If the start and end file is exactly the same, there is nothing to do.
if (drupal_realpath($source) === drupal_realpath($destination)) {
return parent::import($row, $old_destination_id_values);
@@ -62,11 +67,7 @@ class EntityFile extends EntityContentBase {
$replace = FILE_EXISTS_RENAME;
}
}
- $dirname = drupal_dirname($destination);
- if (!file_prepare_directory($dirname, FILE_CREATE_DIRECTORY)) {
- throw new MigrateException(t('Could not create directory %dirname',
- array('%dirname' => $dirname)));
- }
+
if ($this->configuration['move']) {
$copied = file_unmanaged_move($source, $destination, $replace);
}
@@ -78,7 +79,7 @@ class EntityFile extends EntityContentBase {
throw new MigrateException(t('File %file could not be copied because a file by that name already exists in the destination directory (%destination)', array('%file' => $source, '%destination' => $original_destination)));
}
$source = $this->urlencode($source);
- $copied = copy($source, $destination);
+ $copied = @copy($source, $destination);
}
if ($copied) {
return parent::import($row, $old_destination_id_values);
diff --git a/core/modules/migrate/tests/src/Unit/destination/EntityFileTest.php b/core/modules/migrate/tests/src/Unit/destination/EntityFileTest.php
new file mode 100644
index 00000000000..731c722da07
--- /dev/null
+++ b/core/modules/migrate/tests/src/Unit/destination/EntityFileTest.php
@@ -0,0 +1,160 @@
+destination = new TestEntityFile([]);
+
+ $this->installConfig(['system']);
+ file_put_contents('/tmp/test-file.jpg', '');
+ }
+
+ /**
+ * Test successful imports/copies.
+ */
+ public function testSuccessfulCopies() {
+ foreach ($this->localFileDataProvider() as $data) {
+ list($row_values, $destination_path, $expected, $source_base_path) = $data;
+
+ $this->doImport($row_values, $destination_path, $source_base_path);
+ $message = $expected ? sprintf('File %s exists', $destination_path) : sprintf('File %s does not exist', $destination_path);
+ $this->assertIdentical($expected, is_file($destination_path), $message);
+ }
+ }
+
+ /**
+ * The data provider for testing the file destination.
+ *
+ * @return array
+ * An array of file permutations to test.
+ */
+ protected function localFileDataProvider() {
+ global $base_url;
+ return [
+ // Test a local to local copy.
+ [['filepath' => 'core/modules/simpletest/files/image-test.jpg'], 'public://file1.jpg', TRUE, DRUPAL_ROOT . '/'],
+ // Test a temporary file using an absolute path.
+ [['filepath' => '/tmp/test-file.jpg'], 'temporary://test.jpg', TRUE, ''],
+ // Test a remote path to local.
+ [['filepath' => 'core/modules/simpletest/files/image-test.jpg'], 'public://remote-file.jpg', TRUE, $base_url . '/'],
+ // Test a remote path to local inside a folder that doesn't exist.
+ [['filepath' => 'core/modules/simpletest/files/image-test.jpg'], 'public://folder/remote-file.jpg', TRUE, DRUPAL_ROOT . '/'],
+ ];
+ }
+
+
+ /**
+ * Test that non-existent files throw an exception.
+ */
+ public function testNonExistentSourceFile() {
+ try {
+ $this->doImport(['filepath' => '/none/existent/file'], 'public://wontmatter.jpg');
+ }
+ catch (MigrateException $e) {}
+ $destination = '/none/existent/file';
+ $this->assertIdentical($e->getMessage(), 'File ' . $destination . ' could not be copied to public://wontmatter.jpg.');
+ }
+
+ /**
+ * Do an import using the destination.
+ *
+ * @param array $row_values
+ * An array of row values.
+ * @param string $destination_path
+ * The destination path to copy to.
+ * @param string $source_base_path
+ * The source base path.
+ * @return array
+ * An array of saved entities ids.
+ *
+ * @throws \Drupal\migrate\MigrateException
+ */
+ protected function doImport($row_values, $destination_path, $source_base_path = '') {
+ $row = new Row($row_values, []);
+ $row->setDestinationProperty('uri', $destination_path);
+ $this->destination->configuration['source_base_path'] = $source_base_path;
+
+ // Importing asserts there are no errors, then we just check the file has
+ // been copied into place.
+ return $this->destination->import($row, array());
+ }
+
+}
+
+class TestEntityFile extends EntityFile {
+
+ /**
+ * This is needed to be passed to $this->save().
+ *
+ * @var \Drupal\Core\Entity\ContentEntityInterface
+ */
+ public $mockEntity;
+
+ /**
+ * Make this public for easy writing during tests.
+ *
+ * @var array
+ */
+ public $configuration;
+
+ public function __construct($configuration) {
+ $configuration += array(
+ 'source_base_path' => '',
+ 'source_path_property' => 'filepath',
+ 'destination_path_property' => 'uri',
+ 'move' => FALSE,
+ 'urlencode' => FALSE,
+ );
+ $this->configuration = $configuration;
+ // We need a mock entity to be passed to save to prevent strict exceptions.
+ $this->mockEntity = EntityTest::create();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getEntity(Row $row, array $old_destination_id_values) {
+ return $this->mockEntity;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) {}
+
+}