Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 130 |
EntityFile | |
0.00% |
0 / 1 |
|
0.00% |
0 / 11 |
1122 | |
0.00% |
0 / 130 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 11 |
|||
create | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 14 |
|||
getEntity | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 12 |
|||
import | |
0.00% |
0 / 1 |
72 | |
0.00% |
0 / 30 |
|||
writeFile | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 9 |
|||
getOverwriteMode | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 8 |
|||
getDirectory | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 8 |
|||
isLocationUnchanged | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 7 |
|||
isLocalUri | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
urlencode | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 12 |
|||
processStubRow | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 16 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\file\Plugin\migrate\destination\EntityFile. | |
*/ | |
namespace Drupal\file\Plugin\migrate\destination; | |
use Drupal\Component\Utility\Unicode; | |
use Drupal\Core\Entity\EntityManagerInterface; | |
use Drupal\Core\Entity\EntityStorageInterface; | |
use Drupal\Core\Field\FieldTypePluginManagerInterface; | |
use Drupal\Core\Field\Plugin\Field\FieldType\UriItem; | |
use Drupal\Core\File\FileSystemInterface; | |
use Drupal\Core\StreamWrapper\LocalStream; | |
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; | |
use Drupal\migrate\Entity\MigrationInterface; | |
use Drupal\migrate\Row; | |
use Drupal\migrate\MigrateException; | |
use Drupal\migrate\Plugin\migrate\destination\EntityContentBase; | |
use Symfony\Component\DependencyInjection\ContainerInterface; | |
/** | |
* Every migration that uses this destination must have an optional | |
* dependency on the d6_file migration to ensure it runs first. | |
* | |
* @MigrateDestination( | |
* id = "entity:file" | |
* ) | |
*/ | |
class EntityFile extends EntityContentBase { | |
/** | |
* @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface | |
*/ | |
protected $streamWrapperManager; | |
/** | |
* @var \Drupal\Core\File\FileSystemInterface | |
*/ | |
protected $fileSystem; | |
/** | |
* {@inheritdoc} | |
*/ | |
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) { | |
$configuration += array( | |
'source_base_path' => '', | |
'source_path_property' => 'filepath', | |
'destination_path_property' => 'uri', | |
'move' => FALSE, | |
'urlencode' => FALSE, | |
); | |
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager); | |
$this->streamWrapperManager = $stream_wrappers; | |
$this->fileSystem = $file_system; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) { | |
$entity_type = static::getEntityTypeId($plugin_id); | |
return new static( | |
$configuration, | |
$plugin_id, | |
$plugin_definition, | |
$migration, | |
$container->get('entity.manager')->getStorage($entity_type), | |
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)), | |
$container->get('entity.manager'), | |
$container->get('plugin.manager.field.field_type'), | |
$container->get('stream_wrapper_manager'), | |
$container->get('file_system') | |
); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
protected function getEntity(Row $row, array $old_destination_id_values) { | |
// For stub rows, there is no real file to deal with, let the stubbing | |
// process take its default path. | |
if ($row->isStub()) { | |
return parent::getEntity($row, $old_destination_id_values); | |
} | |
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']); | |
$entity = $this->storage->loadByProperties(['uri' => $destination]); | |
if ($entity) { | |
return reset($entity); | |
} | |
else { | |
return parent::getEntity($row, $old_destination_id_values); | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function import(Row $row, array $old_destination_id_values = array()) { | |
// For stub rows, there is no real file to deal with, let the stubbing | |
// process create the stub entity. | |
if ($row->isStub()) { | |
return parent::import($row, $old_destination_id_values); | |
} | |
$file = $row->getSourceProperty($this->configuration['source_path_property']); | |
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']); | |
$source = $this->configuration['source_base_path'] . $file; | |
// Ensure the source file exists, if it's a local URI or path. | |
if ($this->isLocalUri($source) && !file_exists($source)) { | |
throw new MigrateException("File '$source' does not exist."); | |
} | |
// If the start and end file is exactly the same, there is nothing to do. | |
if ($this->isLocationUnchanged($source, $destination)) { | |
return parent::import($row, $old_destination_id_values); | |
} | |
$replace = $this->getOverwriteMode($row); | |
$success = $this->writeFile($source, $destination, $replace); | |
if (!$success) { | |
$dir = $this->getDirectory($destination); | |
if (file_prepare_directory($dir, FILE_CREATE_DIRECTORY)) { | |
$success = $this->writeFile($source, $destination, $replace); | |
} | |
else { | |
throw new MigrateException("Could not create directory '$dir'"); | |
} | |
} | |
if ($success) { | |
return parent::import($row, $old_destination_id_values); | |
} | |
else { | |
throw new MigrateException("File $source could not be copied to $destination."); | |
} | |
} | |
/** | |
* Tries to move or copy a file. | |
* | |
* @param string $source | |
* The source path or URI. | |
* @param string $destination | |
* The destination path or URI. | |
* @param int $replace | |
* (optional) FILE_EXISTS_REPLACE (default) or FILE_EXISTS_RENAME. | |
* | |
* @return bool | |
* TRUE on success, FALSE on failure. | |
*/ | |
protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLACE) { | |
if ($this->configuration['move']) { | |
return (boolean) file_unmanaged_move($source, $destination, $replace); | |
} | |
else { | |
$destination = file_destination($destination, $replace); | |
$source = $this->urlencode($source); | |
return @copy($source, $destination); | |
} | |
} | |
/** | |
* Determines how to handle file conflicts. | |
* | |
* @param \Drupal\migrate\Row $row | |
* | |
* @return int | |
* Either FILE_EXISTS_REPLACE (default) or FILE_EXISTS_RENAME, depending | |
* on the current configuration. | |
*/ | |
protected function getOverwriteMode(Row $row) { | |
if (!empty($this->configuration['rename'])) { | |
$entity_id = $row->getDestinationProperty($this->getKey('id')); | |
if ($entity_id && ($entity = $this->storage->load($entity_id))) { | |
return FILE_EXISTS_RENAME; | |
} | |
} | |
return FILE_EXISTS_REPLACE; | |
} | |
/** | |
* Returns the directory component of a URI or path. | |
* | |
* For URIs like public://foo.txt, the full physical path of public:// | |
* will be returned, since a scheme by itself will trip up certain file | |
* API functions (such as file_prepare_directory()). | |
* | |
* @param string $uri | |
* The URI or path. | |
* | |
* @return string|false | |
* The directory component of the path or URI, or FALSE if it could not | |
* be determined. | |
*/ | |
protected function getDirectory($uri) { | |
$dir = $this->fileSystem->dirname($uri); | |
if (substr($dir, -3) == '://') { | |
return $this->fileSystem->realpath($dir); | |
} | |
else { | |
return $dir; | |
} | |
} | |
/** | |
* Returns if the source and destination URIs represent identical paths. | |
* If either URI is a remote stream, will return FALSE. | |
* | |
* @param string $source | |
* The source URI. | |
* @param string $destination | |
* The destination URI. | |
* | |
* @return bool | |
* TRUE if the source and destination URIs refer to the same physical path, | |
* otherwise FALSE. | |
*/ | |
protected function isLocationUnchanged($source, $destination) { | |
if ($this->isLocalUri($source) && $this->isLocalUri($destination)) { | |
return $this->fileSystem->realpath($source) === $this->fileSystem->realpath($destination); | |
} | |
else { | |
return FALSE; | |
} | |
} | |
/** | |
* Returns if the given URI or path is considered local. | |
* | |
* A URI or path is considered local if it either has no scheme component, | |
* or the scheme is implemented by a stream wrapper which extends | |
* \Drupal\Core\StreamWrapper\LocalStream. | |
* | |
* @param string $uri | |
* The URI or path to test. | |
* | |
* @return bool | |
*/ | |
protected function isLocalUri($uri) { | |
$scheme = $this->fileSystem->uriScheme($uri); | |
return $scheme === FALSE || $this->streamWrapperManager->getViaScheme($scheme) instanceof LocalStream; | |
} | |
/** | |
* Urlencode all the components of a remote filename. | |
* | |
* @param string $filename | |
* The filename of the file to be urlencoded. | |
* | |
* @return string | |
* The urlencoded filename. | |
*/ | |
protected function urlencode($filename) { | |
// Only apply to a full URL | |
if ($this->configuration['urlencode'] && strpos($filename, '://')) { | |
$components = explode('/', $filename); | |
foreach ($components as $key => $component) { | |
$components[$key] = rawurlencode($component); | |
} | |
$filename = implode('/', $components); | |
// Actually, we don't want certain characters encoded | |
$filename = str_replace('%3A', ':', $filename); | |
$filename = str_replace('%3F', '?', $filename); | |
$filename = str_replace('%26', '&', $filename); | |
} | |
return $filename; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
protected function processStubRow(Row $row) { | |
// We stub the uri value ourselves so we can create a real stub file for it. | |
if (!$row->getDestinationProperty('uri')) { | |
$field_definitions = $this->entityManager | |
->getFieldDefinitions($this->storage->getEntityTypeId(), | |
$this->getKey('bundle')); | |
$value = UriItem::generateSampleValue($field_definitions['uri']); | |
if (empty($value)) { | |
throw new MigrateException('Stubbing failed, unable to generate value for field uri'); | |
} | |
// generateSampleValue() wraps the value in an array. | |
$value = reset($value); | |
// Make it into a proper public file uri, stripping off the existing | |
// scheme if present. | |
$value = 'public://' . preg_replace('|^[a-z]+://|i', '', $value); | |
$value = Unicode::substr($value, 0, $field_definitions['uri']->getSetting('max_length')); | |
// Create a real file, so File::preSave() can do filesize() on it. | |
touch($value); | |
$row->setDestinationProperty('uri', $value); | |
} | |
parent::processStubRow($row); | |
} | |
} |