Commit 8d52f52e authored by lussoluca's avatar lussoluca

Merge branch '8.x-1.x' into testing

parents bcb56a96 a388a242
......@@ -18,10 +18,10 @@
float: left;
}
.toolbar .toolbar-tray-horizontal .menu {
.toolbar .toolbar-tray-horizontal .toolbar-menu {
float: left; /* LTR */
}
[dir="rtl"] .toolbar .toolbar-tray-horizontal .menu {
[dir="rtl"] .toolbar .toolbar-tray-horizontal .toolbar-menu {
float: right;
}
......
......@@ -16,7 +16,7 @@ function devel_requirements($phase) {
// https://www.drupal.org/node/2834400.
$requirements['devel'] = [
'title' => t('Devel module enabled'),
'description' => t('The module provide the access to debug informations, therefore is recommended to disable the Devel module on production sites.'),
'description' => t('The Devel module provides access to internal debugging information; therefore it\'s recommended to disable this module on sites in production.'),
'severity' => REQUIREMENT_INFO,
];
}
......
......@@ -26,6 +26,7 @@ use Drupal\Core\Url;
use Drupal\Core\Utility\Error;
use Drupal\devel\EntityTypeInfo;
use Drupal\devel\ToolbarHandler;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Implements hook_help().
......@@ -74,6 +75,11 @@ function devel_help($route_name, RouteMatchInterface $route_match) {
case 'devel.state_system_page':
return '<p>' . t('This is a list of state variables and their values. For more information read online documentation of <a href=":documentation">State API in Drupal 8</a>.', array(':documentation' => "https://www.drupal.org/developing/api/8/state")) . '</p>';
case 'devel.layout_info':
$output = '';
$output .= '<p>' . t('Displays layouts available to the site. For a complete overview of the layout system, see the <a href=":url">Layout API documentation</a>.', [':url' => 'https://www.drupal.org/docs/8/api/layout-api']) . '</p>';
return $output;
}
}
......@@ -104,6 +110,21 @@ function devel_toolbar() {
->toolbar();
}
/**
* Implements hook_menu_links_discovered_alter().
*/
function devel_menu_links_discovered_alter(&$links) {
// Conditionally add the Layouts info menu link.
if (\Drupal::moduleHandler()->moduleExists('layout_discovery')) {
$links['devel.layout_info'] = [
'title' => new TranslatableMarkup('Layouts Info'),
'route_name' => 'devel.layout_info',
'description' => new TranslatableMarkup('Overview of layouts available to the site.'),
'menu_name' => 'devel',
];
}
}
/**
* Implements hook_local_tasks_alter().
*/
......
......@@ -242,3 +242,15 @@ devel.event_info:
_admin_route: TRUE
requirements:
_permission: 'access devel information'
# Layouts info
devel.layout_info:
path: '/devel/layouts'
defaults:
_controller: '\Drupal\devel\Controller\LayoutInfoController::layoutInfoPage'
_title: 'Layouts'
options:
_admin_route: TRUE
requirements:
_permission: 'access devel information'
_module_dependencies: 'layout_discovery'
services:
develgenerate.command:
class: Drupal\devel_generate\Commands\DevelGenerateCommands
arguments: ['@plugin.manager.develgenerate']
tags:
- { name: drush.command }
<?php
namespace Unish;
if (class_exists('Unish\CommandUnishTestCase')) {
/**
* Tests for devel_generate drush commands.
*
* @group devel_generate
*/
class DevelGenerateUnishTest extends CommandUnishTestCase {
/**
* {@inheritdoc}
*/
public function setUp() {
if (UNISH_DRUPAL_MAJOR_VERSION < 8) {
$this->markTestSkipped('Devel Generate Tests only available on D8+.');
}
if (!$this->getSites()) {
$this->setUpDrupal(1, TRUE, UNISH_DRUPAL_MAJOR_VERSION, 'standard');
// Symlink the devel module into the sandbox.
$devel_directory = dirname(dirname(__DIR__));
symlink($devel_directory, $this->webroot() . '/modules/devel');
// Enable the devel_generate modules.
$this->drush('pm-enable', ['devel_generate'], $this->getOptions());
}
}
/**
* Tests devel generate terms.
*/
public function testDevelGenerateTerms() {
$this->drush('pm-enable', ['taxonomy'], $this->getOptions());
$this->drush('generate-terms', [], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Please provide a vocabulary machine name.', $this->getErrorOutput());
$this->drush('generate-terms', ['unknown'], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Invalid vocabulary name: unknown', $this->getErrorOutput());
$this->drush('generate-terms', ['tags', 'NaN'], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Invalid number of terms: NaN', $this->getErrorOutput());
$eval_term_count = "return \\Drupal::entityQuery('taxonomy_term')->count()->execute();";
$eval_options = $this->getOptions() + ['format' => 'string'];
$this->drush('generate-terms', ['tags'], $this->getOptions());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
$this->drush('php-eval', [$eval_term_count], $eval_options);
$this->assertEquals(10, $this->getOutput());
$this->drush('generate-terms', ['tags', '1'], $this->getOptions());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
$this->drush('php-eval', [$eval_term_count], $eval_options);
$this->assertEquals(11, $this->getOutput());
$this->drush('generate-terms', ['tags', '1'], $this->getOptions(TRUE));
$this->assertContains('Deleted existing terms.', $this->getErrorOutput());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
$this->drush('php-eval', [$eval_term_count], $eval_options);
$this->assertEquals(1, $this->getOutput());
$this->drush('gent', ['tags', '1'], $this->getOptions());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
}
/**
* Tests devel generate contents.
*/
public function testDevelGenerateContents() {
$this->drush('pm-enable', ['node'], $this->getOptions());
$eval_content_count = "return \\Drupal::entityQuery('node')->count()->execute();";
$eval_options = $this->getOptions() + ['format' => 'string'];
// Try to generate 10 content of type "page" or "article"
$this->drush('generate-content', [10], $this->getOptions(), NULL, NULL, static::EXIT_SUCCESS);
$this->assertContains('Finished creating 10 nodes', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(10, $this->getOutput());
// Try to generate 1 content of type "page" or "article"
$this->drush('generate-content', [1], $this->getOptions(), NULL, NULL, static::EXIT_SUCCESS);
$this->assertContains('1 node created.', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(11, $this->getOutput());
// Try to generate 5 content of type "page" or "article", removing all
// previous contents.
$this->drush('generate-content', [5], $this->getOptions(TRUE), NULL, NULL, static::EXIT_SUCCESS);
$this->assertContains('Finished creating 5 nodes', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
// Try to generate other 5 content with "crappy" type. Output should
// remains 5.
$generate_content_wrong_ct = $this->getOptions(TRUE) + ['types' => 'crappy'];
$this->drush('generate-content', [5], $generate_content_wrong_ct, NULL, NULL, static::EXIT_ERROR);
$this->assertContains('One or more content types have been entered that don', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
// Try to generate other 5 content with empty types. Output should
// remains 5.
$generate_content_no_types = $this->getOptions(TRUE) + ['types' => ''];
$this->drush('generate-content', [5], $generate_content_no_types, NULL, NULL, static::EXIT_ERROR);
$this->assertContains('No content types available', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
// Try to generate other 5 content without any types. Output should
// remains 5.
$generate_content_no_types = $this->getOptions(TRUE) + ['types' => NULL];
$this->drush('generate-content', [5], $generate_content_no_types, NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Wrong syntax or no content type selected. The correct syntax uses', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
}
/**
* Default drush options.
*
* @param bool $kill
* Whether add kill option.
*
* @return array
* An array containing the default options for drush commands.
*/
protected function getOptions($kill = FALSE) {
$options = [
'yes' => NULL,
'root' => $this->webroot(),
'uri' => key($this->getSites()),
];
if($kill) {
$options['kill'] = NULL;
}
return $options;
}
}
}
......@@ -2,7 +2,7 @@
/**
* @file
* Generate content, taxonomy, menu, and users via drush framework.
* Integration with Drush8. Drush9 commands are in src/Commands.
*/
use Drupal\devel_generate\DevelGenerateBaseInterface;
use Drupal\devel_generate\DevelGeneratePluginManager;
......
<?php
namespace Drupal\devel_generate\Commands;
use Consolidation\AnnotatedCommand\CommandData;
use Drupal\devel_generate\DevelGenerateBaseInterface;
use Drush\Commands\DrushCommands;
/**
* For commands that are parts of modules, Drush expects to find commandfiles in
* __MODULE__/src/Commands, and the namespace is Drupal/__MODULE__/Commands.
*
* In addition to a commandfile like this one, you need to add a drush.services.yml
* in root of your module like this module does.
*/
class DevelGenerateCommands extends DrushCommands {
/**
* @var DevelGenerateBaseInterface $manager
*/
protected $manager;
/**
* The plugin instance.
*
* @var DevelGenerateBaseInterface $instance
*/
protected $pluginInstance;
/**
* The Generate plugin parameters.
*
* @var array $parameters
*/
protected $parameters;
/**
* DevelGenerateCommands constructor.
* @param $manager
*/
public function __construct($manager) {
parent::__construct();
$this->setManager($manager);
}
/**
* @return \Drupal\devel_generate\DevelGenerateBaseInterface
*/
public function getManager() {
return $this->manager;
}
/**
* @param \Drupal\devel_generate\DevelGenerateBaseInterface $manager
*/
public function setManager($manager) {
$this->manager = $manager;
}
/**
* @return mixed
*/
public function getPluginInstance() {
return $this->pluginInstance;
}
/**
* @param mixed $pluginInstance
*/
public function setPluginInstance($pluginInstance) {
$this->pluginInstance = $pluginInstance;
}
/**
* @return array
*/
public function getParameters() {
return $this->parameters;
}
/**
* @param array $parameters
*/
public function setParameters($parameters) {
$this->parameters = $parameters;
}
/**
* Create users.
*
* @command devel-generate-users
* @pluginId user
* @param $num Number of users to generate.
* @option kill Delete all users before generating new ones.
* @option roles A comma delimited list of role IDs for new users. Don't specify 'authenticated'.
* @option pass Specify a password to be set for all generated users.
* @aliases genu
*/
public function users($num = 50, $options = ['kill' => FALSE, 'roles' => '']) {
// @todo pass $options to the plugins.
$this->generate();
}
/**
* Create terms in specified vocabulary.
*
* @command devel-generate-terms
* @pluginId term
* @param $machine_name Vocabulary machine name into which new terms will be inserted.
* @param $num Number of terms to generate.
* @option kill Delete all terms before generating new ones.
* @option feedback An integer representing interval for insertion rate logging.
* @validate-entity-load taxonomy_vocabulary machine_name
* @aliases gent
*/
public function terms($machine_name, $num = 50, $options = ['feedback' => 1000]) {
$this->generate();
}
/**
* Create vocabularies.
*
* @command devel-generate-vocabs
* @pluginId vocabulary
* @param $num Number of vocabularies to generate.
* @option kill Delete all vocabs before generating new ones.
* @aliases genv
* @validate-module-enabled taxonomy
*/
public function vocabs($num = 1, $options = ['kill' => FALSE]) {
$this->generate();
}
/**
* Create menus.
*
* @command devel-generate-menus
* @pluginId menu
* @param $number_menus Number of menus to generate.
* @param $number_links Number of links to generate.
* @param $max_depth Max link depth.
* @param $max_width Max width of first level of links.
* @option kill Delete all content before generating new content.
* @aliases genm
*/
public function menus($number_menus = 2, $number_links = 50, $max_depth = 3, $max_width = 8, $options = ['kill' => FALSE]) {
$this->generate();
}
/**
* Create content.
*
* @command devel-generate-content
* @pluginId content
* @param $num Number of nodes to generate.
* @param $max_comments Maximum number of comments to generate.
* @option kill Delete all content before generating new content.
* @option types A comma delimited list of content types to create. Defaults to page,article.
* @option feedback An integer representing interval for insertion rate logging.
* @option skip-fields A comma delimited list of fields to omit when generating random values
* @option languages A comma-separated list of language codes
* @aliases genc
* @validate-module-enabled node
*/
public function content($num = 50, $max_comments = 0, $options = ['kill' => FALSE, 'types' => 'page,article', 'feedback' => 1000]) {
$this->generate();
}
/**
* @hook validate
* @param \Consolidation\AnnotatedCommand\CommandData $commandData
* @return \Consolidation\AnnotatedCommand\CommandError|null
*/
public function validate(CommandData $commandData) {
$manager = $this->getManager();
$args = $commandData->input()->getArguments();
$commandName = array_shift($args);
/** @var DevelGenerateBaseInterface $instance */
$instance = $manager->createInstance($commandData->annotationData()->get('pluginId'), array());
$this->setPluginInstance($instance);
$parameters = $instance->validateDrushParams($args);
$this->setParameters($parameters);
}
public function generate() {
$instance = $this->getPluginInstance();
$instance->generate($this->getParameters());
}
}
\ No newline at end of file
......@@ -492,7 +492,7 @@ class ContentDevelGenerate extends DevelGenerateBase implements ContainerFactory
}
/**
* Retrive 50 uids from the database.
* Retrieve 50 uids from the database.
*/
protected function getUsers() {
$users = array();
......
services:
devel.command:
class: Drupal\devel\Commands\DevelCommands
arguments: ['@token', '@service_container', '@event_dispatcher']
tags:
- { name: drush.command }
......@@ -2,7 +2,8 @@
/**
* @file
* Drush integration for the devel module.
* This file is only used by Drush8. Drush9 discovers its commands via tagged
* service(s) in devel.services.yml. Also see classes in src/Commands.
*/
use Drupal\Component\Uuid\Php;
......@@ -160,6 +161,7 @@ function drush_devel_fn_event($event = NULL) {
drush_log(dt('No implementations.'), 'ok');
}
}
/**
* Command handler. Show source code of specified function or method.
*/
......
<?php
/**
* @file
* Generate PhpStorm metadata file.
*/
/**
* Implements of hook_drush_command().
*/
function phpstorm_drush_command() {
$items = array();
$items['phpstorm-metadata'] = array(
'description' => 'Save the PhpStorm Metadata file to Drupal root.',
'core' => array('8+'),
'aliases' => array('phpm'),
'category' => 'devel',
);
return $items;
}
/**
* Implements hook_drush_help_alter().
*/
function phpstorm_drush_help_alter(&$command) {
if ($command['command'] == 'cache-rebuild') {
$command['options']['storm'] = 'Write a new PHPstorm metadata file to Drupal root.';
}
}
/*
* Implements drush_hook_post_COMMAND().
*/
function drush_phpstorm_post_cache_rebuild() {
if (drush_get_option('storm')) {
drush_invoke_process('@self', 'phpstorm-metadata');
}
}
/**
* Generate PhpStorm Metadata file.
*
* @see http://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata
*/
function drush_phpstorm_metadata() {
$container = \Drupal::getContainer();
$reflectedClass = new ReflectionClass($container);
$map = array();
// Map for all services of the container.
// @see \Symfony\Component\DependencyInjection\Container::getServiceIds().
foreach ($reflectedClass->getMethods() as $method) {
if (preg_match('/^get(.+)Service$/', $method->name, $match)) {
$id = strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($match[1], '_', '.')));
$service = \Drupal::service($id);
if (is_object($service)) {
$map["\\Drupal::service('')"][$id] = '\\' . get_class($service);
}
}
}
// Entity Manager - getStorage
foreach (\Drupal::entityTypeManager()->getDefinitions() as $type => $definition) {
$class = Drupal::entityTypeManager()->getStorage($type);
$map["\\Drupal::entityManager()->getStorage('')"][$type] = '\\' . get_class($class);
$map["\\Drupal::entityTypeManager()->getStorage('')"][$type] = '\\' . get_class($class);
}
$content = _drush_phpstorm_metadata_phpstorm_metadata_template($map);
file_put_contents(DRUPAL_ROOT . '/.phpstorm.meta.php', $content);
}
function _drush_phpstorm_metadata_phpstorm_metadata_template($data) {
$file = '<?php
namespace PHPSTORM_META {
/** @noinspection PhpUnusedLocalVariableInspection */
/** @noinspection PhpIllegalArrayKeyTypeInspection */
$STATIC_METHOD_TYPES = [
';
foreach ($data as $method => $map) {
$file .= "\n";
$file .= " {$method} => [\n";
foreach ($map as $argument => $class) {
$file .= " '{$argument}' instanceof {$class},\n";
}
$file .= " ],";
$file .= "\n";
}
$file .= '
];
}
';
return $file;
}
<?php
namespace Drupal\devel\Commands;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Component\Uuid\Php;
use Drupal\Core\Utility\Token;
use Drush\Commands\DrushCommands;
use Drush\Exceptions\UserAbortException;
/**
* For commands that are parts of modules, Drush expects to find commandfiles in
* __MODULE__/src/Commands, and the namespace is Drupal/__MODULE__/Commands.
*
* In addition to a commandfile like this one, you need to add a drush.services.yml
* in root of your module like this module does.
*/
class DevelCommands extends DrushCommands {
protected $token;
protected $container;
protected $eventDispatcher;
public function __construct(Token $token, $container, $eventDispatcher) {
parent::__construct();
$this->token = $token;
$this->container = $container;
$this->eventDispatcher = $eventDispatcher;
}
/**
* @return mixed
*/
public function getEventDispatcher() {
return $this->eventDispatcher;
}
/**
* @return mixed
*/
public function getContainer() {
return $this->container;
}
/**
* @return Token
*/
public function getToken() {
return $this->token;
}
/**
* Uninstall, and Install a list of modules.
* @command devel-reinstall
* @param $modules A comma-separated list of module names.
* @aliases dre
* @allow-additional-options pm-uninstall,pm-enable
*/
public function reinstall($projects) {
$projects = _convert_csv_to_array($projects);
// This is faster than 3 separate bootstraps.
$args = array_merge(array('pm-uninstall'), $projects);
// @todo. Use $application dispatch instead of drush_invoke().
call_user_func_array('drush_invoke', $args);
$args = array_merge(array('pm-enable'), $projects);
call_user_func_array('drush_invoke', $args);
}
/**
* List implementations of a given hook and optionally edit one.
*
* @command devel-hook
* @param $hook The name of the hook to explore.
* @usage devel-hook cron
* List implementations of hook_cron().
* @aliases fnh,fn-hook,hook
*/
function hook($hook) {
// Get implementations in the .install files as well.
include_once './core/includes/install.inc';
drupal_load_updates();
if ($hook_implementations = \Drupal::moduleHandler()->getImplementations($hook)) {
if ($choice = drush_choice(array_combine($hook_implementations, $hook_implementations), 'Enter the number of the hook implementation you wish to view.')) {
$info= $this->codeLocate($choice . "_$hook");
$exec = drush_get_editor();
drush_shell_exec_interactive($exec, $info['file']);
}
}
else {
$this->logger()->success(dt('No implementations.'));
}
}
/**
* List implementations of a given event and optionally edit one.
*
* @command devel-event
* @param $event The name of the event to explore. If omitted, a list of events is shown.
* @usage devel-event
* Pick a Kernel event, then pick an implementation, and then view its source code.
* @usage devel-event kernel.terminate
* Pick a terminate subscribers and view its source code.
* @aliases fne,fn-event,event
*/
function event($event) {
$dispatcher = $this->getEventDispatcher();
if (empty($event)) {
// @todo Expand this list and move to interact().
$events = array('kernel.controller', 'kernel.exception', 'kernel.request', 'kernel.response', 'kernel.terminate', 'kernel.view');
$events = array_combine($events, $events);
if (!$event = drush_choice($events, 'Enter the event you wish to explore.')) {
throw new UserAbortException();
}
}
if ($implementations = $dispatcher->getListeners($event)) {
foreach ($implementations as $implementation) {
$callable = get_class($implementation[0]) . '::' . $implementation[1];
$choices[$callable] = $callable;
}
if ($choice = drush_choice($choices, 'Enter the number of the implementation you wish to view.')) {
$info= $this->codeLocate($choice);
$exec = drush_get_editor();
drush_shell_exec_interactive($exec, $info['file']);
}
}
else {
$this->logger()->success(dt('No implementations.'));
}
}