diff --git a/devel_generate/README.txt b/devel_generate/README.txt new file mode 100755 index 0000000..7527a5b --- /dev/null +++ b/devel_generate/README.txt @@ -0,0 +1,52 @@ +This module creates the "DevelGenerate" plugin type. + +All you need to do to provide a new instance for "DevelGenerate" plugin type +is to create your class extending "DevelGenerateBase" and following the next steps. + +1 - Declaring your plugin with annotations: + +/** + * Provides a ExampleDevelGenerate plugin. + * + * @DevelGenerate( + * id = "example", + * label = @Translation("example"), + * description = @Translation("Generate a given number of example elements. Optionally delete current example elements."), + * url = "example", + * settings = { + * "num" = 50, + * "kill" = FALSE, + * "another_property" = "default_value" + * }, + * drushSettings = { + * "suffix" = "example", + * "alias" = "ex", + * "options" = { + * "kill" = "Delete existing examples", + * "another_drush_option" = "Description", + * }, + * "args" = { + * "num" = "Number of examples to create" + * } + * } + * ) + */ + +2 - Implement "settingsForm" method to create a form using the properties from annotations. + +3 - Implement "handleDrushParams" method. It should return an array of values. + +4 - Implement "generateElements" method. You can write here your business logic +using the array of values. + +Notes: + +You can alter existing properties for every plugin implementing hook_devel_generate_info_alter. + +DevelGenerateBaseInterface details base wrapping methods that most DevelGenerate implementations +will want to directly inherit from Drupal\devel_generate\DevelGenerateBase. + +DevelGenerateFieldBaseInterface details base wrapping methods that most class implementations +for supporting new field types will want to directly inherit from Drupal\devel_generate\DevelGenerateFieldBase. +So to give support for a new field type should be enough to create a class called +"DevelGenerateFieldNewfieldtype" extending DevelGenerateFieldBase and to implement "generateValues" method. diff --git a/devel_generate/devel_generate.drush.inc b/devel_generate/devel_generate.drush.inc index 44aec25..3fd54e5 100755 --- a/devel_generate/devel_generate.drush.inc +++ b/devel_generate/devel_generate.drush.inc @@ -9,7 +9,6 @@ */ function devel_generate_drush_command() { - $devel_generate_manager = \Drupal::service('plugin.manager.develgenerate'); $definitions = \Drupal::service('plugin.manager.develgenerate')->getDefinitions(); foreach ($definitions as $id => $plugin_info) { @@ -23,8 +22,8 @@ function devel_generate_drush_command() { ), 'aliases' => array("gen$alias"), ); - $items["generate-$command_suffix"]['options'] = $plugin_info['drushSettings']; - $items["generate-$command_suffix"]['arguments'] = $plugin_info['drushArgs']; + $items["generate-$command_suffix"]['options'] = $plugin_info['drushSettings']['options']; + $items["generate-$command_suffix"]['arguments'] = $plugin_info['drushSettings']['args']; } return $items; @@ -45,7 +44,6 @@ function drush_devel_generate() { $instance = $devel_generate_manager->createInstance($plugin_id, array()); //Plugin instance suit params in order to fit for generateElements - $values = $instance->getDrushValues($params); - $instance->generateElements($values); - $instance->drushLog($values); + $values = $instance->handleDrushParams($params); + $instance->generate($values); } diff --git a/devel_generate/devel_generate.fields.inc b/devel_generate/devel_generate.fields.inc deleted file mode 100755 index 4005b0a..0000000 --- a/devel_generate/devel_generate.fields.inc +++ /dev/null @@ -1,103 +0,0 @@ -getBundleInstances($entity_type, $bundle_name); - $field_types = \Drupal::service('plugin.manager.field.field_type')->getDefinitions(); - $skips = function_exists('drush_get_option') ? drush_get_option('skip-fields', '') : @$_REQUEST['skip-fields']; - foreach (explode(',', $skips) as $skip) { - unset($instances[$skip]); - } - - foreach ($instances as $instance) { - $field = $instance->getField(); - $cardinality = $field->getFieldCardinality(); - $field_name = $field->getFieldName(); - $object_field = array(); - - // If module handles own multiples, then only call its hook once. - $form_display_options = entity_get_form_display($entity_type, $bundle_name, $form_mode)->getComponent($field_name); - $plugin_definition = \Drupal::service('plugin.manager.field.widget')->getDefinition($form_display_options['type']); - if (isset($plugin_definition['multiple_values']) && $plugin_definition['multiple_values'] === TRUE) { - $max = 0; - } - else { - switch ($cardinality) { - case FieldDefinitionInterface::CARDINALITY_UNLIMITED; - $max = rand(0, 3); //just an arbitrary number for 'unlimited' - break; - default: - $max = $cardinality - 1; - break; - } - } - - for ($i = 0; $i <= $max; $i++) { - $provider = $field_types[$field->type]['provider']; - - // Include any support file that might exist for this field. - if (in_array($provider, array('file', 'image', 'taxonomy', 'number', 'text', 'options', 'email', 'link'))) { - // devel_generate implements on behalf of core and special friends. - module_load_include('inc', 'devel_generate', "$provider.devel_generate"); - } - else { - module_load_include('inc', $provider, "$provider.devel_generate"); - } - $function = $provider . '_devel_generate'; - if (function_exists($function)) { - if ($result = $function($object, $instance, $plugin_definition, $form_display_options)) { - if (isset($plugin_definition['multiple_values']) && $plugin_definition['multiple_values'] === TRUE) { - // Fields that handle their own multiples will add their own deltas. - $object_field = $result; - } - else { - // When multiples are handled by the content module, add a delta for each result. - $object_field[$i] = $result; - } - } - } - } - - $object->{$field_name} = $object_field; - } -} - -/** - * A simple function to return multiple values for fields that use - * custom multiple value widgets but don't need any other special multiple - * values handling. This will call the field generation function - * a random number of times and compile the results into a node array. - */ -function devel_generate_multiple($function, $object, $instance, $plugin_definition, $form_display_options) { - $object_field = array(); - if (function_exists($function)) { - $cardinality = $instance->getFieldCardinality(); - switch ($cardinality) { - case FieldDefinitionInterface::CARDINALITY_UNLIMITED; - $max = rand(0, 3); //just an arbitrary number for 'unlimited' - break; - default: - $max = $cardinality - 1; - break; - } - for ($i = 0; $i <= $max; $i++) { - $result = $function($object, $instance, $plugin_definition, $form_display_options); - if (!empty($result)) { - $object_field[$i] = $result; - } - } - } - return $object_field; -} diff --git a/devel_generate/devel_generate.module b/devel_generate/devel_generate.module index 1d1ecc5..c371c40 100755 --- a/devel_generate/devel_generate.module +++ b/devel_generate/devel_generate.module @@ -13,10 +13,11 @@ function devel_generate_menu() { $devel_generate_plugins = $devel_generate_manager = \Drupal::service('plugin.manager.develgenerate')->getDefinitions(); foreach ($devel_generate_plugins as $id => $plugin) { - $type_url_str = str_replace('_', '-', $id); - $items["admin/config/development/generate/$type_url_str"] = array( - 'title' => "Generate $id", - 'description' => 'Generate a given number of entities.', + $label = $plugin['label']; + $url = $plugin['url']; + $items["admin/config/development/generate/$url"] = array( + 'title' => "Generate $label", + 'description' => $plugin['description'], 'route_name' => "devel_generate.$id", ); } @@ -42,7 +43,7 @@ function devel_generate_node_insert(EntityInterface $node) { $instances = Field::fieldInfo()->getBundleInstances($node->entityType(), $node->bundle()); foreach ($instances as $instance) { $field = $instance->getField(); - if ($field->getFieldType() == 'comment') { + if ($field->getType() == 'comment') { devel_generate_add_comments($node, $field, $results['users'], $results['max_comments'], $results['title_length']); } } @@ -65,19 +66,3 @@ function devel_generate_node_insert(EntityInterface $node) { } } } - -/** - * Set a message for either drush or the web interface. - * - * @param $msg - * The message to display. - * @param $type - * The message type, as defined by drupal_set_message(). - * - * @return - * Context-appropriate message output. - */ -function devel_generate_set_message($msg, $type = 'status') { - $function = function_exists('drush_log') ? 'drush_log' : 'drupal_set_message'; - $function($msg, $type); -} diff --git a/devel_generate/devel_generate.services.yml b/devel_generate/devel_generate.services.yml index 5841c42..ffa6aea 100755 --- a/devel_generate/devel_generate.services.yml +++ b/devel_generate/devel_generate.services.yml @@ -1,7 +1,7 @@ services: plugin.manager.develgenerate: class: Drupal\devel_generate\DevelGeneratePluginManager - arguments: ['@container.namespaces'] + arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler'] develgenerate.subscriber: class: Drupal\devel_generate\Routing\DevelGenerateRouteSubscriber diff --git a/devel_generate/devel_generate_batch.inc b/devel_generate/devel_generate_batch.inc deleted file mode 100755 index 2e90357..0000000 --- a/devel_generate/devel_generate_batch.inc +++ /dev/null @@ -1,68 +0,0 @@ - t('Generating Content'), - 'operations' => $operations, - 'finished' => 'devel_generate_batch_finished', - 'file' => drupal_get_path('module', 'devel_generate') . '/devel_generate_batch.inc', - ); - batch_set($batch); -} - -/** - * Create Content Batch Functions: - */ - -function devel_generate_batch_content_kill(&$context) { - module_load_include('inc', 'devel_generate', 'devel_generate'); - devel_generate_content_kill($context['results']); -} - -function devel_generate_batch_content_pre_node($vars, &$context) { - $context['results'] = $vars; - $context['results']['num_nids'] = 0; - module_load_include('inc', 'devel_generate', 'devel_generate'); - devel_generate_content_pre_node($context['results']); -} - -function devel_generate_batch_content_add_node(&$context) { - module_load_include('inc', 'devel_generate', 'devel_generate'); - devel_generate_content_add_node($context['results']); - $context['results']['num_nids'] ++; -} - -function devel_generate_batch_finished($success, $results, $operations) { - if ($success) { - $message = t('Finished @num_nids nodes created successfully.', array('@num_nids' => $results['num_nids'])); - } - else { - $message = t('Finished with an error.'); - } - drupal_set_message($message); -} - diff --git a/devel_generate/lib/Drupal/devel_generate/Annotation/DevelGenerate.php b/devel_generate/lib/Drupal/devel_generate/Annotation/DevelGenerate.php index 77642d9..4897608 100755 --- a/devel_generate/lib/Drupal/devel_generate/Annotation/DevelGenerate.php +++ b/devel_generate/lib/Drupal/devel_generate/Annotation/DevelGenerate.php @@ -14,7 +14,7 @@ use Drupal\Component\Annotation\Plugin; * * DevelGenerate handle the bulk creation of entites. * - * Additional annotation keys for formatters can be defined in + * Additional annotation keys for DevelGenerate can be defined in * hook_devel_generate_info_alter(). * * @Annotation @@ -32,6 +32,31 @@ class DevelGenerate extends Plugin { public $id; /** + * The human-readable name of the DevelGenerate type. + * + * @ingroup plugin_translatable + * + * @var \Drupal\Core\Annotation\Translation + */ + public $label; + + /** + * A short description of the DevelGenerate type. + * + * @ingroup plugin_translatable + * + * @var \Drupal\Core\Annotation\Translation + */ + public $description; + + /** + * A url to access the plugin settings form. + * + * @var string + */ + public $url; + + /** * The name of the DevelGenerate class. * * This is not provided manually, it will be added by the discovery mechanism. @@ -49,20 +74,11 @@ class DevelGenerate extends Plugin { public $settings = array(); /** - * An array whose keys are the names of the settings available to the - * DevelGenerate drush command. + * An array whose keys are the settings available to the + * DevelGenerate drush command: "suffix", "alias", "options" and "args". * * @var array */ - public $drushSettings = array(); - /** - * An array whose keys are the names of the args available to the - * DevelGenerate drush command. - * - * @var array - */ - public $drushArgs = array(); - } diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateBase.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateBase.php index 896860e..eee0c1e 100755 --- a/devel_generate/lib/Drupal/devel_generate/DevelGenerateBase.php +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateBase.php @@ -14,32 +14,17 @@ abstract class DevelGenerateBase extends PluginBase implements DevelGenerateBase protected $settings = array(); /** - * Whether default settings have been merged into the current $settings. - * - * @var bool - */ - protected $defaultSettingsMerged = FALSE; - - /** * Implements Drupal\devel_generate\DevelGenerateBaseInterface::getSetting(). */ public function getSetting($key) { // Merge defaults if we have no value for the key. - if (!$this->defaultSettingsMerged && !array_key_exists($key, $this->settings)) { - $this->mergeDefaults(); + if (!array_key_exists($key, $this->settings)) { + $this->settings = $this->getDefaultSettings(); } return isset($this->settings[$key]) ? $this->settings[$key] : NULL; } /** - * Merges default settings values into $settings. - */ - protected function mergeDefaults() { - $this->settings += $this->getDefaultSettings(); - $this->defaultSettingsMerged = TRUE; - } - - /** * Implements Drupal\devel_generate\DevelGenerateBaseInterface::getDefaultSettings(). */ public function getDefaultSettings() { @@ -48,6 +33,13 @@ abstract class DevelGenerateBase extends PluginBase implements DevelGenerateBase } /** + * Implements Drupal\devel_generate\DevelGenerateBaseInterface::getSettings(). + */ + public function getSettings() { + return $this->settings; + } + + /** * Implements Drupal\devel_generate\DevelGenerateBaseInterface::settingsForm(). */ public function settingsForm(array $form, array &$form_state) { @@ -59,20 +51,177 @@ abstract class DevelGenerateBase extends PluginBase implements DevelGenerateBase */ public function generate(array $values) { $this->generateElements($values); - drupal_set_message("Generate process complete"); + $this->setMessage("Generate process complete."); + } + + /** + * Business logic relating with each DevelGenerate plugin + * + * @param array $values + * The input values from the settings form. + */ + protected function generateElements(array $values) { + } /** - * Implements Drupal\devel_generate\DevelGenerateBaseInterface::getDrushValues(). + * Implements Drupal\devel_generate\DevelGenerateBaseInterface::handleDrushValues(). */ - public function getDrushValues($args) { + public function handleDrushParams($args) { } /** - * Implements Drupal\devel_generate\DevelGenerateBaseInterface::drushLog(). + * Set a message for either drush or the web interface. + * + * @param $msg + * The message to display. + * @param $type + * The message type, as defined by drupal_set_message(). + * + * @return + * Context-appropriate message output. */ - public function drushLog($values = array()) { + protected function setMessage($msg, $type = 'status') { + $function = function_exists('drush_log') ? 'drush_log' : 'drupal_set_message'; + $function($msg, $type); + } + + /** + * Generates a random string + * @param int $length + * the expected word's length + * + * @Return Boolean + */ + public static function generateWord($length) { + mt_srand((double)microtime()*1000000); + + $vowels = array("a", "e", "i", "o", "u"); + $cons = array("b", "c", "d", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "u", "v", "w", "tr", + "cr", "br", "fr", "th", "dr", "ch", "ph", "wr", "st", "sp", "sw", "pr", "sl", "cl", "sh"); + $num_vowels = count($vowels); + $num_cons = count($cons); + $word = ''; + + while(strlen($word) < $length){ + $word .= $cons[mt_rand(0, $num_cons - 1)] . $vowels[mt_rand(0, $num_vowels - 1)]; + } + + return substr($word, 0, $length); + } + + /** + * Check if a given param is a number + * @Return Boolean + */ + public static function isNumber($number) { + if ($number == NULL) return FALSE; + if (!is_numeric($number)) return FALSE; + return TRUE; + } + + public static function createGreeking($word_count, $title = FALSE) { + $dictionary = array("abbas", "abdo", "abico", "abigo", "abluo", "accumsan", + "acsi", "ad", "adipiscing", "aliquam", "aliquip", "amet", "antehabeo", + "appellatio", "aptent", "at", "augue", "autem", "bene", "blandit", + "brevitas", "caecus", "camur", "capto", "causa", "cogo", "comis", + "commodo", "commoveo", "consectetuer", "consequat", "conventio", "cui", + "damnum", "decet", "defui", "diam", "dignissim", "distineo", "dolor", + "dolore", "dolus", "duis", "ea", "eligo", "elit", "enim", "erat", + "eros", "esca", "esse", "et", "eu", "euismod", "eum", "ex", "exerci", + "exputo", "facilisi", "facilisis", "fere", "feugiat", "gemino", + "genitus", "gilvus", "gravis", "haero", "hendrerit", "hos", "huic", + "humo", "iaceo", "ibidem", "ideo", "ille", "illum", "immitto", + "importunus", "imputo", "in", "incassum", "inhibeo", "interdico", + "iriure", "iusto", "iustum", "jugis", "jumentum", "jus", "laoreet", + "lenis", "letalis", "lobortis", "loquor", "lucidus", "luctus", "ludus", + "luptatum", "macto", "magna", "mauris", "melior", "metuo", "meus", + "minim", "modo", "molior", "mos", "natu", "neo", "neque", "nibh", + "nimis", "nisl", "nobis", "nostrud", "nulla", "nunc", "nutus", "obruo", + "occuro", "odio", "olim", "oppeto", "os", "pagus", "pala", "paratus", + "patria", "paulatim", "pecus", "persto", "pertineo", "plaga", "pneum", + "populus", "praemitto", "praesent", "premo", "probo", "proprius", + "quadrum", "quae", "qui", "quia", "quibus", "quidem", "quidne", "quis", + "ratis", "refero", "refoveo", "roto", "rusticus", "saepius", + "sagaciter", "saluto", "scisco", "secundum", "sed", "si", "similis", + "singularis", "sino", "sit", "sudo", "suscipere", "suscipit", "tamen", + "tation", "te", "tego", "tincidunt", "torqueo", "tum", "turpis", + "typicus", "ulciscor", "ullamcorper", "usitas", "ut", "utinam", + "utrum", "uxor", "valde", "valetudo", "validus", "vel", "velit", + "veniam", "venio", "vereor", "vero", "verto", "vicis", "vindico", + "virtus", "voco", "volutpat", "vulpes", "vulputate", "wisi", "ymo", + "zelus"); + $dictionary_flipped = array_flip($dictionary); + + $greeking = ''; + + if (!$title) { + $words_remaining = $word_count; + while ($words_remaining > 0) { + $sentence_length = mt_rand(3, 10); + $words = array_rand($dictionary_flipped, $sentence_length); + $sentence = implode(' ', $words); + $greeking .= ucfirst($sentence) . '. '; + $words_remaining -= $sentence_length; + } + } + else { + // Use slightly different method for titles. + $words = array_rand($dictionary_flipped, $word_count); + $words = is_array($words) ? implode(' ', $words) : $words; + $greeking = ucwords($words); + } + + // Work around possible php garbage collection bug. Without an unset(), this + // function gets very expensive over many calls (php 5.2.11). + unset($dictionary, $dictionary_flipped); + return trim($greeking); + } + + public static function createContent($type = NULL) { + $nparas = mt_rand(1,12); + $type = empty($type) ? mt_rand(0,3) : $type; + + $output = ""; + switch($type % 3) { + // MW: This appears undesireable. Was giving

in text fields + // case 1: // html + // for ($i = 1; $i <= $nparas; $i++) { + // $output .= devel_create_para(mt_rand(10,60),1); + // } + // break; + // + // case 2: // brs only + // for ($i = 1; $i <= $nparas; $i++) { + // $output .= devel_create_para(mt_rand(10,60),2); + // } + // break; + + default: // plain text + for ($i = 1; $i <= $nparas; $i++) { + $output .= static::createPara(mt_rand(10,60)) ."\n\n"; + } + } + + return $output; + } + +public static function createPara($words, $type = 0) { + $output = ''; + switch ($type) { + case 1: + $output .= "

" . static::createGreeking($words) . "

"; + break; + + case 2: + $output .= static::createGreeking($words) . "
"; + break; + + default: + $output .= static::createGreeking($words); + } + return $output; } } diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateBaseInterface.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateBaseInterface.php index 3bccb4c..a3f9357 100755 --- a/devel_generate/lib/Drupal/devel_generate/DevelGenerateBaseInterface.php +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateBaseInterface.php @@ -26,7 +26,7 @@ interface DevelGenerateBaseInterface extends PluginInspectionInterface { * @return array * The array of settings. */ - public function getSetting($key); + function getSetting($key); /** * Returns the default settings for the plugin. @@ -34,40 +34,37 @@ interface DevelGenerateBaseInterface extends PluginInspectionInterface { * @return array * The array of default setting values, keyed by setting names. */ - public function getDefaultSettings(); + function getDefaultSettings(); /** - * Returns the form for the plugin. + * Returns the current settings for the plugin. * * @return array - * The array of default setting values, keyed by setting names. + * The array of current setting values, keyed by setting names. */ - public function settingsForm(array $form, array &$form_state); + function getSettings(); /** - * Execute the instructions in common for all DevelGenerate plugin + * Returns the form for the plugin. * - * @param array $values - * The input values from the settings form. + * @return array + * The array of default setting values, keyed by setting names. */ - public function generate(array $values); + function settingsForm(array $form, array &$form_state); /** - * Execute the concrete instructions for each DevelGenerate plugin + * Execute the instructions in common for all DevelGenerate plugin * * @param array $values * The input values from the settings form. */ - public function generateElements(array $values); - + function generate(array $values); /** * Responsible for manage Drush settings. + * + * @Return an array of values ready to be used for generateElements() */ - public function getDrushValues($args); + function handleDrushParams($args); - /** - * Responsible for show drush log message. - */ - public function drushLog($values = array()); } diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateException.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateException.php new file mode 100755 index 0000000..f80fe48 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateException.php @@ -0,0 +1,15 @@ +generateMultiple($object, $instance, $plugin_definition, $form_display_options); + } + else { + return $this->generateValues($object, $instance, $plugin_definition, $form_display_options); + } + + } + + /** + * A simple function to return multiple values for fields that use + * custom multiple value widgets but don't need any other special multiple + * values handling. This will call the field generation function + * a random number of times and compile the results into a node array. + */ + protected function generateMultiple($object, $instance, $plugin_definition, $form_display_options) { + + $object_field = array(); + $cardinality = $instance->getCardinality(); + switch ($cardinality) { + case FieldDefinitionInterface::CARDINALITY_UNLIMITED; + $max = rand(0, 3); //just an arbitrary number for 'unlimited' + break; + default: + $max = $cardinality - 1; + break; + } + for ($i = 0; $i <= $max; $i++) { + $result = $this->generateValues($object, $instance, $plugin_definition, $form_display_options); + if (!empty($result)) { + $object_field[$i] = $result; + } + } + return $object_field; + } + + /** + * Enrich the $object that is about to be saved with arbitrary + * information in each of its fields. + */ + public static function generateFields(EntityInterface &$object, $entity_type, $bundle_name, $form_mode = 'default') { + $instances = Field::fieldInfo()->getBundleInstances($entity_type, $bundle_name); + $field_types = \Drupal::service('plugin.manager.field.field_type')->getDefinitions(); + $skips = function_exists('drush_get_option') ? drush_get_option('skip-fields', '') : @$_REQUEST['skip-fields']; + foreach (explode(',', $skips) as $skip) { + unset($instances[$skip]); + } + + foreach ($instances as $instance) { + $field = $instance->getField(); + $cardinality = $field->getCardinality(); + $field_name = $field->getName(); + $object_field = array(); + + // If module handles own multiples, then only call its hook once. + $form_display_options = entity_get_form_display($entity_type, $bundle_name, $form_mode)->getComponent($field_name); + $plugin_definition = \Drupal::service('plugin.manager.field.widget')->getDefinition($form_display_options['type']); + if (isset($plugin_definition['multiple_values']) && $plugin_definition['multiple_values'] === TRUE) { + $max = 0; + } + else { + switch ($cardinality) { + case FieldDefinitionInterface::CARDINALITY_UNLIMITED; + $max = rand(0, 3); //just an arbitrary number for 'unlimited' + break; + default: + $max = $cardinality - 1; + break; + } + } + + for ($i = 0; $i <= $max; $i++) { + + $provider = $field_types[$field->type]['provider']; + $devel_generate_field_factory = new DevelGenerateFieldFactory(); + $devel_generate_field_object = $devel_generate_field_factory->createInstance($provider); + + if ($devel_generate_field_object instanceof DevelGenerateFieldBaseInterface) { + + if ($result = $devel_generate_field_object->generate($object, $instance, $plugin_definition, $form_display_options)) { + + if (isset($plugin_definition['multiple_values']) && $plugin_definition['multiple_values'] === TRUE) { + // Fields that handle their own multiples will add their own deltas. + $object_field = $result; + } + else { + // When multiples are handled by the content module, add a delta for each result. + $object_field[$i] = $result; + } + + } + + } + + } + + $object->{$field_name} = $object_field; + } + } +} \ No newline at end of file diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldBaseInterface.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldBaseInterface.php new file mode 100755 index 0000000..7a7fbc4 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldBaseInterface.php @@ -0,0 +1,34 @@ +getFieldSettings(); + + if (empty($file)) { + if ($path = $this->generateTextFile()) { + $source = new stdClass(); + $source->uri = $path; + $source->uid = 1; // TODO: randomize? use case specific. + $source->filemime = 'text/plain'; + $source->filename = drupal_basename($path); + $destination_dir = $settings['uri_scheme'] . '://' . $settings['file_directory']; + file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY); + $destination = $destination_dir . '/' . basename($path); + $file = file_move($source, $destination, FILE_CREATE_DIRECTORY); + } + else { + return FALSE; + } + } + if (!$file) { + // In case a previous file operation failed or no file is set, return FALSE + return FALSE; + } + else { + $object_field['target_id'] = $file->id(); + $object_field['display'] = $settings['display_default']; + $object_field['description'] = DevelGenerateBase::develCreateGreeking(10); + + return $object_field; + } + } + + /** + * Private function for generating a random text file. + */ + private function generateTextFile($filesize = 1024) { + if ($tmp_file = drupal_tempnam('temporary://', 'filefield_')) { + $destination = $tmp_file . '.txt'; + file_unmanaged_move($tmp_file, $destination); + + $fp = fopen($destination, 'w'); + fwrite($fp, str_repeat('01', $filesize/2)); + fclose($fp); + + return $destination; + } + } +} diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldImage.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldImage.php new file mode 100755 index 0000000..6314146 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldImage.php @@ -0,0 +1,88 @@ +getSettings(); + + $min_resolution = empty($settings['min_resolution']) ? '100x100' : $settings['min_resolution']; + $max_resolution = empty($settings['max_resolution']) ? '600x600' : $settings['max_resolution']; + $extensions = array_intersect(explode(' ', $settings['file_extensions']), array('png', 'gif', 'jpg', 'jpeg')); + $extension = array_rand(drupal_map_assoc($extensions)); + // Generate a max of 5 different images. + if (!isset($images[$extension][$min_resolution][$max_resolution]) || count($images[$extension][$min_resolution][$max_resolution]) <= DEVEL_GENERATE_IMAGE_MAX) { + if ($path = $this->generateImage($extension, $min_resolution, $max_resolution)) { + $account = user_load(1); + $image = entity_create('file', array()); + $image->setFileUri($path); + $image->setOwner($account); + $image->setMimeType('image/' . pathinfo($path, PATHINFO_EXTENSION)); + $image->setFileName(drupal_basename($path)); + $destination_dir = $settings['uri_scheme'] . '://' . $settings['file_directory']; + file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY); + $destination = $destination_dir . '/' . basename($path); + $file = file_move($image, $destination, FILE_CREATE_DIRECTORY); + $images[$extension][$min_resolution][$max_resolution][$file->id()] = $file; + } + else { + return FALSE; + } + } + else { + // Select one of the images we've already generated for this field. + $image_index = array_rand($images[$extension][$min_resolution][$max_resolution]); + $file = $images[$extension][$min_resolution][$max_resolution][$image_index]; + } + + $object_field['target_id'] = $file->id(); + $object_field['alt'] = DevelGenerateBase::createGreeking(4); + $object_field['title'] = DevelGenerateBase::createGreeking(4); + return $object_field; + } + + /** + * Private function for creating a random image. + * + * This function only works with the GD toolkit. ImageMagick is not supported. + */ + protected function generateImage($extension = 'png', $min_resolution, $max_resolution) { + if ($tmp_file = drupal_tempnam('temporary://', 'imagefield_')) { + $destination = $tmp_file . '.' . $extension; + file_unmanaged_move($tmp_file, $destination, FILE_CREATE_DIRECTORY); + + $min = explode('x', $min_resolution); + $max = explode('x', $max_resolution); + + $width = rand((int)$min[0], (int)$max[0]); + $height = rand((int)$min[1], (int)$max[1]); + + // Make an image split into 4 sections with random colors. + $im = imagecreate($width, $height); + for ($n = 0; $n < 4; $n++) { + $color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255)); + $x = $width/2 * ($n % 2); + $y = $height/2 * (int) ($n >= 2); + imagefilledrectangle($im, $x, $y, $x + $width/2, $y + $height/2, $color); + } + + // Make a perfect circle in the image middle. + $color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255)); + $smaller_dimension = min($width, $height); + $smaller_dimension = ($smaller_dimension % 2) ? $smaller_dimension : $smaller_dimension; + imageellipse($im, $width/2, $height/2, $smaller_dimension, $smaller_dimension, $color); + + $save_function = 'image'. ($extension == 'jpg' ? 'jpeg' : $extension); + $save_function($im, drupal_realpath($destination)); + return $destination; + } + + } + +} diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldLink.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldLink.php new file mode 100755 index 0000000..1c996ce --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldLink.php @@ -0,0 +1,43 @@ +getFieldSettings(); + + // Set of possible top-level domains. + $tlds = array('com', 'net', 'gov', 'org', 'edu', 'biz', 'info'); + + // Set random length for the domain name. + $domain_length = mt_rand(7, 15); + + // Get the title settings from the field instance. + $allow_title = $settings['title']; + switch ($allow_title) { + case DRUPAL_DISABLED: + $generate_title = FALSE; + break; + case DRUPAL_REQUIRED: + $generate_title = TRUE; + break; + case DRUPAL_OPTIONAL: + // In case of optional title, randomize its generation. + $generate_title = mt_rand(0,1); + break; + } + + // Set the title value as the presave function is expecting it but only + // input content if needed. + $object_field['title'] = ''; + if ($generate_title == TRUE) { + $object_field['title'] = DevelGenerateBase::develCreateGreeking(4); + } + + $object_field['url'] = 'http://www.' . DevelGenerateBase::generateWord($domain_length) . '.' . $tlds[mt_rand(0, (sizeof($tlds)-1))]; + return $object_field; + } + +} \ No newline at end of file diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldNumber.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldNumber.php new file mode 100755 index 0000000..c28701d --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldNumber.php @@ -0,0 +1,43 @@ +getFieldSettings(); + + // Make sure the instance settings are all set. + foreach (array('min', 'max', 'precision', 'scale') as $key) { + if (empty($settings[$key])) { + $settings[$key] = NULL; + } + } + $min = is_numeric($settings['min']) ? $settings['min'] : 0; + switch ($form_display_options['type']) { + case 'number_integer': + $max = is_numeric($settings['max']) ? $settings['max'] : 10000; + $decimal = 0; + $scale = 0; + break; + + case 'number_decimal': + $precision = is_numeric($settings['precision']) ? $settings['precision'] : 10; + $scale = is_numeric($settings['scale']) ? $settings['scale'] : 2; + $max = is_numeric($settings['max']) ? $settings['max'] : pow(10, ($precision - $scale)); + $decimal = rand(0, (10 * $scale)) / 100; + break; + + case 'number_float': + $precision = rand(10, 32); + $scale = rand(0, 2); + $decimal = rand(0, (10 * $scale)) / 100; + $max = is_numeric($settings['max']) ? $settings['max'] : pow(10, ($precision - $scale)); + break; + } + $object_field['value'] = round((rand($min, $max) + $decimal), $scale); + return $object_field; + } + +} \ No newline at end of file diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldOptions.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldOptions.php new file mode 100755 index 0000000..30f72a5 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldOptions.php @@ -0,0 +1,17 @@ +getField($object->entityType(), $instance->getFieldName()); + if ($allowed_values = options_allowed_values($field_info, $object)) { + $keys = array_keys($allowed_values); + $object_field['value'] = $keys[mt_rand(0, count($allowed_values) - 1)]; + } + return $object_field; + } + +} \ No newline at end of file diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldTaxonomy.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldTaxonomy.php new file mode 100755 index 0000000..4de5f4f --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldTaxonomy.php @@ -0,0 +1,34 @@ +getFieldSettings(); + // TODO: For free tagging vocabularies that do not already have terms, this + // will not result in any tags being added. + $machine_name = $settings['allowed_values'][0]['vocabulary']; + $vocabulary = entity_load('taxonomy_vocabulary', $machine_name); + if ($max = db_query('SELECT MAX(tid) FROM {taxonomy_term_data} WHERE vid = :vid', array(':vid' => $vocabulary->vid))->fetchField()) { + $candidate = mt_rand(1, $max); + $query = db_select('taxonomy_term_data', 't'); + $tid = $query + ->fields('t', array('tid')) + ->condition('t.vid', $vocabulary->vid, '=') + ->condition('t.tid', $candidate, '>=') + ->range(0,1) + ->execute() + ->fetchField(); + // If there are no terms for the taxonomy, the query will fail, in which + // case we return NULL. + if ($tid === FALSE) { + return NULL; + } + $object_field['target_id'] = (int) $tid; + return $object_field; + } + } + +} \ No newline at end of file diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldText.php b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldText.php new file mode 100755 index 0000000..a051fed --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/DevelGenerateFieldText.php @@ -0,0 +1,33 @@ +getFieldSettings(); + if (!empty($settings['text_processing'])) { + $formats = filter_formats(); + $format = array_rand($formats); + } + else { + $format = filter_fallback_format(); + } + + if (empty($settings['max_length'])) { + // Textarea handling + $object_field['value'] = DevelGenerateBase::createContent($format); + if ($form_display_options['type'] == 'text_textarea_with_summary' && !empty($settings['display_summary'])) { + $object_field['summary'] = DevelGenerateBase::createContent($format); + } + } + else { + // Textfield handling. + $object_field['value'] = substr(DevelGenerateBase::createGreeking(mt_rand(1, $settings['max_length'] / 6), FALSE), 0, $settings['max_length']); + } + $object_field['format'] = $format; + return $object_field; + } + +} \ No newline at end of file diff --git a/devel_generate/lib/Drupal/devel_generate/DevelGeneratePluginManager.php b/devel_generate/lib/Drupal/devel_generate/DevelGeneratePluginManager.php index bc87ed2..1b16f26 100755 --- a/devel_generate/lib/Drupal/devel_generate/DevelGeneratePluginManager.php +++ b/devel_generate/lib/Drupal/devel_generate/DevelGeneratePluginManager.php @@ -6,22 +6,22 @@ namespace Drupal\devel_generate; -use \Drupal\Core\Plugin\DefaultPluginManager; +use Drupal\Core\Plugin\DefaultPluginManager; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Language\LanguageManager; /** * Plugin type manager for DevelGenerate plugins. */ -Class DevelGeneratePluginManager extends DefaultPluginManager -{ +Class DevelGeneratePluginManager extends DefaultPluginManager { - public function __construct(\Traversable $namespaces) { + public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) { parent::__construct('Plugin/DevelGenerate', $namespaces, 'Drupal\devel_generate\Annotation\DevelGenerate'); - //$this->setCacheBackend($cache_backend, $language_manager, 'devel_generate_plugins'); - //$this->alterInfo($module_handler, 'devel_generate_info'); - $this->factory = new DevelGenerateFactory($this); + $this->setCacheBackend($cache_backend, $language_manager, 'devel_generate_plugins'); + $this->alterInfo($module_handler, 'devel_generate_info'); } } - diff --git a/devel_generate/lib/Drupal/devel_generate/Form/GenerateForm.php b/devel_generate/lib/Drupal/devel_generate/Form/GenerateForm.php index be24d7d..9f4a0f7 100755 --- a/devel_generate/lib/Drupal/devel_generate/Form/GenerateForm.php +++ b/devel_generate/lib/Drupal/devel_generate/Form/GenerateForm.php @@ -9,7 +9,7 @@ namespace Drupal\devel_generate\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormInterface; - +use Drupal\devel_generate\DevelGenerateException; /** * Defines a form that allows privileged users to generate entities. */ @@ -28,8 +28,10 @@ class GenerateForm extends FormBase implements FormInterface { public function buildForm(array $form, array &$form_state) { $devel_generate_manager = \Drupal::service('plugin.manager.develgenerate'); - $element_to_generate = arg(4); - $instance = $devel_generate_manager->createInstance($element_to_generate, array()); + + $request = $this->getRequest(); + $element_to_generate = $request->get('_plugin_id'); + $instance = $devel_generate_manager->createInstance($element_to_generate); $form = $instance->settingsForm($form, $form_state); $form_state['instance'] = $instance; @@ -46,9 +48,15 @@ class GenerateForm extends FormBase implements FormInterface { */ public function submitForm(array &$form, array &$form_state) { - $values = $form_state['values']; - $instance = $form_state['instance']; - $instance->generate($values); + try { + $values = $form_state['values']; + $instance = $form_state['instance']; + $instance->generate($values); + } + catch (DevelGenerateException $e) { + watchdog('DevelGenerate', 'Failed to generate elements due to "%error".', array('%error' => $e->getMessage()), WATCHDOG_WARNING); + drupal_set_message($this->t('Failed to generate elements due to "%error".', array('%error' => $e->getMessage()))); + } } } diff --git a/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/ContentDevelGenerate.php b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/ContentDevelGenerate.php new file mode 100755 index 0000000..133acc7 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/ContentDevelGenerate.php @@ -0,0 +1,337 @@ +moduleExists('content')) { + $types = content_types(); + foreach ($types as $type) { + $warn = ''; + if (count($type['fields'])) { + $warn = t('. This type contains CCK fields which will only be populated by fields that implement the content_generate hook.'); + } + $options[$type['type']] = array('#markup' => t($type['name']). $warn); + } + } + else { + $types = node_type_get_types(); + foreach ($types as $type) { + $options[$type->type] = array( + 'type' => array('#markup' => t($type->name)), + ); + if (\Drupal::moduleHandler()->moduleExists('comment')) { + $default = variable_get('comment_' . $type->type, COMMENT_OPEN); + $map = array(t('Hidden'), t('Closed'), t('Open')); + $options[$type->type]['comments'] = array('#markup' => ''. $map[$default]. ''); + } + } + } + // we cannot currently generate valid polls. + unset($options['poll']); + + if (empty($options)) { + $this->setMessage(t('You do not have any content types that can be generated. Go create a new content type already!', array('@create-type' => url('admin/structure/types/add'))), 'error', FALSE); + return; + } + + $header = array( + 'type' => t('Content type'), + ); + if (\Drupal::moduleHandler()->moduleExists('comment')) { + $header['comments'] = t('Comments'); + } + + $form['node_types'] = array( + '#type' => 'table', + '#header' => $header, + '#tableselect' => TRUE, + ); + + $form['node_types'] += $options; + + if (\Drupal::moduleHandler()->moduleExists('checkall')) $form['node_types']['#checkall'] = TRUE; + $form['kill'] = array( + '#type' => 'checkbox', + '#title' => t('Delete all content in these content types before generating new content.'), + '#default_value' => $this->getSetting('kill'), + ); + $form['num'] = array( + '#type' => 'textfield', + '#title' => t('How many nodes would you like to generate?'), + '#default_value' => $this->getSetting('num'), + '#size' => 10, + ); + + $options = array(1 => t('Now')); + foreach (array(3600, 86400, 604800, 2592000, 31536000) as $interval) { + $options[$interval] = \Drupal::service('date')->formatInterval($interval, 1) . ' ' . t('ago'); + } + $form['time_range'] = array( + '#type' => 'select', + '#title' => t('How far back in time should the nodes be dated?'), + '#description' => t('Node creation dates will be distributed randomly from the current time, back to the selected time.'), + '#options' => $options, + '#default_value' => 604800, + ); + + $form['max_comments'] = array( + '#type' => \Drupal::moduleHandler()->moduleExists('comment') ? 'textfield' : 'value', + '#title' => t('Maximum number of comments per node.'), + '#description' => t('You must also enable comments for the content types you are generating. Note that some nodes will randomly receive zero comments. Some will receive the max.'), + '#default_value' => $this->getSetting('max_comments'), + '#size' => 3, + '#access' => \Drupal::moduleHandler()->moduleExists('comment'), + ); + $form['title_length'] = array( + '#type' => 'textfield', + '#title' => t('Maximum number of words in titles'), + '#default_value' => $this->getSetting('title_length'), + '#size' => 10, + ); + $form['add_alias'] = array( + '#type' => 'checkbox', + '#disabled' => !\Drupal::moduleHandler()->moduleExists('path'), + '#description' => t('Requires path.module'), + '#title' => t('Add an url alias for each node.'), + '#default_value' => FALSE, + ); + $form['add_statistics'] = array( + '#type' => 'checkbox', + '#title' => t('Add statistics for each node (node_counter table).'), + '#default_value' => TRUE, + '#access' => \Drupal::moduleHandler()->moduleExists('statistics'), + ); + + unset($options); + $options[Language::LANGCODE_NOT_SPECIFIED] = t('Language neutral'); + if (\Drupal::moduleHandler()->moduleExists('locale')) { + $languages = language_list(); + foreach ($languages as $langcode => $language) { + $options[$langcode] = $language->name; + } + } + $form['add_language'] = array( + '#type' => 'select', + '#title' => t('Set language on nodes'), + '#multiple' => TRUE, + '#disabled' => !\Drupal::moduleHandler()->moduleExists('locale'), + '#description' => t('Requires locale.module'), + '#options' => $options, + '#default_value' => array(Language::LANGCODE_NOT_SPECIFIED), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Generate'), + '#tableselect' => TRUE, + ); + $form['#redirect'] = FALSE; + + + return $form; + } + + /** + * {@inheritdoc} + */ + protected function generateElements(array $values) { + if ($values['num'] <= 50 && $values['max_comments'] <= 10) { + if (!empty($values['kill'])) { + $this->contentKill($values); + } + + if (count($values['node_types'])) { + // Generate nodes. + $this->develGenerateContentPreNode($values); + $start = time(); + for ($i = 1; $i <= $values['num']; $i++) { + $this->develGenerateContentAddNode($values); + if (function_exists('drush_log') && $i % drush_get_option('feedback', 1000) == 0) { + $now = time(); + drush_log(dt('Completed !feedback nodes (!rate nodes/min)', array('!feedback' => drush_get_option('feedback', 1000), '!rate' => (drush_get_option('feedback', 1000)*60)/($now-$start))), 'ok'); + $start = $now; + } + } + } + $this->setMessage(\Drupal::translation()->formatPlural($values['num'], '1 node created.', 'Finished creating @count nodes')); + } + else { + //@todo devel_generate_batch_content($form_state). + } + } + + public function handleDrushParams($args) { + + $add_language = drush_get_option('languages'); + if (!empty($add_language)) { + $add_language = explode(',', str_replace(' ', '', $add_language)); + // Intersect with the enabled languages to make sure the language args + // passed are actually enabled. + $values['values']['add_language'] = array_intersect($add_language, array_keys(locale_language_list())); + } + + $values['kill'] = drush_get_option('kill'); + $values['title_length'] = 6; + $values['num'] = array_shift($args); + $values['max_comments'] = array_shift($args); + $all_types = array_keys(node_type_get_names()); + $default_types = array_intersect(array('page', 'article'), $all_types); + $selected_types = _convert_csv_to_array(drush_get_option('types', $default_types)); + + if (empty($selected_types)) { + return drush_set_error('DEVEL_GENERATE_NO_CONTENT_TYPES', dt('No content types available')); + } + + $values['node_types'] = drupal_map_assoc($selected_types); + $node_types = array_filter($values['node_types']); + + if (!empty($values['kill']) && empty($node_types)) { + return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Please provide content type (--types) in which you want to delete the content.')); + } + + return $values; + } + + protected function contentKill($values) { + $results = db_select('node', 'n') + ->fields('n', array('nid')) + ->condition('type', $values['node_types'], 'IN') + ->execute(); + foreach ($results as $result) { + $nids[] = $result->nid; + } + + if (!empty($nids)) { + entity_delete_multiple('node', $nids); + $this->setMessage(t('Deleted %count nodes.', array('%count' => count($nids)))); + } + } + + protected function develGenerateContentPreNode(&$results) { + // Get user id. + $users = $this->getUsers(); + $users = array_merge($users, array('0')); + $results['users'] = $users; + } + + /** + * Create one node. Used by both batch and non-batch code branches. + * + * @param $num + * array of options obtained from devel_generate_content_form. + */ + protected function develGenerateContentAddNode(&$results) { + if (!isset($results['time_range'])) { + $results['time_range'] = 0; + } + $users = $results['users']; + + $node_type = array_rand(array_filter($results['node_types'])); + $type = node_type_load($node_type); + $uid = $users[array_rand($users)]; + + $edit_node = array( + 'nid' => NULL, + 'type' => $node_type, + 'uid' => $uid, + 'revision' => mt_rand(0, 1), + 'status' => TRUE, + 'promote' => mt_rand(0, 1), + 'created' => REQUEST_TIME - mt_rand(0, $results['time_range']), + 'langcode' => $this->getLangcode($results), + ); + if ($type->has_title) { + // We should not use the random function if the value is not random + if ($results['title_length'] < 2) { + $edit_node['title'] = $this->createGreeking(1, TRUE); + } + else { + $edit_node['title'] = $this->createGreeking(mt_rand(1, $results['title_length']), TRUE); + } + } + else { + $edit_node['title'] = ''; + } + $node = entity_create('node', $edit_node); + + // A flag to let hook_node_insert() implementations know that this is a + // generated node. + $node->devel_generate = $results; + + // Populate all core fields on behalf of field.module + $this->generateFields($node, 'node', $node->bundle()); + + // See devel_generate_node_insert() for actions that happen before and after + // this save. + $node->save(); + } + + /* + * Determine language based on $results. + */ + protected function getLangcode($results) { + if (isset($results['add_language'])) { + $langcodes = $results['add_language']; + $langcode = $langcodes[array_rand($langcodes)]; + } + else { + $langcode = language_default()->id; + } + return $langcode == 'en' ? Language::LANGCODE_NOT_SPECIFIED : $langcode; + } + + protected function getUsers() { + + $users = array(); + $result = db_query_range("SELECT uid FROM {users}", 0, 50); + foreach ($result as $record) { + $users[] = $record->uid; + } + return $users; + } + +} diff --git a/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/MenuDevelGenerate.php b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/MenuDevelGenerate.php new file mode 100755 index 0000000..22110f3 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/MenuDevelGenerate.php @@ -0,0 +1,322 @@ +moduleExists('menu'); + if ($menu_enabled) { + $menus = array('__new-menu__' => t('Create new menu(s)')) + menu_get_menus(); + } + else { + $menus = menu_list_system_menus(); + } + $form['existing_menus'] = array( + '#type' => 'checkboxes', + '#title' => t('Generate links for these menus'), + '#options' => $menus, + '#default_value' => array('__new-menu__'), + '#required' => TRUE, + ); + if ($menu_enabled) { + $form['num_menus'] = array( + '#type' => 'textfield', + '#title' => t('Number of new menus to create'), + '#default_value' => $this->getSetting('num_menus'), + '#size' => 10, + '#states' => array( + 'visible' => array( + ':input[name=existing_menus[__new-menu__]]' => array('checked' => TRUE), + ), + ), + ); + } + $form['num_links'] = array( + '#type' => 'textfield', + '#title' => t('Number of links to generate'), + '#default_value' => $this->getSetting('num_links'), + '#size' => 10, + '#required' => TRUE, + ); + $form['title_length'] = array( + '#type' => 'textfield', + '#title' => t('Maximum number of characters in menu and menu link names'), + '#description' => t("The minimum length is 2."), + '#default_value' => $this->getSetting('title_length'), + '#size' => 10, + '#required' => TRUE, + ); + $form['link_types'] = array( + '#type' => 'checkboxes', + '#title' => t('Types of links to generate'), + '#options' => array( + 'node' => t('Nodes'), + 'front' => t('Front page'), + 'external' => t('External'), + ), + '#default_value' => array('node', 'front', 'external'), + '#required' => TRUE, + ); + $form['max_depth'] = array( + '#type' => 'select', + '#title' => t('Maximum link depth'), + '#options' => range(0, MENU_MAX_DEPTH), + '#default_value' => floor(MENU_MAX_DEPTH / 2), + '#required' => TRUE, + ); + unset($form['max_depth']['#options'][0]); + $form['max_width'] = array( + '#type' => 'textfield', + '#title' => t('Maximum menu width'), + '#default_value' => $this->getSetting('max_width'), + '#size' => 10, + '#description' => t("Limit the width of the generated menu's first level of links to a certain number of items."), + '#required' => TRUE, + ); + $form['kill'] = array( + '#type' => 'checkbox', + '#title' => 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(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(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(t('Created @count new menu links.', array('@count' => count($new_links)))); + } + + public function handleDrushParams($args) { + + $values = array( + 'num_menus' => array_shift($args), + 'num_links' => array_shift($args), + 'kill' => drush_get_option('kill'), + 'pipe' => drush_get_option('pipe'), + 'link_types' => $link_types = drupal_map_assoc(array('node', 'front', 'external')), + ); + + $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['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 (\Drupal::moduleHandler()->moduleExists('menu')) { + foreach (menu_get_menus(FALSE) as $menu => $menu_title) { + if (strpos($menu, 'devel-') === 0) { + menu_load($menu)->delete(); + } + } + } + // Delete menu links generated by devel. + $result = db_select('menu_links', 'm') + ->fields('m', array('mlid')) + ->condition('m.menu_name', 'devel', '<>') + // Look for the serialized version of 'devel' => TRUE. + ->condition('m.options', '%' . db_like('s:5:"devel";b:1') . '%', 'LIKE') + ->execute(); + foreach ($result as $link) { + menu_link_delete($link->mlid); + } + } + + /** + * Generates new menus. + */ + protected function generateMenus($num_menus, $title_length = 12) { + $menus = array(); + + if (!\Drupal::moduleHandler()->moduleExists('menu')) { + $num_menus = 0; + } + + for ($i = 1; $i <= $num_menus; $i++) { + $menu = array(); + $menu['label'] = $this->generateWord(mt_rand(2, max(2, $title_length))); + $menu['id'] = 'devel-' . drupal_strtolower($menu['label']); + $menu['description'] = t('Description of @name', array('@name' => $menu['label'])); + $new_menu = entity_create('menu', $menu); + $new_menu->save(); + $menus[$new_menu->id()] = $new_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 = entity_create('menu_link', array( + 'menu_name' => $menu_name, + 'options' => array('devel' => TRUE), + 'weight' => mt_rand(-50, 50), + 'mlid' => 0, + 'link_title' => $this->generateWord(mt_rand(2, max(2, $title_length))), + )); + $link->options['attributes']['title'] = t('Description of @title.', array('@title' => $link->link_title)); + + // 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 { + $link->plid = db_select('menu_links', 'm') + ->fields('m', array('mlid')) + ->condition('m.menu_name', $menus, 'IN') + ->condition('m.depth', $depth) + ->range(0, 1) + ->orderRandom() + ->execute() + ->fetchField(); + $depth--; + } while (!$link->plid && $depth > 0); + if (!$link->plid) { + $link->plid = 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_path = $link->router_path = 'node/' . $node['nid']; + $link->link_title = $node['title']; + break; + } + case 'external': + $link->link_path = 'http://www.example.com/'; + break; + case 'front': + $link->link_path = $link->router_path = ''; + break; + default: + $link->devel_link_type = $link_type; + break; + } + + $link->save(); + + $links[$link->id()] = $link->link_title; + } + + return $links; + } + +} diff --git a/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/TermDevelGenerate.php b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/TermDevelGenerate.php new file mode 100755 index 0000000..fd3b943 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/TermDevelGenerate.php @@ -0,0 +1,215 @@ + $vocab) { + $options[$vid] = $vocab->vid; + } + $form['vids'] = array( + '#type' => 'select', + '#multiple' => TRUE, + '#title' => t('Vocabularies'), + '#required' => TRUE, + '#options' => $options, + '#description' => t('Restrict terms to these vocabularies.'), + ); + $form['num'] = array( + '#type' => 'textfield', + '#title' => t('Number of terms?'), + '#default_value' => $this->getSetting('num'), + '#size' => 10, + ); + $form['title_length'] = array( + '#type' => 'textfield', + '#title' => t('Maximum number of characters in term names'), + '#default_value' => $this->getSetting('title_length'), + '#size' => 10, + ); + $form['kill'] = array( + '#type' => 'checkbox', + '#title' => t('Delete existing terms in specified vocabularies before generating new terms.'), + '#default_value' => $this->getSetting('kill'), + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function generateElements(array $values) { + + if ($values['kill']) { + foreach ($values['vids'] as $vid) { + $this->deleteVocabularyTerms($vid); + } + $this->setMessage(t('Deleted existing terms.')); + } + $vocabs = entity_load_multiple('taxonomy_vocabulary', $values['vids']); + $new_terms = $this->generateTerms($values['num'], $vocabs, $values['title_length']); + if (!empty($new_terms)) { + $this->setMessage(t('Created the following new terms: !terms', array('!terms' => implode(', ', $new_terms)))); + } + } + + /** + * Deletes all terms of a vocabulary. + * + * @param $vid + * int a vocabulary vid. + */ + protected function deleteVocabularyTerms($vid) { + $tids = array(); + foreach (taxonomy_get_tree($vid) as $term) { + $tids[] = $term->tid; + } + entity_delete_multiple('taxonomy_term', $tids);; + } + + /** + * Generates taxonomy terms for a list of given vocabularies. + * + * @param $records + * int number of terms to create in total. + * @param $vocabs + * array list of vocabs to populate. + * @param $maxlength + * int maximum length per term. + * @return + * array the list of names of the created terms. + */ + function generateTerms($records, $vocabs, $maxlength = 12) { + $terms = array(); + + // Insert new data: + $max = db_query('SELECT MAX(tid) FROM {taxonomy_term_data}')->fetchField(); + $start = time(); + for ($i = 1; $i <= $records; $i++) { + $values = array(); + switch ($i % 2) { + case 1: + // Set vid and vocabulary_machine_name properties. + $vocab = $vocabs[array_rand($vocabs)]; + $values['vid'] = $vocab->vid; + $values['vocabulary_machine_name'] = $vocab->vid; + $values['parent'] = array(0); + break; + default: + while (TRUE) { + // Keep trying to find a random parent. + $candidate = mt_rand(1, $max); + $query = db_select('taxonomy_term_data', 't'); + $parent = $query + ->fields('t', array('tid', 'vid')) + ->condition('t.vid', array_keys($vocabs), 'IN') + ->condition('t.tid', $candidate, '>=') + ->range(0,1) + ->execute() + ->fetchAssoc(); + if ($parent['tid']) { + break; + } + } + $values['parent'] = array($parent['tid']); + // Slight speedup due to this property being set. + $values['vocabulary_machine_name'] = $parent['vid']; + $values['vid'] = $parent['vid']; + break; + } + + $values['name'] = $this->generateWord(mt_rand(2, $maxlength)); + $values['description'] = "description of " . $values['name']; + $values['format'] = filter_fallback_format(); + $values['weight'] = mt_rand(0, 10); + $values['langcode'] = Language::LANGCODE_NOT_SPECIFIED; + $term = entity_create('taxonomy_term', $values); + + // Populate all core fields on behalf of field.module + $this->generateFields($term, 'taxonomy_term', $values['vocabulary_machine_name']); + + if ($status = $term->save()) { + $max += 1; + if (function_exists('drush_log')) { + + $feedback = drush_get_option('feedback', 1000); + if ($i % $feedback == 0) { + $now = time(); + drush_log(dt('Completed !feedback terms (!rate terms/min)', array('!feedback' => $feedback, '!rate' => $feedback*60 / ($now-$start) )), 'ok'); + $start = $now; + } + } + + // Limit memory usage. Only report first 20 created terms. + if ($i < 20) { + $terms[] = $term->name->value; + } + + unset($term); + } + } + return $terms; + } + + public function handleDrushParams($args) { + + $vname = array_shift($args); + $values = array( + 'num' => array_shift($args), + 'kill' => drush_get_option('kill'), + 'title_length' => 12, + ); + // Try to convert machine name to a vocab ID + if (!$vocab = entity_load('taxonomy_vocabulary', $vname)) { + return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid vocabulary name: !name', array('!name' => $vname))); + } + if ($this->isNumber($values['num']) == FALSE) { + return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of terms: !num', array('!num' => $values['num']))); + } + + $values['vids'] = array($vocab->vid); + + return $values; + } + +} diff --git a/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/UserDevelGenerate.php b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/UserDevelGenerate.php index 3e7fedc..cd8a16e 100755 --- a/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/UserDevelGenerate.php +++ b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/UserDevelGenerate.php @@ -8,60 +8,36 @@ namespace Drupal\devel_generate\Plugin\DevelGenerate; use Drupal\devel_generate\DevelGenerateBase; -use Drupal\Core\Plugin\ContainerFactoryPluginInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\devel_generate\DevelGenerateFieldBase; /** * Provides a UserDevelGenerate plugin. * * @DevelGenerate( * id = "user", + * label = @Translation("users"), + * description = @Translation("Generate a given number of users. Optionally delete current users."), + * url = "user", * settings = { - * "num" = 53, - * "kill_users" = FALSE, + * "num" = 50, + * "kill" = FALSE, * "pass" = "" * }, * drushSettings = { * "suffix" = "users", * "alias" = "u", - * "num" = "Number of user to be created", - * "kill" = "Delete existing users", - * "pass" = "Set a predifined password", - * "roles" = "Roles for new users" - * }, - * drushArgs= { - * "num" = "Number of users to create", + * "options" = { + * "kill" = "Delete existing users", + * "pass" = "Set a predifined password", + * "roles" = "Roles for new users" + * }, + * "args" = { + * "num" = "Number of users to create" + * } * } * ) */ -class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface { - - private function generateWord($length) { - mt_srand((double)microtime()*1000000); - - $vowels = array("a", "e", "i", "o", "u"); - $cons = array("b", "c", "d", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "u", "v", "w", "tr", - "cr", "br", "fr", "th", "dr", "ch", "ph", "wr", "st", "sp", "sw", "pr", "sl", "cl", "sh"); - - $num_vowels = count($vowels); - $num_cons = count($cons); - $word = ''; - - while(strlen($word) < $length){ - $word .= $cons[mt_rand(0, $num_cons - 1)] . $vowels[mt_rand(0, $num_vowels - 1)]; - } - - return substr($word, 0, $length); - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) { - return new static( - //@todo: implement create method. - ); - } +class UserDevelGenerate extends DevelGenerateBase { public function settingsForm(array $form, array &$form_state) { @@ -72,10 +48,10 @@ class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu '#size' => 10, ); - $form['kill_users'] = array( + $form['kill'] = array( '#type' => 'checkbox', '#title' => t('Delete all users (except user id 1) before generating new users.'), - '#default_value' => $this->getSetting('kill_users'), + '#default_value' => $this->getSetting('kill'), ); $options = user_role_names(TRUE); @@ -97,7 +73,7 @@ class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu $options = array(1 => t('Now')); foreach (array(3600, 86400, 604800, 2592000, 31536000) as $interval) { - $options[$interval] = format_interval($interval, 1) . ' ' . t('ago'); + $options[$interval] = \Drupal::service('date')->formatInterval($interval, 1) . ' ' . t('ago'); } $form['time_range'] = array( '#type' => 'select', @@ -106,15 +82,16 @@ class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu '#options' => $options, '#default_value' => 604800, ); + return $form; } /** * {@inheritdoc} */ - public function generateElements(array $values) { + protected function generateElements(array $values) { $num = $values['num']; - $kill = $values['kill_users']; + $kill = $values['kill']; $pass = $values['pass']; $age = $values['time_range']; $roles = $values['roles']; @@ -126,7 +103,7 @@ class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu ->execute() ->fetchAllAssoc('uid'); user_delete_multiple(array_keys($uids)); - drupal_set_message(format_plural(count($uids), '1 user deleted', '@count users deleted.')); + $this->setMessage(\Drupal::translation()->formatPlural(count($uids), '1 user deleted', '@count users deleted.')); } if ($num > 0) { @@ -154,27 +131,22 @@ class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPlu $account = entity_create('user', $edit); // Populate all core fields on behalf of field.module - module_load_include('inc', 'devel_generate', 'devel_generate.fields'); - devel_generate_fields($account, 'user', 'user', 'register'); + DevelGenerateFieldBase::generateFields($account, 'user', 'user', 'register'); $account->save(); } } - drupal_set_message(t('!num_users created.', array('!num_users' => format_plural($num, '1 user', '@count users')))); + $this->setMessage(t('!num_users created.', array('!num_users' => format_plural($num, '1 user', '@count users')))); } - public function getDrushValues($args) { + public function handleDrushParams($args) { $values = array( 'num' => array_shift($args), 'roles' => drush_get_option('roles') ? explode(',', drush_get_option('roles')) : array(), - 'kill_users' => drush_get_option('kill'), + 'kill' => drush_get_option('kill'), 'pass' => drush_get_option('pass', NULL), 'time_range' => 0, ); return $values; } - public function drushLog($values = array()) { - drush_log(t('Generated @number users.', array('@number' => $values['num'])), 'success'); - } - } diff --git a/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/VocabularyDevelGenerate.php b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/VocabularyDevelGenerate.php new file mode 100755 index 0000000..2f92e90 --- /dev/null +++ b/devel_generate/lib/Drupal/devel_generate/Plugin/DevelGenerate/VocabularyDevelGenerate.php @@ -0,0 +1,126 @@ + 'textfield', + '#title' => t('Number of vocabularies?'), + '#default_value' => $this->getSetting('num'), + '#size' => 10, + ); + $form['title_length'] = array( + '#type' => 'textfield', + '#title' => t('Maximum number of characters in vocabulary names'), + '#default_value' => $this->getSetting('title_length'), + '#size' => 10, + ); + $form['kill_taxonomy'] = array( + '#type' => 'checkbox', + '#title' => t('Delete existing vocabularies before generating new ones.'), + '#default_value' => $this->getSetting('kill'), + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function generateElements(array $values) { + + if ($values['kill_taxonomy']) { + $this->deleteVocabularies(); + $this->setMessage(t('Deleted existing vocabularies.')); + } + $new_vocs = $this->generateVocabs($values['num'], $values['title_length']); + if (!empty($new_vocs)) { + $this->setMessage(t('Created the following new vocabularies: !vocs', array('!vocs' => implode(', ', $new_vocs)))); + } + } + + /** + * Deletes all vocabularies. + */ + protected function deleteVocabularies() { + foreach (entity_load_multiple('taxonomy_vocabulary') as $vid => $vocabulary) { + $vocabulary->delete(); + } + } + + function generateVocabs($records, $maxlength = 12) { + $vocs = array(); + + // Insert new data: + for ($i = 1; $i <= $records; $i++) { + $name = $this->generateWord(mt_rand(2, $maxlength)); + $vocabulary = entity_create('taxonomy_vocabulary', array( + 'name' => $name, + 'vid' => drupal_strtolower($name), + 'langcode' => Language::LANGCODE_NOT_SPECIFIED, + 'description' => "description of $name", + 'hierarchy' => 1, + 'weight' => mt_rand(0, 10), + 'multiple' => 1, + 'required' => 0, + 'relations' => 1, + )); + $vocabulary->save(); + $vocs[] = $vocabulary->name; + + unset($vocabulary); + } + return $vocs; + } + + public function handleDrushParams($args) { + $values = array( + 'num' => array_shift($args), + 'kill_taxonomy' => drush_get_option('kill'), + 'title_length' => 12, + ); + + if ($this->isNumber($values['num']) == FALSE) { + return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of vocabularies: !num.', array('!num' => $values['num']))); + } + return $values; + } + +} diff --git a/devel_generate/lib/Drupal/devel_generate/Routing/DevelGenerateRouteSubscriber.php b/devel_generate/lib/Drupal/devel_generate/Routing/DevelGenerateRouteSubscriber.php index 2a9182b..2d5d2e1 100755 --- a/devel_generate/lib/Drupal/devel_generate/Routing/DevelGenerateRouteSubscriber.php +++ b/devel_generate/lib/Drupal/devel_generate/Routing/DevelGenerateRouteSubscriber.php @@ -13,23 +13,28 @@ use Symfony\Component\Routing\RouteCollection; */ class DevelGenerateRouteSubscriber extends RouteSubscriberBase { - public function routes(RouteCollection $collection) { + public function alterRoutes(RouteCollection $collection, $provider) { + + if ($provider != 'dynamic_routes') { + return; + } $devel_generate_plugins = $devel_generate_manager = \Drupal::service('plugin.manager.develgenerate')->getDefinitions(); foreach ($devel_generate_plugins as $id => $plugin) { - $type_url_str = str_replace('_', '-', $id); + $type_url_str = str_replace('_', '-', $plugin['url']); $route = new Route( - 'admin/config/development/generate/' . $type_url_str, + "admin/config/development/generate/$type_url_str", array( '_form' => '\Drupal\devel_generate\Form\GenerateForm', '_title' => 'Generate', + '_plugin_id' => $id, ), array( - '_permission' => 'admin devel generate', + '_permission' => 'admin devel_generate', ) ); - $collection->add('devel_generate.' . $id, $route); + $collection->add("devel_generate.$id", $route); } } }