function TermDevelGenerate::generateTerms

Same name and namespace in other branches
  1. 4.x devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php \Drupal\devel_generate\Plugin\DevelGenerate\TermDevelGenerate::generateTerms()

Generates taxonomy terms for a list of given vocabularies.

Parameters

array $parameters: The input parameters from the settings form or drush command.

Return value

array Information about the created terms.

1 call to TermDevelGenerate::generateTerms()
TermDevelGenerate::generateElements in devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php
Business logic relating with each DevelGenerate plugin.

File

devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php, line 222

Class

TermDevelGenerate
Provides a TermDevelGenerate plugin.

Namespace

Drupal\devel_generate\Plugin\DevelGenerate

Code

protected function generateTerms(array $parameters) : array {
  $info = [
    'terms' => 0,
    'terms_translations' => 0,
  ];
  $min_depth = $parameters['minimum_depth'];
  $max_depth = $parameters['maximum_depth'];
  // $parameters['vids'] from the UI has keys of the vocab ids. From drush
  // the array is keyed 0,1,2. Therefore create $vocabs which has keys of the
  // vocab ids, so it can be used with array_rand().
  $vocabs = array_combine($parameters['vids'], $parameters['vids']);
  // Delete terms from the vocabularies we are creating new terms in.
  if ($parameters['kill']) {
    $deleted = $this->deleteVocabularyTerms($vocabs);
    $this->setMessage($this->formatPlural($deleted, 'Deleted 1 existing term', 'Deleted @count existing terms'));
    if ($min_depth != 1) {
      $this->setMessage($this->t('Minimum depth changed from @min_depth to 1 because all terms were deleted', [
        '@min_depth' => $min_depth,
      ]));
      $min_depth = 1;
    }
  }
  // Build an array of potential parents for the new terms. These will be
  // terms in the vocabularies we are creating in, which have a depth of one
  // less than the minimum for new terms up to one less than the maximum.
  $all_parents = [];
  foreach ($parameters['vids'] as $vid) {
    $info['vocabs'][$vid] = $this->vocabularyStorage
      ->load($vid)
      ->label();
    // Initialise the nested array for this vocabulary.
    $all_parents[$vid] = [
      'top_level' => [],
      'lower_levels' => [],
    ];
    $ids = [];
    for ($depth = 1; $depth < $max_depth; ++$depth) {
      $query = $this->termStorage
        ->getQuery()
        ->accessCheck(FALSE)
        ->condition('vid', $vid);
      if ($depth == 1) {
        // For the top level the parent id must be zero.
        $query->condition('parent', 0);
      }
      else {
        // For lower levels use the $ids array obtained in the previous loop.
        $query->condition('parent', $ids, 'IN');
      }
      $ids = $query->execute();
      if (empty($ids)) {
        // Reached the end, no more parents to be found.
        break;

      }
      // Store these terms as parents if they are within the depth range for
      // new terms.
      if ($depth == $min_depth - 1) {
        $all_parents[$vid]['top_level'] = array_fill_keys($ids, $depth);
      }
      elseif ($depth >= $min_depth) {
        $all_parents[$vid]['lower_levels'] += array_fill_keys($ids, $depth);
      }
    }
    // No top-level parents will have been found above when the minimum depth
    // is 1 so add a record for that data here.
    if ($min_depth == 1) {
      $all_parents[$vid]['top_level'] = [
        0 => 0,
      ];
    }
    elseif (empty($all_parents[$vid]['top_level'])) {
      // No parents for required minimum level so cannot use this vocabulary.
      unset($vocabs[$vid]);
    }
  }
  if ($vocabs === []) {
    // There are no available parents at the required depth in any vocabulary,
    // so we cannot create any new terms.
    throw new \Exception(sprintf('Invalid minimum depth %s because there are no terms in any vocabulary at depth %s', $min_depth, $min_depth - 1));
  }
  // Insert new data:
  for ($i = 1; $i <= $parameters['num']; ++$i) {
    // Select a vocabulary at random.
    $vid = array_rand($vocabs);
    // Set the group to use to select a random parent from. Using < 50 means
    // on average half of the new terms will be top_level. Also if no terms
    // exist yet in 'lower_levels' then we have to use 'top_level'.
    $group = mt_rand(0, 100) < 50 || empty($all_parents[$vid]['lower_levels']) ? 'top_level' : 'lower_levels';
    $parent = array_rand($all_parents[$vid][$group]);
    $depth = $all_parents[$vid][$group][$parent] + 1;
    $name = $this->getRandom()
      ->word(mt_rand(2, $parameters['title_length']));
    $values = [
      'name' => $name,
      'description' => 'Description of ' . $name . ' (depth ' . $depth . ')',
      'format' => filter_fallback_format(),
      'weight' => mt_rand(0, 10),
      'vid' => $vid,
      'parent' => [
        $parent,
      ],
      // Give hook implementations access to the parameters used for generation.
'devel_generate' => $parameters,
    ];
    if (isset($parameters['add_language'])) {
      $values['langcode'] = $this->getLangcode($parameters['add_language']);
    }
    /** @var \Drupal\taxonomy\TermInterface $term */
    $term = $this->termStorage
      ->create($values);
    // Populate all fields with sample values.
    $this->populateFields($term);
    $term->save();
    // Add translations.
    if (isset($parameters['translate_language']) && !empty($parameters['translate_language'])) {
      $info['terms_translations'] += $this->generateTermTranslation($parameters['translate_language'], $term);
    }
    // If the depth of the new term is less than the maximum depth then it can
    // also be saved as a potential parent for the subsequent new terms.
    if ($depth < $max_depth) {
      $all_parents[$vid]['lower_levels'] += [
        $term->id() => $depth,
      ];
    }
    // Store data about the newly generated term.
    ++$info['terms'];
    @$info[$vid][$depth]['total']++;
    // List only the first 10 new terms at each vocab/level.
    if (!isset($info[$vid][$depth]['terms']) || count($info[$vid][$depth]['terms']) < 10) {
      $info[$vid][$depth]['terms'][] = $term->label();
    }
    unset($term);
  }
  return $info;
}