根据字段创建分类,并建立关联或修复关联

<?php

/**
 * Class ReferenceCreator.
 *
 * Create terms by one of  a content type's field value, and establish entity reference relationship to another field
 *  in the same bundle with term.
 */
class ReferenceCreator {

  /**
   * @var string
   * The bundle name.
   */
  private $content_type;

  /**
   * @var string Data source field.
   */
  private $tmp_field_name;

  /**
   * @var string Taxonomy name.
   */
  private $vid;

  /**
   * @var string The entity reference filed in the node bundle.
   */
  private $entity_reference_field;

  /**
   * @var array Cache array.
   */
  private $terms = [];

  /**
   * Init args.
   *
   * @param $content_type
   * @param $tmp_field_name
   * @param $vid
   * @param $entity_reference_field
   */
  public function init($content_type, $tmp_field_name, $vid, $entity_reference_field) {
    $this->content_type = $content_type;
    $this->tmp_field_name = $tmp_field_name;
    $this->vid = $vid;
    $this->entity_reference_field = $entity_reference_field;
  }

  public function run() {

    $storage = \Drupal::entityManager()->getStorage('node');
    $query = $storage->getQuery();
    $query->condition('type', $this->content_type);
    $result = $query->execute();
    $total = count($result);
    $i = 0;

    foreach ($result as $nid) {
      $node = $storage->load($nid);
      $i++;
      if (!empty($node->{$this->tmp_field_name}->value)) {
        $name = $node->{$this->tmp_field_name}->value;
        $tid = $this->getTid($name);
        $node->{$this->entity_reference_field}->target_id = $tid;
        $node->save();
      }

      drush_print("Processing $i / $total");

    }

  }

  /**
   * Fix ; seperated data source's reference.
   */
  public function fix() {
    $storage = \Drupal::entityManager()->getStorage('node');
    $query = $storage->getQuery();
    $query->condition('type', $this->content_type);
    $result = $query->execute();
    $total = count($result);
    $i = 0;

    foreach ($result as $nid) {
      $node = $storage->load($nid);
      $i++;
      if (!empty($node->{$this->tmp_field_name}->value)) {
        $name = $node->{$this->tmp_field_name}->value;
        $names = explode(";", $name);
        if (count($names) > 1) {
          drush_print($name . "needed to be fixed.");
          $tid = $this->getTid($name);
          $this->deleteTerm($tid);
          foreach ($names as $index => $value) {
            $tid = $this->getTid($value);
            $node->{$this->entity_reference_field}[$index]->target_id = $tid;
          }
          $node->save();
        }
      }

      drush_print("Processing $i / $total");
    }
  }

  /**
   * Find the exists tid, or create new one, then return the newly created tid.
   *
   * @param $name
   * @return int|null|string
   */
  private function getTid($name) {
    if (isset($this->terms[$this->vid][$name])) {
      return $this->terms[$this->vid][$name];
    }
    else {
      $properties = [
        'name' => $name,
        'vid' => $this->vid,
      ];

      $storage = \Drupal::entityManager()->getStorage('taxonomy_term');
      $terms = $storage->loadByProperties($properties);
      $term = NULL;
      if (empty($terms)) {
        $term = $storage->create(array('name' => $name, 'vid' => $this->vid));
        $term->save();
      }
      else {
        $term = reset($terms);
      }

      $tid = $term->id();
      $this->terms[$this->vid][$name] = $tid;
      return $tid;
    }
  }

  /**
   * Delete the wrong term.
   *
   * @param $tid
   */
  private function deleteTerm($tid) {
    $storage = \Drupal::entityManager()->getStorage('taxonomy_term');
    $term = $storage->load($tid);
    $term->delete();

    drush_print($tid . " (tid) was deleted");

  }

}