TermDevelGenerate.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. namespace Drupal\devel_generate\Plugin\DevelGenerate;
  3. use Drupal\Core\Entity\EntityStorageInterface;
  4. use Drupal\Core\Form\FormStateInterface;
  5. use Drupal\Core\Language\Language;
  6. use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
  7. use Drupal\devel_generate\DevelGenerateBase;
  8. use Symfony\Component\DependencyInjection\ContainerInterface;
  9. /**
  10. * Provides a TermDevelGenerate plugin.
  11. *
  12. * @DevelGenerate(
  13. * id = "term",
  14. * label = @Translation("terms"),
  15. * description = @Translation("Generate a given number of terms. Optionally delete current terms."),
  16. * url = "term",
  17. * permission = "administer devel_generate",
  18. * settings = {
  19. * "num" = 10,
  20. * "title_length" = 12,
  21. * "kill" = FALSE,
  22. * }
  23. * )
  24. */
  25. class TermDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
  26. /**
  27. * The vocabulary storage.
  28. *
  29. * @var \Drupal\Core\Entity\EntityStorageInterface
  30. */
  31. protected $vocabularyStorage;
  32. /**
  33. * The term storage.
  34. *
  35. * @var \Drupal\Core\Entity\EntityStorageInterface
  36. */
  37. protected $termStorage;
  38. /**
  39. * Constructs a new TermDevelGenerate object.
  40. *
  41. * @param array $configuration
  42. * A configuration array containing information about the plugin instance.
  43. * @param string $plugin_id
  44. * The plugin_id for the plugin instance.
  45. * @param mixed $plugin_definition
  46. * The plugin implementation definition.
  47. * @param \Drupal\Core\Entity\EntityStorageInterface $vocabulary_storage
  48. * The vocabulary storage.
  49. * @param \Drupal\Core\Entity\EntityStorageInterface $term_storage
  50. * The term storage.
  51. */
  52. public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $vocabulary_storage, EntityStorageInterface $term_storage) {
  53. parent::__construct($configuration, $plugin_id, $plugin_definition);
  54. $this->vocabularyStorage = $vocabulary_storage;
  55. $this->termStorage = $term_storage;
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
  61. $entity_manager = $container->get('entity.manager');
  62. return new static(
  63. $configuration, $plugin_id, $plugin_definition,
  64. $entity_manager->getStorage('taxonomy_vocabulary'),
  65. $entity_manager->getStorage('taxonomy_term')
  66. );
  67. }
  68. /**
  69. * {@inheritdoc}
  70. */
  71. public function settingsForm(array $form, FormStateInterface $form_state) {
  72. $options = array();
  73. foreach ($this->vocabularyStorage->loadMultiple() as $vocabulary) {
  74. $options[$vocabulary->id()] = $vocabulary->label();
  75. }
  76. $form['vids'] = array(
  77. '#type' => 'select',
  78. '#multiple' => TRUE,
  79. '#title' => $this->t('Vocabularies'),
  80. '#required' => TRUE,
  81. '#default_value' => 'tags',
  82. '#options' => $options,
  83. '#description' => $this->t('Restrict terms to these vocabularies.'),
  84. );
  85. $form['num'] = array(
  86. '#type' => 'number',
  87. '#title' => $this->t('Number of terms?'),
  88. '#default_value' => $this->getSetting('num'),
  89. '#required' => TRUE,
  90. '#min' => 0,
  91. );
  92. $form['title_length'] = array(
  93. '#type' => 'number',
  94. '#title' => $this->t('Maximum number of characters in term names'),
  95. '#default_value' => $this->getSetting('title_length'),
  96. '#required' => TRUE,
  97. '#min' => 2,
  98. '#max' => 255,
  99. );
  100. $form['kill'] = array(
  101. '#type' => 'checkbox',
  102. '#title' => $this->t('Delete existing terms in specified vocabularies before generating new terms.'),
  103. '#default_value' => $this->getSetting('kill'),
  104. );
  105. return $form;
  106. }
  107. /**
  108. * {@inheritdoc}
  109. */
  110. public function generateElements(array $values) {
  111. if ($values['kill']) {
  112. $this->deleteVocabularyTerms($values['vids']);
  113. $this->setMessage($this->t('Deleted existing terms.'));
  114. }
  115. $vocabs = $this->vocabularyStorage->loadMultiple($values['vids']);
  116. $new_terms = $this->generateTerms($values['num'], $vocabs, $values['title_length']);
  117. if (!empty($new_terms)) {
  118. $this->setMessage($this->t('Created the following new terms: @terms', array('@terms' => implode(', ', $new_terms))));
  119. }
  120. }
  121. /**
  122. * Deletes all terms of given vocabularies.
  123. *
  124. * @param array $vids
  125. * Array of vocabulary vid.
  126. */
  127. protected function deleteVocabularyTerms($vids) {
  128. $tids = $this->vocabularyStorage->getToplevelTids($vids);
  129. $terms = $this->termStorage->loadMultiple($tids);
  130. $this->termStorage->delete($terms);
  131. }
  132. /**
  133. * Generates taxonomy terms for a list of given vocabularies.
  134. *
  135. * @param int $records
  136. * Number of terms to create in total.
  137. * @param \Drupal\taxonomy\TermInterface[] $vocabs
  138. * List of vocabularies to populate.
  139. * @param int $maxlength
  140. * (optional) Maximum length per term.
  141. *
  142. * @return array
  143. * The list of names of the created terms.
  144. */
  145. protected function generateTerms($records, $vocabs, $maxlength = 12) {
  146. $terms = array();
  147. // Insert new data:
  148. $max = db_query('SELECT MAX(tid) FROM {taxonomy_term_data}')->fetchField();
  149. $start = time();
  150. for ($i = 1; $i <= $records; $i++) {
  151. $name = $this->getRandom()->word(mt_rand(2, $maxlength));
  152. $values = array(
  153. 'name' => $name,
  154. 'description' => 'description of ' . $name,
  155. 'format' => filter_fallback_format(),
  156. 'weight' => mt_rand(0, 10),
  157. 'langcode' => Language::LANGCODE_NOT_SPECIFIED,
  158. );
  159. switch ($i % 2) {
  160. case 1:
  161. $vocab = $vocabs[array_rand($vocabs)];
  162. $values['vid'] = $vocab->id();
  163. $values['parent'] = array(0);
  164. break;
  165. default:
  166. while (TRUE) {
  167. // Keep trying to find a random parent.
  168. $candidate = mt_rand(1, $max);
  169. $query = db_select('taxonomy_term_data', 't');
  170. $parent = $query
  171. ->fields('t', array('tid', 'vid'))
  172. ->condition('t.vid', array_keys($vocabs), 'IN')
  173. ->condition('t.tid', $candidate, '>=')
  174. ->range(0, 1)
  175. ->execute()
  176. ->fetchAssoc();
  177. if ($parent['tid']) {
  178. break;
  179. }
  180. }
  181. $values['parent'] = array($parent['tid']);
  182. // Slight speedup due to this property being set.
  183. $values['vid'] = $parent['vid'];
  184. break;
  185. }
  186. $term = $this->termStorage->create($values);
  187. // Populate all fields with sample values.
  188. $this->populateFields($term);
  189. $term->save();
  190. $max++;
  191. if (function_exists('drush_log')) {
  192. $feedback = drush_get_option('feedback', 1000);
  193. if ($i % $feedback == 0) {
  194. $now = time();
  195. drush_log(dt('Completed @feedback terms (@rate terms/min)', array('@feedback' => $feedback, '@rate' => $feedback * 60 / ($now - $start))), 'ok');
  196. $start = $now;
  197. }
  198. }
  199. // Limit memory usage. Only report first 20 created terms.
  200. if ($i < 20) {
  201. $terms[] = $term->label();
  202. }
  203. unset($term);
  204. }
  205. return $terms;
  206. }
  207. /**
  208. * {@inheritdoc}
  209. */
  210. public function validateDrushParams($args) {
  211. $vocabulary_name = array_shift($args);
  212. $number = array_shift($args);
  213. if ($number === NULL) {
  214. $number = 10;
  215. }
  216. if (!$vocabulary_name) {
  217. return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Please provide a vocabulary machine name.'));
  218. }
  219. if (!$this->isNumber($number)) {
  220. return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of terms: @num', array('@num' => $number)));
  221. }
  222. // Try to convert machine name to a vocabulary id.
  223. if (!$vocabulary = $this->vocabularyStorage->load($vocabulary_name)) {
  224. return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid vocabulary name: @name', array('@name' => $vocabulary_name)));
  225. }
  226. $values = [
  227. 'num' => $number,
  228. 'kill' => drush_get_option('kill'),
  229. 'title_length' => 12,
  230. 'vids' => [$vocabulary->id()],
  231. ];
  232. return $values;
  233. }
  234. }