improvements-2.x-dev/src/Plugin/migrate/process/D7FileFieldCopy.php
src/Plugin/migrate/process/D7FileFieldCopy.php
<?php
namespace Drupal\improvements\Plugin\migrate\process;
use Drupal\Core\Database\Connection;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\migrate\process\FileCopy;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
/**
* @code
* source:
* plugin: d7_taxonomy_term # Any plugin implements FieldableEntity
* constants:
* source_base_path: '/path/to/old/site' # Required
* source_public_path: 'sites/default/files' # Required
* process:
* field_file_destination:
* plugin: d7_file_field_copy
* source: field_field_source
* destination_file_directory: 'images'
* destination:
* plugin: entity:taxonomy_term
* @endcode
*
* @MigrateProcessPlugin(
* id = "d7_file_field_copy"
* )
*/
class D7FileFieldCopy extends ProcessPluginBase {
protected MigrationInterface $migration;
protected FieldableEntity $source;
protected Connection $sourceDatabase;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migration = $migration;
$this->source = $migration->getSourcePlugin();
$this->sourceDatabase = $this->source->getDatabase();
}
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (!$value || (!isset($value['fid']) && !isset($value['target_id']))) {
throw new MigrateSkipProcessException('$value does not contain fid property');
}
$fid = $value['fid'] ?? ($value['target_id'] ?? NULL);
if (!$fid || !($source_file_info = $this->getSourceFileInfo($fid))) {
throw new MigrateSkipProcessException('File with fid ' . $fid . ' does not exist');
}
$source_base_path = rtrim($row->getSourceProperty('constants/source_base_path'), '/'); // Eg "/path/to/old/site"
$source_public_path = trim($row->getSourceProperty('constants/source_public_path'), '/'); // Eg "sites/default/files"
$source_file_fullpath = str_replace('public://', $source_base_path . '/' . $source_public_path . '/', $source_file_info['uri']); // Eg "/path/to/old/site/sites/default/files/example.jpg"
// @TODO Use field setting "file_directory"
$destination_file_directory = trim($this->configuration['destination_file_directory'] ?? '', '/'); // Eg "images"
// @TODO Use tokens without hardcoded file name
$destination_file_uri = 'public://' . $destination_file_directory . '/o' . $fid . '.' . $source_file_info['extension']; // Eg "public://images/o123.jpg"
if ($destination_file_uri = $this->copyFile($source_file_fullpath, $destination_file_uri, $migrate_executable, $row, $destination_property)) {
$destination_file = $this->loadFileByUri($destination_file_uri) ?: File::create([
'uri' => $destination_file_uri,
'filename' => $source_file_info['filename'],
]);
return ['entity' => $destination_file];
}
}
/**
* Return source file info.
*/
protected function getSourceFileInfo($fid): array {
$file_info = $this->sourceDatabase->select('file_managed', 'f')
->fields('f', ['filename', 'uri'])
->condition('f.fid', $fid)
->execute()
->fetchAssoc();
$file_info['extension'] = pathinfo($file_info['filename'])['extension'];
return $file_info;
}
/**
* Load file entity by uri.
*/
protected function loadFileByUri($file_uri): ?FileInterface {
if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $file_uri])) {
return current($files);
}
return NULL;
}
/**
* Copy file and return destination path.
*
* @return string|FALSE
*/
protected function copyFile($source_file_fullpath, $destination_file_uri, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$file_copy_configuration = $this->configuration + ['file_exists' => 'use existing'];
/** @var FileCopy $file_copy_plugin */
$file_copy_plugin = \Drupal::service('plugin.manager.migrate.process')->createInstance('file_copy', $file_copy_configuration);
return $file_copy_plugin->transform([$source_file_fullpath, $destination_file_uri], $migrate_executable, $row, $destination_property);
}
}
