function TermDevelGenerate::generateTerms

Same name in other branches
  1. 5.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 258

Class

TermDevelGenerate
Provides a TermDevelGenerate plugin.

Namespace

Drupal\devel_generate\Plugin\DevelGenerate

Code

protected function generateTerms(array $parameters) {
    $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' => [],
        ];
        for ($depth = 1; $depth < $max_depth; $depth++) {
            $query = \Drupal::entityQuery('taxonomy_term')->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.
                // phpcs:ignore DrupalPractice.CodeAnalysis.VariableAnalysis.UndefinedVariable
                $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 (empty($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,
            ],
        ];
        if (isset($parameters['add_language'])) {
            $values['langcode'] = $this->getLangcode($parameters['add_language']);
        }
        $term = $this->termStorage
            ->create($values);
        // Give hook implementations access to the parameters used for generation.
        $term->devel_generate = $parameters;
        // 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;
}