Мне нужен был обработчик для migration API, который создаёт media entity по URL и возвращает его ID.
Обработчики представляют из себя расширения ProcessPluginBase, которые нужно размещать в папке /src/Plugin/migrate/process вашего модуля.
Файл /src/Plugin/migrate/process/MediaGenerate.php
Т.к. media сущность настраивается разработчиком, то в качестве параметров нужно указать bundle сущности (destination_bundle) и поле (destination_field), в которое будет записываться file reference. Ещё один параметр — это подкаталог pubic://, куда будет записана картинка — public_dir.
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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
<?php namespace Drupal\custom_migration\Plugin\migrate\process; use Drupal\Core\File\FileSystemInterface; use Drupal\media\Entity\Media; use Drupal\migrate\MigrateException; use Drupal\migrate\MigrateExecutableInterface; use Drupal\migrate\ProcessPluginBase; use Drupal\migrate\Row; /** * Generates a media entity from a file and returns the media id. * * @MigrateProcessPlugin( * id = "media_generate" * ) * * To generate the entity it is best to this in a subprocess: * * @code * process: * field_blog_image/target_id: * source: thumbnail * plugin: media_generate * destination_bundle: image * destination_field: field_media_image * public_dir: test-public * @endcode */ class MediaGenerate extends ProcessPluginBase { /** * {@inheritdoc} */ public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { if (!isset($this->configuration['destination_field'])) { throw new MigrateException('Destination field must be set.'); } if (!isset($this->configuration['destination_bundle'])) { throw new MigrateException('Destination bundle must be set.'); } $field = $this->configuration['destination_field']; $bundle = $this->configuration['destination_bundle']; $imageContent = FALSE; if (!empty($value)) { $destinationDir = 'public://' . ($this->configuration['public_dir'] ?? 'migration_uploads'); $destinationFile = $destinationDir . '/' . basename(parse_url($value, PHP_URL_PATH)); // Prepare FILE. $files = \Drupal::entityTypeManager() ->getStorage('file') ->loadByProperties(['uri' => $destinationFile]); $file = reset($files) ?: NULL; if ($file === NULL) { try { $imageContent = file_get_contents($value); } catch (\Exception $e) { return NULL; } \Drupal::service('file_system') ->prepareDirectory( $destinationDir, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS ); $file = \Drupal::service('file.repository') ->writeData($imageContent, $destinationDir . '/' . basename($value), FileSystemInterface::EXISTS_REPLACE); } // Prepare MEDIA. $query = \Drupal::entityTypeManager()->getStorage('media')->getQuery(); $query->condition('status', 1) ->condition($field, $file->id()) ->accessCheck(FALSE); $mids = $query->execute(); $mid = reset($mids) ?: NULL; if ($mid === NULL) { $alt = $row->getSourceProperty('alt'); if (empty($alt)) { $alt = "Media Name: " . $file->label(); } $media = Media::create([ 'bundle' => $bundle, 'uid' => $file->getOwner()->id(), 'status' => '1', 'name' => $file->label(), $field => [ 'target_id' => $file->id(), 'alt' => $alt, ], ]); $media->save(); return $media->id(); } else { return $mid; } } return NULL; } } |
Логика работы следующая: сначала определяется место, куда будет записан файл, если такой файл уже есть в Drupal, то повторно его копировать не будем. Далее идет поиск/создание media entity. Если media элемент, указывающий на файл уже есть — вернем его ID, если нет, то создаём и получаем ID нового media entity.
Пример использования:
1 2 3 4 5 6 7 |
process: field_blog_image/target_id: source: thumbnail plugin: media_generate destination_bundle: image destination_field: field_media_image public_dir: test-public |