При работе с migration API в друпал, в документации предполагается, что вы задаёте файл в секции source как значение path. (Подразумевается, что вы используете модуль migrate_source_csv).
Хотелось бы делать это через интерфейс, а не конфигурационные файлы. Т.е. идеальный процесс такой, что пользователь выбирает файл через форму миграции, запускается процесс миграции и пользователь видит этот процесс как стандартную batch — обработка в Drupal (аналогично тому как, например, выглядит загрузка переводов при установке модуля).
Всё это можно устроить и делается небольшими усилиями, т.к. batch процесс уже является частью миграции, а сами миграции — это расширение над ConfigEntityBase и работать с ними довольно легко из кода.
Cоздадим форму /src/Form/MigrationCSV.php, которая позволит выбрать файл и запустить миграцию данных из CSV файла.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
<?php namespace Drupal\custom_migration\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\migrate\MigrateMessage; use Drupal\migrate_plus\Entity\Migration; use Drupal\migrate_tools\MigrateBatchExecutable; /** * @see \Drupal\Core\Form\FormBase */ class MigrationCSV extends FormBase { /** * */ public function buildForm(array $form, FormStateInterface $form_state) { $form['file'] = [ '#type' => 'file', '#title' => $this->t('Import file'), '#attributes' => ['accept' => 'csv'], ]; // Import action. $form['actions']['start_import'] = [ '#type' => 'submit', '#value' => $this->t('Start import'), '#submit' => ['::startImport'], ]; return $form; } /** * */ public function getFormId() { return 'migration_csv_file'; } /** * */ public function startImport(array &$form, FormStateInterface $form_state) { $filefield_name = 'file'; $all_files = \Drupal::request()->files; $file = $all_files->get('files')[$filefield_name]; if ($file && $file->isValid()) { $migration_id = 'MIGRATION_ID'; $obj_migration = Migration::load($migration_id); if ($obj_migration) { @\Drupal::service('file_system') ->mkdir("public://migrations", 0777, TRUE); if ($drupalFile = file_save_upload( 'file', ['file_validate_extensions' => ['csv']], 'public://migrations', 0) ) { // обновить настройки миграции $source = $obj_migration->get('source'); $source['path'] = trim($drupalFile->createFileUrl(), '/'); $obj_migration->set('source', $source); $obj_migration->save(); $options = [ 'limit' => 0, 'update' => 1, 'force' => 0, ]; // Запуск batch процесса. $migrationPlugin = \Drupal::service('plugin.manager.migration') ->createInstance($migration_id); $executable = new MigrateBatchExecutable($migrationPlugin, new MigrateMessage(), $options); $executable->batchImport(); } } } } /** * @inherited. */ public function submitForm(array &$form, FormStateInterface $form_state) { } } |
Я сразу привел весь код файла, т.к. форма очень проста и единственное интересное место — это то, так подставить файл, указанный пользователем в конфигурацию миграции.
MIGRATION_ID — это машинное имя вашей миграции. Если миграция происходит в несколько этапов (есть дочерние миграции), то файл нужно подставить во все конфигурации миграции, использующие его.
Т.к. миграция происходит в виде batch процесса, то CSV файл нужно где то сохранить. Функция file_save_upload позволяет переместить файл в public папку, при этом он получает статус temporary (временный). Нам этого достаточно, чтобы успешно прошла миграция. А через несколько часов (обычно 8 часов) файл будет удален сборщиком мусора Drupal.