123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- <?php
- namespace Drupal\devel_generate\Plugin\DevelGenerate;
- use Drupal\Component\Utility\Unicode;
- use Drupal\Core\Entity\EntityStorageInterface;
- use Drupal\Core\Extension\ModuleHandlerInterface;
- use Drupal\Core\Form\FormStateInterface;
- use Drupal\Core\Menu\MenuLinkTreeInterface;
- use Drupal\Core\Menu\MenuTreeParameters;
- use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
- use Drupal\devel_generate\DevelGenerateBase;
- use Symfony\Component\DependencyInjection\ContainerInterface;
- /**
- * Provides a MenuDevelGenerate plugin.
- *
- * @DevelGenerate(
- * id = "menu",
- * label = @Translation("menus"),
- * description = @Translation("Generate a given number of menus and menu links. Optionally delete current menus."),
- * url = "menu",
- * permission = "administer devel_generate",
- * settings = {
- * "num_menus" = 2,
- * "num_links" = 50,
- * "title_length" = 12,
- * "max_width" = 6,
- * "kill" = FALSE,
- * }
- * )
- */
- class MenuDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
- /**
- * The menu tree service.
- *
- * @var \Drupal\Core\Menu\MenuLinkTreeInterface
- */
- protected $menuLinkTree;
- /**
- * The menu storage.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface
- */
- protected $menuStorage;
- /**
- * The menu link storage.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface
- */
- protected $menuLinkContentStorage;
- /**
- * The module handler.
- *
- * @var \Drupal\Core\Extension\ModuleHandlerInterface
- */
- protected $moduleHandler;
- /**
- * Constructs a MenuDevelGenerate object.
- *
- * @param array $configuration
- * A configuration array containing information about the plugin instance.
- * @param string $plugin_id
- * The plugin ID for the plugin instance.
- * @param mixed $plugin_definition
- * The plugin implementation definition.
- * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
- * The menu tree service.
- * @param \Drupal\Core\Entity\EntityStorageInterface $menu_storage
- * The menu storage.
- * @param \Drupal\Core\Entity\EntityStorageInterface $menu_link_storage
- * The menu storage.
- * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
- * The module handler.
- */
- public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, EntityStorageInterface $menu_storage, EntityStorageInterface $menu_link_storage, ModuleHandlerInterface $module_handler) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
- $this->menuLinkTree = $menu_tree;
- $this->menuStorage = $menu_storage;
- $this->menuLinkContentStorage = $menu_link_storage;
- $this->moduleHandler = $module_handler;
- }
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
- $entity_manager = $container->get('entity.manager');
- return new static(
- $configuration, $plugin_id, $plugin_definition,
- $container->get('menu.link_tree'),
- $entity_manager->getStorage('menu'),
- $entity_manager->getStorage('menu_link_content'),
- $container->get('module_handler')
- );
- }
- /**
- * {@inheritdoc}
- */
- public function settingsForm(array $form, FormStateInterface $form_state) {
- $menu_enabled = $this->moduleHandler->moduleExists('menu_ui');
- if ($menu_enabled) {
- $menus = array('__new-menu__' => $this->t('Create new menu(s)')) + menu_ui_get_menus();
- }
- else {
- $menus = menu_list_system_menus();
- }
- $form['existing_menus'] = array(
- '#type' => 'checkboxes',
- '#title' => $this->t('Generate links for these menus'),
- '#options' => $menus,
- '#default_value' => array('__new-menu__'),
- '#required' => TRUE,
- );
- if ($menu_enabled) {
- $form['num_menus'] = array(
- '#type' => 'number',
- '#title' => $this->t('Number of new menus to create'),
- '#default_value' => $this->getSetting('num_menus'),
- '#min' => 0,
- '#states' => array(
- 'visible' => array(
- ':input[name="existing_menus[__new-menu__]"]' => array('checked' => TRUE),
- ),
- ),
- );
- }
- $form['num_links'] = array(
- '#type' => 'number',
- '#title' => $this->t('Number of links to generate'),
- '#default_value' => $this->getSetting('num_links'),
- '#required' => TRUE,
- '#min' => 0,
- );
- $form['title_length'] = array(
- '#type' => 'number',
- '#title' => $this->t('Maximum number of characters in menu and menu link names'),
- '#description' => $this->t('The minimum length is 2.'),
- '#default_value' => $this->getSetting('title_length'),
- '#required' => TRUE,
- '#min' => 2,
- '#max' => 128,
- );
- $form['link_types'] = array(
- '#type' => 'checkboxes',
- '#title' => $this->t('Types of links to generate'),
- '#options' => array(
- 'node' => $this->t('Nodes'),
- 'front' => $this->t('Front page'),
- 'external' => $this->t('External'),
- ),
- '#default_value' => array('node', 'front', 'external'),
- '#required' => TRUE,
- );
- $form['max_depth'] = array(
- '#type' => 'select',
- '#title' => $this->t('Maximum link depth'),
- '#options' => range(0, $this->menuLinkTree->maxDepth()),
- '#default_value' => floor($this->menuLinkTree->maxDepth() / 2),
- '#required' => TRUE,
- );
- unset($form['max_depth']['#options'][0]);
- $form['max_width'] = array(
- '#type' => 'number',
- '#title' => $this->t('Maximum menu width'),
- '#default_value' => $this->getSetting('max_width'),
- '#description' => $this->t('Limit the width of the generated menu\'s first level of links to a certain number of items.'),
- '#required' => TRUE,
- '#min' => 0,
- );
- $form['kill'] = array(
- '#type' => 'checkbox',
- '#title' => $this->t('Delete existing custom generated menus and menu links before generating new ones.'),
- '#default_value' => $this->getSetting('kill'),
- );
- return $form;
- }
- /**
- * {@inheritdoc}
- */
- public function generateElements(array $values) {
- // If the create new menus checkbox is off, set the number of new menus to 0.
- if (!isset($values['existing_menus']['__new-menu__']) || !$values['existing_menus']['__new-menu__']) {
- $values['num_menus'] = 0;
- }
- else {
- // Unset the aux menu to avoid attach menu new items.
- unset($values['existing_menus']['__new-menu__']);
- }
- // Delete custom menus.
- if ($values['kill']) {
- $this->deleteMenus();
- $this->setMessage($this->t('Deleted existing menus and links.'));
- }
- // Generate new menus.
- $new_menus = $this->generateMenus($values['num_menus'], $values['title_length']);
- if (!empty($new_menus)) {
- $this->setMessage($this->t('Created the following new menus: @menus', array('@menus' => implode(', ', $new_menus))));
- }
- // Generate new menu links.
- $menus = $new_menus;
- if (isset($values['existing_menus'])) {
- $menus = $menus + $values['existing_menus'];
- }
- $new_links = $this->generateLinks($values['num_links'], $menus, $values['title_length'], $values['link_types'], $values['max_depth'], $values['max_width']);
- $this->setMessage($this->t('Created @count new menu links.', array('@count' => count($new_links))));
- }
- /**
- * {@inheritdoc}
- */
- public function validateDrushParams($args) {
- $link_types = array('node', 'front', 'external');
- $values = array(
- 'num_menus' => array_shift($args),
- 'num_links' => array_shift($args),
- 'kill' => drush_get_option('kill'),
- 'pipe' => drush_get_option('pipe'),
- 'link_types' => array_combine($link_types, $link_types),
- );
- $max_depth = array_shift($args);
- $max_width = array_shift($args);
- $values['max_depth'] = $max_depth ? $max_depth : 3;
- $values['max_width'] = $max_width ? $max_width : 8;
- $values['title_length'] = $this->getSetting('title_length');
- $values['existing_menus']['__new-menu__'] = TRUE;
- if ($this->isNumber($values['num_menus']) == FALSE) {
- return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of menus'));
- }
- if ($this->isNumber($values['num_links']) == FALSE) {
- return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of links'));
- }
- if ($this->isNumber($values['max_depth']) == FALSE || $values['max_depth'] > 9 || $values['max_depth'] < 1) {
- return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid maximum link depth. Use a value between 1 and 9'));
- }
- if ($this->isNumber($values['max_width']) == FALSE || $values['max_width'] < 1) {
- return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid maximum menu width. Use a positive numeric value.'));
- }
- return $values;
- }
- /**
- * Deletes custom generated menus.
- */
- protected function deleteMenus() {
- if ($this->moduleHandler->moduleExists('menu_ui')) {
- $menu_ids = array();
- foreach (menu_ui_get_menus(FALSE) as $menu => $menu_title) {
- if (strpos($menu, 'devel-') === 0) {
- $menu_ids[] = $menu;
- }
- }
- if ($menu_ids) {
- $menus = $this->menuStorage->loadMultiple($menu_ids);
- $this->menuStorage->delete($menus);
- }
- }
- // Delete menu links generated by devel.
- $link_ids = $this->menuLinkContentStorage->getQuery()
- ->condition('menu_name', 'devel', '<>')
- ->condition('link__options', '%' . db_like('s:5:"devel";b:1') . '%', 'LIKE')
- ->execute();
- if ($link_ids) {
- $links = $this->menuLinkContentStorage->loadMultiple($link_ids);
- $this->menuLinkContentStorage->delete($links);
- }
- }
- /**
- * Generates new menus.
- *
- * @param int $num_menus
- * Number of menus to create.
- * @param int $title_length
- * (optional) Maximum length per menu name.
- *
- * @return array
- * Array containing the generated vocabularies id.
- */
- protected function generateMenus($num_menus, $title_length = 12) {
- $menus = array();
- if ($this->moduleHandler->moduleExists('menu_ui')) {
- for ($i = 1; $i <= $num_menus; $i++) {
- $name = $this->getRandom()->word(mt_rand(2, max(2, $title_length)));
- $menu = $this->menuStorage->create(array(
- 'label' => $name,
- 'id' => 'devel-' . Unicode::strtolower($name),
- 'description' => $this->t('Description of @name', array('@name' => $name)),
- ));
- $menu->save();
- $menus[$menu->id()] = $menu->label();
- }
- }
- return $menus;
- }
- /**
- * Generates menu links in a tree structure.
- */
- protected function generateLinks($num_links, $menus, $title_length, $link_types, $max_depth, $max_width) {
- $links = array();
- $menus = array_keys(array_filter($menus));
- $link_types = array_keys(array_filter($link_types));
- $nids = array();
- for ($i = 1; $i <= $num_links; $i++) {
- // Pick a random menu.
- $menu_name = $menus[array_rand($menus)];
- // Build up our link.
- $link_title = $this->getRandom()->word(mt_rand(2, max(2, $title_length)));
- $link = $this->menuLinkContentStorage->create(array(
- 'menu_name' => $menu_name,
- 'weight' => mt_rand(-50, 50),
- 'title' => $link_title,
- 'bundle' => 'menu_link_content',
- 'description' => $this->t('Description of @title.', array('@title' => $link_title)),
- ));
- $link->link->options = array('devel' => TRUE);
- // For the first $max_width items, make first level links.
- if ($i <= $max_width) {
- $depth = 0;
- }
- else {
- // Otherwise, get a random parent menu depth.
- $depth = mt_rand(1, max(1, $max_depth - 1));
- }
- // Get a random parent link from the proper depth.
- do {
- $parameters = new MenuTreeParameters();
- $parameters->setMinDepth($depth);
- $parameters->setMaxDepth($depth);
- $tree = $this->menuLinkTree->load($menu_name, $parameters);
- if ($tree) {
- $link->parent = array_rand($tree);
- }
- $depth--;
- } while (!$link->parent && $depth > 0);
- $link_type = array_rand($link_types);
- switch ($link_types[$link_type]) {
- case 'node':
- // Grab a random node ID.
- $select = db_select('node_field_data', 'n')
- ->fields('n', array('nid', 'title'))
- ->condition('n.status', 1)
- ->range(0, 1)
- ->orderRandom();
- // Don't put a node into the menu twice.
- if (!empty($nids[$menu_name])) {
- $select->condition('n.nid', $nids[$menu_name], 'NOT IN');
- }
- $node = $select->execute()->fetchAssoc();
- if (isset($node['nid'])) {
- $nids[$menu_name][] = $node['nid'];
- $link->link->uri = 'entity:node/' . $node['nid'];
- $link->title = $node['title'];
- break;
- }
- case 'external':
- $link->link->uri = 'http://www.example.com/';
- break;
- case 'front':
- $link->link->uri = 'internal:/<front>';
- break;
- default:
- $link->devel_link_type = $link_type;
- break;
- }
- $link->save();
- $links[$link->id()] = $link->link_title;
- }
- return $links;
- }
- }
|