Термины представляют из себя отдельные сущности, которые подключаются к родительской entity в виде term reference. Потому классический подход — это отдельная предварительная миграция терминов, а потом подключение их, используя migration_lookup плагин.
Но на практике, вы скорее всего будет иметь термины в виде текстовых меток. И вам удобнее будет обработать их «на лету», без дополнительной отдельной миграции.
Именно для этого я и написал небольшой миграционный обработчик, который преобразует текстовую метку в ссылку на термин (создаёт или находит существующий).
Вот код этого process plugin:
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 |
<?php // у меня он был в составе моего // модуля миграции custom_migration namespace Drupal\custom_migration\Plugin\migrate\process; use Drupal\migrate\MigrateException; use Drupal\migrate\MigrateExecutableInterface; use Drupal\migrate\ProcessPluginBase; use Drupal\migrate\Row; use Drupal\taxonomy\Entity\Term; /** * Generates a term entity from a Term Name and returns the term id. * * @MigrateProcessPlugin( * id = "term_generate" * ) * * To generate the entity it is best to this in a subprocess: * * @code * process: * field_blog_category/target_id: * source: category_name * plugin: term_generate * destination_bundle: content_tags * @endcode */ class TermGenerate extends ProcessPluginBase { /** * {@inheritdoc} */ public function transform( $value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { if (!isset($this->configuration['destination_bundle'])) { throw new MigrateException('Destination bundle must be set.'); } $vid = $this->configuration['destination_bundle']; $value = trim($value ?? ''); $result = NULL; if (!empty($value)) { // Prepare TERM. $query = \Drupal::entityTypeManager() ->getStorage('taxonomy_term') ->getQuery(); $query->condition('status', 1) ->condition('name', $value) ->condition('vid', $vid) ->accessCheck(FALSE); $tids = $query->execute(); $tid = reset($tids) ?: NULL; if ($tid === NULL) { $term = Term::create([ 'vid' => $vid, 'status' => '1', 'name' => $value, ]); $term->save(); $result = $term->id(); } else { $result = $tid; } } return ['target_id' => $result]; } } |
Он принимает $value (метку термина) и возвращает массив [‘target_id’ => TERMID].
В настройках можно указать в какой словарь должен попадать термин (destination_bundle).
Примеры использования в миграции:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
process: field_blog_category: source: category plugin: term_generate destination_bundle: blog_category field_blog_tag: - plugin: explode source: tags delimiter: ',' - plugin: term_generate destination_bundle: blog_tags |
В первом случае (field_blog_category) читается одиночный термин категории (category). Во втором — (field_blog_tag) список тегов, разделенных запятыми. При этом используется т.н. pipeline, где на первом шаге строка разбивается стандартным плагином explode, а дальше каждый термин передаётся в наш процессор term_generate.
Разместите данный плагин в вашем модуле (/src/Plugin/migrate/process), и сбросьте кеш, чтобы Drupal его зарегистрировал.