Commit 295c7613 authored by willzyx's avatar willzyx

Issue #2191395 by willzyx, lussoluca: Make dpm() and friends pluggable (with...

Issue #2191395 by willzyx, lussoluca: Make dpm() and friends pluggable (with Krumo, Kint, Ladybug etc)
parent 449d8ed0
......@@ -6,3 +6,4 @@ error_handlers:
rebuild_theme: FALSE
debug_mail_file_format: '%to-%subject-%datetime.mail.txt'
debug_mail_directory: 'temporary://devel-mails'
devel_dumper: 'default'
......@@ -27,6 +27,9 @@ devel.settings:
debug_mail_directory:
type: string
label: 'Mail debug directory'
devel_dumper:
type: string
label: 'Devel variable dumper'
block.settings.devel_switch_user:
type: block_settings
......
.devel-obj-output .field {
color: red;
}
.devel-obj-output dd {
display: block;
/**
* Dumpers
*/
.devel-dumper .details-wrapper{
max-height: 450px;
margin-right: 3px;
overflow: auto;
}
/**
* Switch User block
*/
......
<?php
/**
* @file
* Hooks for the devel module.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Alter devel dumper information declared by other modules.
*
* @param $info
* Devel dumper information to alter.
*/
function hook_devel_dumper_info_alter(&$info) {
$info['default']['label'] = 'Altered label';
}
/**
* @} End of "addtogroup hooks".
*/
......@@ -17,3 +17,16 @@ function devel_uninstall() {
}
}
/**
* Set the default devel dumper plugin.
*/
function devel_update_8001() {
$kint_enabled = \Drupal::moduleHandler()->moduleExists('kint');
$default_dumper = $kint_enabled ? 'kint' : 'default';
// Set the default dumper plugin to kint if kint module is available.
\Drupal::configFactory()->getEditable('devel.settings')
->set('devel_dumper', $default_dumper)
->save(TRUE);
}
This diff is collapsed.
......@@ -5,6 +5,14 @@ services:
tags:
- { name: event_subscriber }
plugin.manager.devel_dumper:
class: Drupal\devel\DevelDumperPluginManager
parent: default_plugin_manager
devel.dumper:
class: Drupal\devel\DevelDumperManager
arguments: ['@config.factory', '@current_user', '@plugin.manager.devel_dumper']
devel.route_subscriber:
class: Drupal\devel\Routing\RouteSubscriber
arguments: ['@entity_type.manager']
......
......@@ -56,5 +56,5 @@ function ksm() {
* Load the Kint class.
*/
function kint_require() {
require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'kint') . '/kint/Kint.class.php';
return require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'kint') . '/kint/Kint.class.php';
}
<?php
/**
* @file
* Contains \Drupal\kint\Plugin\Devel\Dumper\Kint.
*/
namespace Drupal\kint\Plugin\Devel\Dumper;
use Drupal\devel\DevelDumperBase;
/**
* Provides a Kint dumper plugin.
*
* @DevelDumper(
* id = "kint",
* label = @Translation("Kint"),
* description = @Translation("Wrapper for Kint debugging tool."),
* )
*/
class Kint extends DevelDumperBase {
/**
* Constructs a KintDevelDumper object.
*
* @TODO find another solution for kint class inclusion!
*/
public function __construct() {
kint_require();
}
/**
* {@inheritdoc}
*/
public function dump($input, $name = NULL) {
if ($name) {
$input = [(string) $name => $input];
}
\Kint::dump($input);
}
/**
* {@inheritdoc}
*/
public function export($input, $name = NULL) {
if ($name) {
$input = [(string) $name => $input];
}
$dump = @\Kint::dump($input);
return $this->setSafeMarkup($dump);
}
/**
* {@inheritdoc}
*/
public static function checkRequirements() {
return kint_require();
}
}
<?php
/**
* @file
* Contains \Drupal\devel\Annotation\DevelDumper.
*/
namespace Drupal\devel\Annotation;
use Drupal\Component\Annotation\Plugin;
/**
* Defines a DevelDumper annotation object.
*
* @Annotation
*
* @see \Drupal\devel\DevelDumperPluginManager
* @see \Drupal\devel\DevelDumperInterface
* @see \Drupal\devel\DevelDumperBase
* @see plugin_api
*/
class DevelDumper extends Plugin {
/**
* The plugin ID.
*
* @var string
*/
public $id;
/**
* The human-readable name of the DevelDumper type.
*
* @ingroup plugin_translatable
*
* @var \Drupal\Core\Annotation\Translation
*/
public $label;
/**
* A short description of the DevelDumper type.
*
* @ingroup plugin_translatable
*
* @var \Drupal\Core\Annotation\Translation
*/
public $description;
}
<?php
/**
* @file
* Contains \Drupal\devel\DevelDumperBase.
*/
namespace Drupal\devel;
use Drupal\Core\Render\Markup;
use Drupal\Core\Plugin\PluginBase;
/**
* Defines a base devel dumper implementation.
*
* @see \Drupal\devel\Annotation\DevelDumper
* @see \Drupal\devel\DevelDumperInterface
* @see \Drupal\devel\DevelDumperPluginManager
* @see plugin_api
*/
abstract class DevelDumperBase extends PluginBase implements DevelDumperInterface {
/**
* {@inheritdoc}
*/
public function exportAsRenderable($input, $name = NULL) {
return ['#markup' => $this->export($input, $name)];
}
/**
* Wrapper for \Drupal\Core\Render\Markup::create().
*
* @param string $input
* The input string to mark as safe.
*
* @return string
* The unaltered input value.
*/
protected function setSafeMarkup($input) {
return Markup::create($input);
}
}
<?php
/**
* @file
* Contains \Drupal\devel\DevelDumperInterface.
*/
namespace Drupal\devel;
/**
* Base interface definition for DevelDumper plugins.
*
* @see \Drupal\devel\Annotation\DevelDumper
* @see \Drupal\devel\DevelDumperPluginManager
* @see \Drupal\devel\DevelDumperBase
* @see plugin_api
*/
interface DevelDumperInterface {
/**
* Dumps information about a variable.
*
* @param mixed $input
* The variable to dump.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
*/
public function dump($input, $name = NULL);
/**
* Returns a string representation of a variable.
*
* @param mixed $input
* The variable to export.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
*
* @return string
* String representation of a variable.
*/
public function export($input, $name = NULL);
/**
* Returns a string representation of a variable wrapped in a render array.
*
* @param mixed $input
* The variable to export.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
*
* @return array
* String representation of a variable wrapped in a render array.
*/
public function exportAsRenderable($input, $name = NULL);
/**
* Checks if requirements for this plugin are satisfied.
*
* @return bool
* TRUE is requirements are satisfied, FALSE otherwise.
*/
public static function checkRequirements();
}
<?php
/**
* @file
* Contains \Drupal\devel\DevelDumperManager.
*/
namespace Drupal\devel;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Session\AccountProxyInterface;
/**
* Class DevelDumperManager
*/
class DevelDumperManager implements DevelDumperManagerInterface {
/**
* The devel config.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**
* The current account.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $account;
/**
* The devel dumper plugin manager.
*
* @var \Drupal\devel\DevelDumperPluginManagerInterface
*/
protected $dumperManager;
/**
* Constructs a DevelDumperPluginManager object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\Core\Session\AccountProxyInterface $account
* The current account.
* @param \Drupal\devel\DevelDumperPluginManagerInterface $dumper_manager
* The devel dumper plugin manager.
*/
public function __construct(ConfigFactoryInterface $config_factory, AccountProxyInterface $account, DevelDumperPluginManagerInterface $dumper_manager) {
$this->config = $config_factory->get('devel.settings');
$this->account = $account;
$this->dumperManager = $dumper_manager;
}
/**
* Instances a new dumper plugin.
*
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*
* @return \Drupal\devel\DevelDumperInterface
* Returns the devel dumper plugin instance.
*/
protected function createInstance($plugin_id = NULL) {
if (!$plugin_id || !$this->dumperManager->isPluginSupported($plugin_id)) {
$plugin_id = $this->config->get('devel_dumper');
}
return $this->dumperManager->createInstance($plugin_id);
}
/**
* {@inheritdoc}
*/
public function dump($input, $name = NULL, $plugin_id = NULL) {
if ($this->hasAccessToDevelInformation()) {
$this->createInstance($plugin_id)->dump($input, $name);
}
}
/**
* {@inheritdoc}
*/
public function export($input, $name = NULL, $plugin_id = NULL) {
if ($this->hasAccessToDevelInformation()) {
return $this->createInstance($plugin_id)->export($input, $name);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function message($input, $name = NULL, $type = 'status', $plugin_id = NULL) {
if ($this->hasAccessToDevelInformation()) {
$output = $this->export($input, $name, $plugin_id);
drupal_set_message($output, $type, TRUE);
}
}
/**
* {@inheritdoc}
*/
public function debug($input, $name = NULL, $plugin_id = NULL) {
$name = $name ? $name . ': ' : '';
$output = $this->export($input, $name, $plugin_id) . "\n";
// The temp directory does vary across multiple simpletest instances.
$file = file_directory_temp() . '/drupal_debug.txt';
if (file_put_contents($file, $output, FILE_APPEND) === FALSE && $this->hasAccessToDevelInformation()) {
drupal_set_message(t('Devel was unable to write to %file.', ['%file' => $file]), 'error');
return FALSE;
}
}
/**
* {@inheritdoc}
*/
public function dumpOrExport($input, $name = NULL, $export = TRUE, $plugin_id = NULL) {
if ($this->hasAccessToDevelInformation()) {
$dumper = $this->createInstance($plugin_id);
if ($export) {
return $dumper->export($input, $name);
}
$dumper->dump($input, $name);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function exportAsRenderable($input, $name = NULL, $plugin_id = NULL) {
if ($this->hasAccessToDevelInformation()) {
return $this->createInstance($plugin_id)->exportAsRenderable($input, $name);
}
return [];
}
/**
* Checks whether a user has access to devel information.
*
* @return bool
* TRUE if the user has the permission, FALSE otherwise.
*/
protected function hasAccessToDevelInformation() {
return $this->account && $this->account->hasPermission('access devel information');
}
}
<?php
/**
* @file
* Contains \Drupal\devel\DevelDumperManagerInterface.
*/
namespace Drupal\devel;
/**
* Interface DevelDumperManagerInterface
*/
interface DevelDumperManagerInterface {
/**
* Dumps information about a variable.
*
* @param mixed $input
* The variable to dump.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*/
public function dump($input, $name = NULL, $plugin_id = NULL);
/**
* Returns a string representation of a variable.
*
* @param mixed $input
* The variable to dump.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*
* @return string
* String representation of a variable.
*/
public function export($input, $name = NULL, $plugin_id = NULL);
/**
* Sets a message with a string representation of a variable.
*
* @param mixed $input
* The variable to dump.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
* @param string $type
* (optional) The message's type. Defaults to 'status'.
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*/
public function message($input, $name = NULL, $type = 'status', $plugin_id = NULL);
/**
* Logs a variable to a drupal_debug.txt in the site's temp directory.
*
* @param mixed $input
* The variable to log to the drupal_debug.txt log file.
* @param string $name
* (optional) If set, a label to output before $data in the log file.
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*
* @return void|false
* Empty if successful, FALSE if the log file could not be written.
*
* @see dd()
* @see http://drupal.org/node/314112
*/
public function debug($input, $name = NULL, $plugin_id = NULL);
/**
* Wrapper for ::dump() and ::export().
*
* @param mixed $input
* The variable to dump.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
* @param bool $export
* (optional) Whether return string representation of a variable.
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*
* @return string|null
* String representation of a variable if $export is set to TRUE,
* NULL otherwise.
*/
public function dumpOrExport($input, $name = NULL, $export = TRUE, $plugin_id = NULL);
/**
* Returns a render array representation of a variable.
*
* @param mixed $input
* The variable to export.
* @param string $name
* (optional) The label to output before variable, defaults to NULL.
* @param string $plugin_id
* (optional) The plugin ID, defaults to NULL.
*
* @return array
* String representation of a variable wrapped in a render array.
*/
public function exportAsRenderable($input, $name = NULL, $plugin_id = NULL);
}
<?php
/**
* @file
* Contains \Drupal\devel\DevelDumperPluginManager.
*/
namespace Drupal\devel;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\devel\Annotation\DevelDumper;
/**
* Plugin type manager for Devel Dumper plugins.
*
* @see \Drupal\devel\Annotation\DevelDumper
* @see \Drupal\devel\DevelDumperInterface
* @see \Drupal\devel\DevelDumperBase
* @see plugin_api
*/
class DevelDumperPluginManager extends DefaultPluginManager implements DevelDumperPluginManagerInterface {
/**
* Constructs a DevelDumperPluginManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
parent::__construct('Plugin/Devel/Dumper', $namespaces, $module_handler, DevelDumperInterface::class, DevelDumper::class);
$this->setCacheBackend($cache_backend, 'devel_dumper_plugins');
$this->alterInfo('devel_dumper_info');
}
/**
* {@inheritdoc}
*/
public function processDefinition(&$definition, $plugin_id) {
parent::processDefinition($definition, $plugin_id);
$definition['supported'] = (bool) call_user_func([$definition['class'], 'checkRequirements']);
}
/**
* {@inheritdoc}
*/
public function isPluginSupported($plugin_id) {
$definition = $this->getDefinition($plugin_id, FALSE);
return $definition && $definition['supported'];
}
/**
* {@inheritdoc}
*/
public function createInstance($plugin_id, array $configuration = []) {
if (!$this->isPluginSupported($plugin_id)) {
$plugin_id = $this->getFallbackPluginId($plugin_id);
}
return parent::createInstance($plugin_id, $configuration);
}
/**
* {@inheritdoc}
*/
public function getFallbackPluginId($plugin_id, array $configuration = []) {
return 'default';
}
}
<?php
/**
* @file
* Contains \Drupal\devel\DevelDumperPluginManagerInterface.
*/
namespace Drupal\devel;
use Drupal\Component\Plugin\FallbackPluginManagerInterface;
use Drupal\Component\Plugin\PluginManagerInterface;
/**
* Interface DevelDumperPluginManagerInterface.
*/
interface DevelDumperPluginManagerInterface extends PluginManagerInterface, FallbackPluginManagerInterface {
/**
* Checks if plugin has a definition and is supported.
*
* @param string $plugin_id
* The ID of the plugin to check.
*
* @return bool
* TRUE if the plugin is supported, FALSE otherwise.
*/
public function isPluginSupported($plugin_id);
}
......@@ -75,7 +75,7 @@ class DevelEventSubscriber implements EventSubscriberInterface {
}
else {
$firephp_path = DRUPAL_ROOT . '/libraries/FirePHPCore/lib/FirePHPCore/';
$chromephp_path = './' . drupal_get_path('module', 'devel') . '/chromephp';
$chromephp_path = DRUPAL_ROOT . '/libraries/chromephp';
}
// Include FirePHP if it exists.
......@@ -91,7 +91,6 @@ class DevelEventSubscriber implements EventSubscriberInterface {
}
if ($this->config->get('rebuild_theme')) {
drupal_theme_rebuild();
......
......@@ -8,6 +8,8 @@
namespace Drupal\devel\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\devel\DevelDumperPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
......@@ -17,6 +19,32 @@ use Drupal\Core\Url;
*/
class SettingsForm extends ConfigFormBase {
/**
* Devel Dumper Plugin Manager.
*
* @var \Drupal\devel\DevelDumperPluginManager
*/
protected $dumperManager;
/**
* Constructs a new SettingsForm object.
*
* @param \Drupal\devel\DevelDumperPluginManagerInterface $devel_dumper_manager
* Devel Dumper Plugin Manager.
*/
public function __construct(DevelDumperPluginManagerInterface $devel_dumper_manager) {
$this->dumperManager = $devel_dumper_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.devel_dumper')
);
}