Skip to content
Snippets Groups Projects
Commit 647c9785 authored by Nia Kathoni's avatar Nia Kathoni Committed by Daniel Cothran
Browse files

Issue #3390738 by nikathone, andileco, diaodiallo: Dynamically hide chart...

Issue #3390738 by nikathone, andileco, diaodiallo: Dynamically hide chart types that are not available for the selected library
parent b795a281
No related branches found
No related tags found
1 merge request!73Issue #3390738 by diaodiallo: Dynamically hide chart types that are not...
Pipeline #59758 passed with warnings
Showing
with 651 additions and 33 deletions
......@@ -161,3 +161,22 @@ function charts_post_update_resave_views_to_account_calculated_library_dependenc
}
return t('This site did not have any chart related views.');
}
/**
* Setting charts config module dependencies based on the selected library.
*/
function charts_post_update_setting_charts_config_module_dependencies(&$sandbox) {
$config = \Drupal::service('config.factory')
->getEditable('charts.settings');
$settings = $config->get('charts_default_settings');
$library = $settings['library'] ?? '';
$type = $settings['type'] ?? '';
if ($library || $type) {
/** @var \Drupal\charts\EventSubscriber\ConfigImportSubscriber $config_import_subscriber */
$config_import_subscriber = \Drupal::service('charts.config_import_subscriber');
$config->set('dependencies', $config_import_subscriber->calculateDependencies($library, $type))
->save();
return 'Updated chart settings dependencies';
}
return 'The default config for charts did not have a library and type set. So no dependencies were set.';
}
......@@ -2,6 +2,20 @@ services:
plugin.manager.charts:
class: Drupal\charts\ChartManager
parent: default_plugin_manager
plugin.manager.charts_type:
class: Drupal\charts\TypeManager
arguments: ['@module_handler', '@cache.discovery', '@event_dispatcher']
charts.plugins_uninstall_validator:
class: Drupal\charts\PluginsUninstallValidator
tags:
- { name: module_install.uninstall_validator }
arguments: ['@config.factory']
lazy: true
charts.config_import_subscriber:
class: Drupal\charts\EventSubscriber\ConfigImportSubscriber
arguments: ['@plugin.manager.charts', '@plugin.manager.charts_type']
tags:
- { name: event_subscriber }
dependencies: []
charts_default_settings:
library: ''
type: line
......
......@@ -19,3 +19,6 @@ charts.settings:
cdn:
type: boolean
label: 'Check if CDN is being used for external libraries'
dependencies:
type: config_dependencies
label: 'Dependencies'
......@@ -9,8 +9,8 @@ use Drupal\Core\Plugin\DefaultPluginManager;
/**
* Chart Manager.
*
* Provides the Chart plugin plugin manager and manages discovery and
* instantiation of chart plugins.
* Provides the Chart plugin manager and manages discovery and instantiation of
* chart plugins.
*/
class ChartManager extends DefaultPluginManager {
......
<?php
namespace Drupal\charts;
/**
* Provide method to calculate dependencies for charts config.
*/
trait DependenciesCalculatorTrait {
/**
* The chart library plugin manager.
*
* @var \Drupal\charts\ChartManager
*/
protected $chartPluginManager;
/**
* The chart type plugin library manager.
*
* @var \Drupal\charts\TypeManager
*/
protected $chartTypePluginManager;
/**
* Calculates the dependencies given the chart library and chart type.
*
* @param string $chart_library_id
* The chart library plugin id.
* @param string $chart_type_id
* The chart type plugin id.
*
* @return array
* The calculated dependencies.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function calculateDependencies(string $chart_library_id, string $chart_type_id):array {
$calculated_dependencies = [];
$dependent_modules = [];
if ($chart_library_id) {
// Getting charting library provider and set it as one of the
// dependencies for the chart settings.
$plugin_definition = $this->chartPluginManager()->getDefinition($chart_library_id);
$dependent_modules = [$plugin_definition['provider']];
}
if ($chart_type_id) {
// Do the same thing for the chart type unless it was added by the main
// "charts" module.
$plugin_definition = $this->chartTypePluginManager()->getDefinition($chart_type_id);
$provider = $plugin_definition['provider'];
if ($provider !== 'charts' && !in_array($provider, $dependent_modules)) {
$dependent_modules[] = $provider;
}
}
if ($dependent_modules) {
$calculated_dependencies = ['module' => $dependent_modules];
}
return $calculated_dependencies;
}
/**
* Initialize the chart plugin manager if needed.
*
* @return \Drupal\charts\ChartManager
* The chart manager plugin.
*/
private function chartPluginManager(): ChartManager {
if (!isset($this->chartPluginManager)) {
$this->chartPluginManager = \Drupal::service('plugin.manager.charts');
}
return $this->chartPluginManager;
}
/**
* Initialize the chart type plugin manager if needed.
*
* @return \Drupal\charts\TypeManager
* The chart type manager plugin.
*/
private function chartTypePluginManager(): TypeManager {
if (!isset($this->chartTypePluginManager)) {
$this->chartTypePluginManager = \Drupal::service('plugin.manager.charts_type');
}
return $this->chartTypePluginManager;
}
}
......@@ -116,11 +116,24 @@ class BaseSettings extends FormElement {
$required = !empty($element['#required']) ? $element['#required'] : FALSE;
$options = $value;
$library_options = [];
if ($used_in !== 'config_form') {
$library_options['site_default'] = new TranslatableMarkup('Site Default');
$library_options = self::getLibraries();
if ($used_in !== 'config_form' && $library_options) {
$library_options = [
'site_default' => new TranslatableMarkup('Site Default'),
] + $library_options;
}
if (!$library_options) {
$element['no_chart_plugin_error'] = [
'#type' => 'container',
'#attributes' => [
'class' => ['messages', 'messages--error'],
],
'content' => [
'#markup' => new TranslatableMarkup('<p>Please <a href="/admin/modules">install</a> at least one module that implements a chart library plugin.</p>'),
],
];
return $element;
}
$library_options += self::getLibraries();
if (!empty($element['#library']) && isset($library_options[$element['#library']])) {
$element['library'] = [
......@@ -143,14 +156,22 @@ class BaseSettings extends FormElement {
'wrapper' => $wrapper_id,
],
];
$selected_library = $options['library'];
$selected_library = $options['library'] ?: array_key_first($library_options);
}
// Making sure that the selected chart type is part of chart type options
// associated with the library.
$chart_type_options = self::getChartTypes($selected_library);
$selected_chart_type = $options['type'] ?? '';
if (!isset($chart_type_options[$selected_chart_type])) {
$selected_chart_type = NULL;
}
$element['type'] = [
'#title' => new TranslatableMarkup('Chart type'),
'#type' => 'radios',
'#default_value' => $options['type'],
'#options' => self::getChartTypes($selected_library),
'#default_value' => $selected_chart_type,
'#options' => $chart_type_options,
'#access' => !empty($chart_type_options),
'#required' => $required,
'#attributes' => [
'class' => [
......@@ -160,6 +181,18 @@ class BaseSettings extends FormElement {
],
];
if (!$chart_type_options) {
$error_message = $selected_library !== 'site_default' ?
new TranslatableMarkup('<p>The selected chart library does not have valid chart type options. Please select another charting library or install a module that have chart type options.</p>') :
new TranslatableMarkup('<p>The site default charting library has not been set yet, or it does not support chart type options. Please ensure that you have correctly <a href="/admin/config/content/charts">configured the chart module</a>.</p>');
$element['no_chart_type_plugin_error'] = [
'#type' => 'container',
'#attributes' => ['class' => ['messages', 'messages--error']],
'content' => ['#markup' => $error_message],
];
return $element;
}
if (!empty($element['#series'])) {
$element = self::processSeriesForm($element, $options, $form_state);
}
......@@ -499,8 +532,8 @@ class BaseSettings extends FormElement {
],
];
if ($used_in === 'config_form' && !empty($options['library'])) {
$element = self::buildLibraryConfigurationForm($element, $form_state, $options['library']);
if ($used_in === 'config_form' && $selected_library) {
$element = self::buildLibraryConfigurationForm($element, $form_state, $selected_library);
}
return $element;
......@@ -586,17 +619,20 @@ class BaseSettings extends FormElement {
}
/**
* The types of chart.
* Gets chart types by chart library.
*
* @param string $library
* @param string $library_plugin_id
* The library.
*
* @return array
* The type options.
*/
public static function getChartTypes(string $library = ''): array {
if (!$library) {
\Drupal::logger('charts')->warning('Update your custom code to pass the library in getChartTypes().');
public static function getChartTypes(string $library_plugin_id = ''): array {
if ($library_plugin_id === 'site_default') {
$library_plugin_id = static::getConfiguredSiteDefaultLibraryId();
}
if (!$library_plugin_id) {
\Drupal::logger('charts')->error('Update your custom code to pass the library in getChartTypes() or install a module that implement a charting library plugin.');
return [];
}
......@@ -604,7 +640,7 @@ class BaseSettings extends FormElement {
$chart_plugin_manager = \Drupal::service('plugin.manager.charts');
/** @var \Drupal\charts\Plugin\chart\Library\ChartInterface $chart_plugin */
$chart_plugin = $chart_plugin_manager->createInstance($library, []);
$chart_plugin = $chart_plugin_manager->createInstance($library_plugin_id, []);
$chart_type_plugin_definitions = $chart_type_plugin_manager->getDefinitions();
$types_options = [];
......@@ -617,6 +653,17 @@ class BaseSettings extends FormElement {
return $types_options;
}
/**
* Gets the configured site default library chart plugin id.
*
* @return string
* The plugin id or an empty string if nothing has been configured.
*/
public static function getConfiguredSiteDefaultLibraryId(): string {
$chart_config = \Drupal::config('charts.settings');
return $chart_config->get('charts_default_settings.library') ?? '';
}
/**
* Attaches the #charts_library_settings_element_submit functionality.
*
......@@ -1392,7 +1439,7 @@ class BaseSettings extends FormElement {
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
private static function buildLibraryConfigurationForm(array $element, FormStateInterface $form_state, $library) {
private static function buildLibraryConfigurationForm(array $element, FormStateInterface $form_state, string $library) {
$plugin_configuration = $element['#value']['library_config'] ?? [];
// Using plugins to get the available installed libraries.
/** @var \Drupal\charts\ChartManager $plugin_manager */
......
......@@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* @RenderElement("chart")
*/
class Chart extends RenderElement implements ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
......@@ -52,7 +53,7 @@ class Chart extends RenderElement implements ContainerFactoryPluginInterface {
protected $moduleHandler;
/**
* Constructs Chart object.
* Constructs a Chart object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
......@@ -191,7 +192,7 @@ class Chart extends RenderElement implements ContainerFactoryPluginInterface {
}
$this->moduleHandler->alter($alter_hooks, $element, $chart_id);
// Include the library specific render callback via their plugin manager.
// Include the library-specific render callback via their plugin manager.
// Use the first charting library if the requested library is not available.
$library = $element['#chart_library'] ?? '';
$library = $this->getLibrary($library);
......@@ -202,12 +203,8 @@ class Chart extends RenderElement implements ContainerFactoryPluginInterface {
/** @var \Drupal\charts\Plugin\chart\Library\ChartInterface $plugin */
$plugin = $this->chartsManager->createInstance($library, $plugin_configuration);
if (!$plugin->isSupportedChartType($type_name)) {
return [
'#markup' => $this->t('Chart type @type not supported by @plugin', [
'@type' => $type_name,
'@plugin' => $plugin->getChartName(),
]),
];
// Chart type not supported by the library.
throw new \LogicException(sprintf('The provided chart type "%s" is not supported by "%s" chart plugin library.', $type_name, $plugin->getChartName()));
}
$element = $plugin->preRender($element);
......
<?php
namespace Drupal\charts\EventSubscriber;
use Drupal\charts\ChartManager;
use Drupal\charts\DependenciesCalculatorTrait;
use Drupal\charts\TypeManager;
use Drupal\Core\Config\ConfigEvents;
use Drupal\Core\Config\ConfigImporterEvent;
use Drupal\Core\Config\StorageTransformEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Ensure charts settings are calculated when configurations are imported.
*/
class ConfigImportSubscriber implements EventSubscriberInterface {
use DependenciesCalculatorTrait;
/**
* Constructs a ConfigImportSubscriber instance.
*
* @param \Drupal\charts\ChartManager $chart_manager
* The chart library plugin manager.
* @param \Drupal\charts\TypeManager $chart_type_manager
* The chart type plugin manager.
*/
public function __construct(ChartManager $chart_manager, TypeManager $chart_type_manager) {
$this->chartPluginManager = $chart_manager;
$this->chartTypePluginManager = $chart_type_manager;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
ConfigEvents::STORAGE_TRANSFORM_IMPORT => ['onImportTransform'],
// There is no specific reason for choosing 50 beside it should be
// executed before \Drupal\Core\EventSubscriber::onConfigImporterImport()
// set at 40.
ConfigEvents::IMPORT => ['onConfigImporterImport', 50],
];
}
/**
* Ensure the config dependencies are calculated for charts settings.
*
* @param \Drupal\Core\Config\ConfigImporterEvent $event
* The event to process.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function onConfigImporterImport(ConfigImporterEvent $event) {
$config_importer = $event->getConfigImporter();
$storage_comparer = $config_importer->getStorageComparer();
$source_storage = $storage_comparer->getSourceStorage();
$charts_config = $source_storage->read('charts.settings');
if ($settings = $charts_config['charts_default_settings'] ?? []) {
$target_storage = $storage_comparer->getTargetStorage();
$library = $settings['library'] ?? '';
$type = $settings['type'] ?? '';
$charts_config['dependencies'] = $this->calculateDependencies($library, $type);
$target_storage->write('charts.settings', $charts_config);
}
}
/**
* Acts when the storage is transformed for import.
*
* @param \Drupal\Core\Config\StorageTransformEvent $event
* The config storage transform event.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function onImportTransform(StorageTransformEvent $event) {
$storage = $event->getStorage();
if ($charts_config = $storage->read('charts.settings')) {
$settings = $charts_config['charts_default_settings'];
$library = $settings['library'] ?? '';
$type = $settings['type'] ?? '';
$charts_config['dependencies'] = $this->calculateDependencies($library, $type);
$storage->write('charts.settings', $charts_config);
}
}
}
......@@ -2,10 +2,15 @@
namespace Drupal\charts\Form;
use Drupal\charts\ChartManager;
use Drupal\charts\DependenciesCalculatorTrait;
use Drupal\charts\TypeManager;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Serialization\Yaml;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -13,6 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class ChartsConfigForm extends ConfigFormBase {
use DependenciesCalculatorTrait;
/**
* The cache tags invalidator.
*
......@@ -20,6 +27,27 @@ class ChartsConfigForm extends ConfigFormBase {
*/
protected $cacheTagsInvalidator;
/**
* The chart library plugin manager.
*
* @var \Drupal\charts\ChartManager
*/
protected $chartPluginManager;
/**
* The chart type plugin library manager.
*
* @var \Drupal\charts\TypeManager
*/
protected $chartTypePluginManager;
/**
* The module extension service.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleExtensionList;
/**
* Constructs a new ChartsConfigForm.
*
......@@ -27,10 +55,21 @@ class ChartsConfigForm extends ConfigFormBase {
* Config factory.
* @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
* Cache tag invalidator.
* @param \Drupal\charts\ChartManager|null $chart_plugin_manager
* The chart plugin manager.
* @param \Drupal\charts\TypeManager|null $chart_type_plugin_manager
* The chart type plugin manager.
* @param \Drupal\Core\Extension\ModuleExtensionList|null $module_extension_list
* The module extension list.
*/
public function __construct(ConfigFactoryInterface $config_factory, CacheTagsInvalidatorInterface $cache_tags_invalidator) {
public function __construct(ConfigFactoryInterface $config_factory, CacheTagsInvalidatorInterface $cache_tags_invalidator, ChartManager $chart_plugin_manager = NULL, TypeManager $chart_type_plugin_manager = NULL, ModuleExtensionList $module_extension_list = NULL) {
parent::__construct($config_factory);
$this->cacheTagsInvalidator = $cache_tags_invalidator;
// @todo Implement full if statement for optional parameters, and add
// deprecation warnings when they are not passed.
$this->chartPluginManager = $chart_plugin_manager ?: \Drupal::service('plugin.manager.charts');
$this->chartTypePluginManager = $chart_type_plugin_manager ?: \Drupal::service('plugin.manager.charts_type');
$this->moduleExtensionList = $module_extension_list ?: \Drupal::service('extension.list.module');
}
/**
......@@ -39,7 +78,10 @@ class ChartsConfigForm extends ConfigFormBase {
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('cache_tags.invalidator')
$container->get('cache_tags.invalidator'),
$container->get('plugin.manager.charts'),
$container->get('plugin.manager.charts_type'),
$container->get('extension.list.module')
);
}
......@@ -80,9 +122,28 @@ class ChartsConfigForm extends ConfigFormBase {
'#default_value' => $default_config,
];
$form['actions']['reset_to_default'] = [
'#type' => 'submit',
'#submit' => ['::submitReset'],
'#value' => $this->t('Reset to default configurations'),
'#weight' => 100,
'#access' => !empty($default_config['library']),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$settings = $form_state->getValue('settings');
if (empty($settings['library'])) {
$form_state->setError($form['settings'], $this->t('Please select a library to use by default or install a module implementing a chart library plugin.'));
}
parent::validateForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
......@@ -100,7 +161,8 @@ class ChartsConfigForm extends ConfigFormBase {
// Save the main settings.
$config = $this->config('charts.settings');
$config->set('charts_default_settings', $settings)
$config->set('dependencies', $this->calculateDependencies($settings['library'], $settings['type']))
->set('charts_default_settings', $settings)
->save();
// Invalidate cache tags to refresh any view relying on this.
......@@ -109,4 +171,29 @@ class ChartsConfigForm extends ConfigFormBase {
parent::submitForm($form, $form_state);
}
/**
* Reset submit callback.
*
* @param array $form
* The form structure.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function submitReset(array &$form, FormStateInterface $form_state) {
$path = $this->moduleExtensionList->getPath('charts');
$default_install_settings_file = $path . '/config/install/charts.settings.yml';
if (!file_exists($default_install_settings_file)) {
$this->messenger()->addWarning($this->t('We could not reset the configuration to default because the default settings file does not exist. Please re-download the charts module files.'));
return;
}
$config = $this->config('charts.settings');
$default_install_settings = Yaml::decode(file_get_contents($default_install_settings_file));
$config->set('charts_default_settings', $default_install_settings['charts_default_settings'])
->set('dependencies', $default_install_settings['dependencies'])
->save();
$this->messenger()->addStatus($this->t('The charts configuration were successfully reset to default.'));
}
}
......@@ -4,6 +4,7 @@ namespace Drupal\charts\Plugin\views\style;
use Drupal\charts\ChartManager;
use Drupal\charts\ChartViewsFieldInterface;
use Drupal\charts\Element\BaseSettings;
use Drupal\charts\Plugin\chart\Library\ChartInterface;
use Drupal\charts\TypeManager;
use Drupal\Component\Serialization\Json;
......@@ -141,7 +142,9 @@ class ChartsPluginStyleChart extends StylePluginBase implements ContainerFactory
// @todo ensure that chart extensions inherit defaults from parent
// Remove the default setting for chart type so it can be inherited if this
// is a chart extension type.
if ($this->view->style_plugin === 'chart_extension') {
$style_plugin = $this->view->style_plugin ?? NULL;
$style_plugin_id = $style_plugin ? $style_plugin->getPluginId() : '';
if ($style_plugin_id === 'chart_extension') {
$options['chart_settings']['default']['type'] = NULL;
}
$options['path'] = ['default' => 'charts'];
......@@ -157,7 +160,7 @@ class ChartsPluginStyleChart extends StylePluginBase implements ContainerFactory
$handlers = $this->displayHandler->getHandlers('field');
if (empty($handlers)) {
$form['error_markup'] = ['#markup' => '<div class="error messages">' . $this->t('You need at least one field before you can configure your table settings') . '</div>'];
$form['error_markup'] = ['#markup' => '<div class="error messages">' . $this->t('You need at least one field before you can configure your chart settings') . '</div>'];
return;
}
......@@ -197,13 +200,58 @@ class ChartsPluginStyleChart extends StylePluginBase implements ContainerFactory
];
}
/**
* {@inheritdoc}
*/
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
if (!$form_state->hasValue(['style_options', 'chart_settings'])) {
return;
}
$chart_settings = $form_state->getValue(['style_options', 'chart_settings']);
$selected_library_id = $chart_settings['library'] ?? '';
if (empty($chart_settings['library'])) {
$form_state->setError($form['chart_settings'], $this->t('Please select a valid charting library or <a href="/admin/modules">install</a> at least one module that implements a chart library plugin.'));
return;
}
if (($selected_library_id === 'site_default' && !BaseSettings::getConfiguredSiteDefaultLibraryId()) || empty($chart_settings['type'])) {
$destination = '/admin/structure/views/view/' . $this->view->storage->id();
if ($this->view->current_display) {
$destination .= '/' . $this->view->current_display;
}
$form_state->setError($form['chart_settings'], $this->t('The site default charting library has not been set yet, or it does not support chart type options. Please ensure that you have correctly <a href="@url">configured the chart module</a>.', [
'@url' => '/admin/config/content/charts?destination=' . $destination,
]));
}
}
/**
* {@inheritdoc}
*/
public function validate() {
$errors = parent::validate();
$chart_settings = $this->options['chart_settings'];
$selected_data_fields = !empty($chart_settings['fields']['data_providers']) && is_array($chart_settings['fields']['data_providers']) ? $this->getSelectedDataFields($chart_settings['fields']['data_providers']) : NULL;
$selected_library_id = $chart_settings['library'] ?? '';
if (!$selected_library_id) {
$errors[] = $this->t('Please select a valid charting library.');
return $errors;
}
if ($selected_library_id === 'site_default' && !BaseSettings::getConfiguredSiteDefaultLibraryId()) {
$destination = '/admin/structure/views/view/' . $this->view->storage->id();
if ($this->view->current_display) {
$destination .= '/' . $this->view->current_display;
}
$errors[] = $this->t('The site default charting library has not been set yet, or it does not support chart type options. Please ensure that you have correctly <a href="@url">configured the chart module</a>.', [
'@url' => '/admin/config/content/charts?destination=' . $destination,
]);
return $errors;
}
$selected_data_fields = !empty($chart_settings['fields']['data_providers']) && is_array($chart_settings['fields']['data_providers']) ?
$this->getSelectedDataFields($chart_settings['fields']['data_providers']) : NULL;
// Avoid calling validation before arriving at the view edit page.
if ($this->routeMatch->getRouteName() != 'views_ui.add' && empty($selected_data_fields)) {
......
<?php
namespace Drupal\charts;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Prevents uninstalling of a module providing default chart library plugin.
*/
class PluginsUninstallValidator implements ModuleUninstallValidatorInterface {
use StringTranslationTrait;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Constructs a new ChartsPluginsUninstallValidator.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
*/
public function __construct(ConfigFactoryInterface $config_factory) {
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public function validate($module) {
$reasons = [];
$config = $this->configFactory->get('charts.settings');
$dependent_modules = $config->get('dependencies.module') ?? [];
if (in_array($module, $dependent_modules)) {
$reasons[] = $this->t('Provides a chart library or chart type plugin configured as the default option for chart. Please update <a href="/admin/config/content/charts?destination=/admin/modules/uninstall">the configuration</a> or reset them before uninstalling it.');
}
return $reasons;
}
}
<?php
// phpcs:ignoreFile
/**
* This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\charts\PluginsUninstallValidator' "web/modules/custom/charts/src".
*/
namespace Drupal\charts\ProxyClass {
/**
* Provides a proxy class for \Drupal\charts\PluginsUninstallValidator.
*
* @see \Drupal\Component\ProxyBuilder
*/
class PluginsUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
{
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
/**
* The id of the original proxied service.
*
* @var string
*/
protected $drupalProxyOriginalServiceId;
/**
* The real proxied service, after it was lazy loaded.
*
* @var \Drupal\charts\PluginsUninstallValidator
*/
protected $service;
/**
* The service container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* Constructs a ProxyClass Drupal proxy object.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param string $drupal_proxy_original_service_id
* The service ID of the original service.
*/
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
{
$this->container = $container;
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
}
/**
* Lazy loads the real service from the container.
*
* @return object
* Returns the constructed real service.
*/
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
}
return $this->service;
}
/**
* {@inheritdoc}
*/
public function validate($module)
{
return $this->lazyLoadItself()->validate($module);
}
/**
* {@inheritdoc}
*/
public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
{
return $this->lazyLoadItself()->setStringTranslation($translation);
}
}
}
......@@ -15,7 +15,18 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*
* @Chart(
* id = "charts_test_library",
* name = @Translation("Charts Test Library")
* name = @Translation("Charts Test Library"),
* types = {
* "area",
* "bar",
* "bubble",
* "column",
* "donut",
* "gauge",
* "line",
* "pie",
* "scatter",
* },
* )
*/
class ChartsTestLibrary extends ChartBase implements ContainerFactoryPluginInterface {
......
<?php
namespace Drupal\Tests\charts\Kernel;
use Drupal\Tests\charts\Traits\ConfigUpdateTrait;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
/**
* Tests the chart types support functionality.
*
* @group charts
*/
class ChartTypeSupportTest extends ChartsKernelTestBase {
use ConfigUpdateTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'charts',
'charts_test',
];
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->updateFooConfiguration('bar');
}
/**
* Tests the chart type support functionality.
*
* @param string $chart_type
* The chart type to test.
* @param string $expected_exception
* The expected exception.
* @param string $expected_exception_message
* The expected exception message.
*
* @dataProvider provideChartTypesData
*/
public function testNotSupportedChartType(string $chart_type, string $expected_exception, string $expected_exception_message) {
$element = [
'#type' => 'chart',
'#library' => 'charts_test_library',
'#chart_type' => $chart_type,
];
$this->expectException($expected_exception);
$this->expectExceptionMessage($expected_exception_message);
$this->renderer->renderRoot($element);
}
/**
* Provides data for chart types support test.
*
* @return array[]
* The chart types test cases.
*/
public function provideChartTypesData(): array {
return [
// Asserting that a chart type that is not a valid plugin chart type will
// throw a plugin not found exception during discovery.
'chart type plugin does not exist' => [
'not_supported',
PluginNotFoundException::class,
'The "not_supported" plugin does not exist. Valid plugin IDs for Drupal\charts\TypeManager are: area, bar, bubble, column, donut, gauge, line, pie, scatter, spline',
],
// Asserting that a chart type not supported by a chart library plugin
// will throw a logic exception.
'chart type plugin exists but not supported by the chart library plugin' => [
'spline',
\LogicException::class,
'The provided chart type "spline" is not supported by "Charts Test Library" chart plugin library.',
],
];
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment