diff --git a/inmail.drush.inc b/inmail.drush.inc index 9932620..80434b1 100644 --- a/inmail.drush.inc +++ b/inmail.drush.inc @@ -70,6 +70,10 @@ function drush_inmail_process() { drush_set_error(dt('Deliverer "@deliverer_id" not found', ['@deliverer_id' => $deliverer_config_id])); return; } + if (!$deliverer->isAvailable()) { + drush_set_error(dt('Deliverer "@deliverer_id" is not available', ['@deliverer_id' => $deliverer_config_id])); + return; + } if (count($args) > 0) { $raws = array(); diff --git a/inmail.install b/inmail.install index 0d15490..bb72393 100644 --- a/inmail.install +++ b/inmail.install @@ -5,6 +5,71 @@ */ /** + * Implements hook_requirements(). + */ +function inmail_requirements($phase) { + $requirements = []; + if ($phase == 'runtime') { + $requirements += inmail_get_requirements(); + } + + return $requirements; +} + +/** + * Returns plugin and instance requirements. + * + * @return array + * An array of plugin and instance requirements. + */ +function inmail_get_requirements() { + /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ + $entity_type_manager = \Drupal::entityTypeManager(); + $plugin_types = ['analyzer', 'deliverer', 'handler']; + $requirements = []; + + foreach ($plugin_types as $plugin_type) { + // Check instance requirements. + $entities = $entity_type_manager->getStorage("inmail_$plugin_type")->loadByProperties(['status' => TRUE]); + /** @var \Drupal\inmail\Entity\PluginConfigEntity $entity */ + foreach ($entities as $entity) { + // Add requirements specific entity and plugin keys. + $plugin_id = $entity->getPluginId(); + $entity_key = $plugin_type . '_entity_' . $entity->id(); + $plugin_key = $plugin_type . '_plugin_' . $plugin_id; + try { + /** @var \Drupal\inmail\PluginRequirementsInterface $plugin */ + $plugin = $entity->getPluginInstance(); + + // Check entity instance requirements. + $requirements[$entity_key] = $plugin->checkInstanceRequirements(); + // Add title in case requirements are not empty. + if (!empty($requirements[$entity_key])) { + $requirements[$entity_key]['title'] = $entity->label() . ' (' . $entity->id() . ')'; + } + + // Check plugin requirements only if it is not already checked. + if (!isset($requirements[$plugin_key])) { + $requirements[$plugin_key] = $plugin::checkPluginRequirements(); + } + } + catch (\Drupal\Component\Plugin\Exception\PluginException $e) { + $requirements[$plugin_key] = [ + 'title' => t('Missing plugin @id', ['@id' => $plugin_id]), + 'description' => t('Inmail @type plugin @id is missing and cannot be used.', ['@type' => $plugin_type, '@id' => $plugin_id]), + 'severity' => REQUIREMENT_ERROR, + ]; + } + } + } + + // Filter plugins/instances with no requirements. + $requirements = array_filter($requirements); + + return $requirements; +} + +/** * Implements hook_install(). */ function inmail_install() { diff --git a/inmail_demo/src/Form/PasteForm.php b/inmail_demo/src/Form/PasteForm.php index 26d3368..fe541c4 100644 --- a/inmail_demo/src/Form/PasteForm.php +++ b/inmail_demo/src/Form/PasteForm.php @@ -187,17 +187,20 @@ class PasteForm extends FormBase { } /** - * Loads and returns all deliverer configs using the Paste deliverer. + * Loads and returns all available deliverer configs using Paste deliverer. * * @return \Drupal\inmail\Entity\DelivererConfig[] - * All enabled Paste deliverer configs. + * All enabled and available Paste deliverer configs. */ protected function getDelivererConfigs() { $ids = $this->delivererStorage->getQuery() ->condition('plugin', 'paste') ->condition('status', TRUE) ->execute(); - return $this->delivererStorage->loadMultiple($ids); + $deliverers = $this->delivererStorage->loadMultiple($ids); + return array_filter($deliverers, function ($deliverer) { + return $deliverer->isAvailable(); + }); } /** diff --git a/src/Entity/AnalyzerConfig.php b/src/Entity/AnalyzerConfig.php index b415afb..e287449 100644 --- a/src/Entity/AnalyzerConfig.php +++ b/src/Entity/AnalyzerConfig.php @@ -43,6 +43,13 @@ namespace Drupal\inmail\Entity; class AnalyzerConfig extends PluginConfigEntity { /** + * The Inmail plugin type. + * + * @var string + */ + protected $pluginType = 'analyzer'; + + /** * The weight of the analyzer configuration. * * Analyzers with lower weights are invoked before those with higher weights. diff --git a/src/Entity/DelivererConfig.php b/src/Entity/DelivererConfig.php index 39893d0..797620c 100644 --- a/src/Entity/DelivererConfig.php +++ b/src/Entity/DelivererConfig.php @@ -40,4 +40,12 @@ namespace Drupal\inmail\Entity; * ) */ class DelivererConfig extends PluginConfigEntity { + + /** + * The Inmail plugin type. + * + * @var string + */ + protected $pluginType = 'deliverer'; + } diff --git a/src/Entity/HandlerConfig.php b/src/Entity/HandlerConfig.php index 552f146..5e97708 100644 --- a/src/Entity/HandlerConfig.php +++ b/src/Entity/HandlerConfig.php @@ -40,4 +40,12 @@ namespace Drupal\inmail\Entity; */ class HandlerConfig extends PluginConfigEntity { // @todo Implement HandlerConfig::calculateDependencies() https://www.drupal.org/node/2379929 + + /** + * The Inmail plugin type. + * + * @var string + */ + protected $pluginType = 'handler'; + } diff --git a/src/Entity/PluginConfigEntity.php b/src/Entity/PluginConfigEntity.php index 366ae77..1fe4c63 100644 --- a/src/Entity/PluginConfigEntity.php +++ b/src/Entity/PluginConfigEntity.php @@ -38,6 +38,13 @@ abstract class PluginConfigEntity extends ConfigEntityBase { protected $configuration = array(); /** + * The plugin instance. + * + * @var \Drupal\inmail\Plugin\inmail\Analyzer\AnalyzerInterface|\Drupal\inmail\Plugin\inmail\Deliverer\DelivererInterface|\Drupal\inmail\Plugin\inmail\Handler\HandlerInterface + */ + protected $pluginInstance; + + /** * Returns the plugin ID. * * @return string @@ -71,4 +78,47 @@ abstract class PluginConfigEntity extends ConfigEntityBase { $this->configuration = $configuration; return $this; } + + /** + * Returns the plugin instance. + * + * @return \Drupal\inmail\Plugin\inmail\Analyzer\AnalyzerInterface|\Drupal\inmail\Plugin\inmail\Deliverer\DelivererInterface|\Drupal\inmail\Plugin\inmail\Handler\HandlerInterface The instantiated plugin. + * The instantiated plugin. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * Throws an exception in case of missing plugin. + */ + public function getPluginInstance() { + if (empty($this->pluginInstance)) { + $this->pluginInstance = \Drupal::service('plugin.manager.inmail.' . $this->pluginType)->createInstance($this->plugin, $this->configuration); + } + + return $this->pluginInstance; + } + + /** + * Returns the plugin type. + * + * @return string + * The plugin type. + */ + public function getPluginType() { + return $this->pluginType; + } + + /** + * Flag determining whether a plugin is available to be used in processing. + * + * @return bool + * TRUE if the plugin is available. Otherwise, FALSE. + */ + public function isAvailable() { + $is_available = FALSE; + if ($plugin = $this->getPluginInstance()) { + $is_available = $plugin->isAvailable(); + } + + return $is_available; + } + } diff --git a/src/Form/DelivererListForm.php b/src/Form/DelivererListForm.php index ab84e80..ecde679 100644 --- a/src/Form/DelivererListForm.php +++ b/src/Form/DelivererListForm.php @@ -77,7 +77,7 @@ class DelivererListForm extends FormBase { // Get plugin instance. $deliverer = $this->delivererManager->createInstance($deliverer_config->getPluginId(), $deliverer_config->getConfiguration()); // Update plugin. - if ($deliverer instanceof FetcherInterface) { + if ($deliverer instanceof FetcherInterface && $deliverer->isAvailable()) { $deliverer->update(); $deliverer->setLastCheckedTime(REQUEST_TIME); $fetchers_count++; diff --git a/src/InmailPluginBase.php b/src/InmailPluginBase.php new file mode 100644 index 0000000..81c898c --- /dev/null +++ b/src/InmailPluginBase.php @@ -0,0 +1,33 @@ +analyzerStorage->getEntityType()->getClass(), 'sort')); foreach ($analyzer_configs as $analyzer_config) { /** @var \Drupal\inmail\Entity\AnalyzerConfig $analyzer_config */ - if ($analyzer_config->status()) { + if ($analyzer_config->status() && $analyzer_config->isAvailable()) { /** @var \Drupal\inmail\Plugin\inmail\Analyzer\AnalyzerInterface $analyzer */ $analyzer = $this->analyzerManager->createInstance($analyzer_config->getPluginId(), $analyzer_config->getConfiguration()); $analyzer->analyze($message, $result); @@ -136,7 +136,7 @@ class MessageProcessor implements MessageProcessorInterface { // Handle message. foreach ($this->handlerStorage->loadMultiple() as $handler_config) { /** @var \Drupal\inmail\Entity\HandlerConfig $handler_config */ - if ($handler_config->status()) { + if ($handler_config->status() && $handler_config->isAvailable()) { /** @var \Drupal\inmail\Plugin\inmail\handler\HandlerInterface $handler */ $handler = $this->handlerManager->createInstance($handler_config->getPluginId(), $handler_config->getConfiguration()); $handler->invoke($message, $result); diff --git a/src/Plugin/inmail/Analyzer/AnalyzerBase.php b/src/Plugin/inmail/Analyzer/AnalyzerBase.php index 5b71343..e88e538 100644 --- a/src/Plugin/inmail/Analyzer/AnalyzerBase.php +++ b/src/Plugin/inmail/Analyzer/AnalyzerBase.php @@ -3,14 +3,14 @@ namespace Drupal\inmail\Plugin\inmail\Analyzer; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Plugin\PluginBase; +use Drupal\inmail\InmailPluginBase; /** * Base class for message analyzer plugins. * * @ingroup analyzer */ -abstract class AnalyzerBase extends PluginBase implements AnalyzerInterface { +abstract class AnalyzerBase extends InmailPluginBase implements AnalyzerInterface { /** * {@inheritdoc} diff --git a/src/Plugin/inmail/Deliverer/DelivererBase.php b/src/Plugin/inmail/Deliverer/DelivererBase.php index 599edec..0248d2e 100644 --- a/src/Plugin/inmail/Deliverer/DelivererBase.php +++ b/src/Plugin/inmail/Deliverer/DelivererBase.php @@ -1,8 +1,7 @@ save(); } $default_result->setAccount($demo_user); + + // Update the body of the default result. + $default_result->setBody($message->getBody()); } /** diff --git a/tests/modules/inmail_test/src/Plugin/inmail/Analyzer/UnavailableAnalyzer.php b/tests/modules/inmail_test/src/Plugin/inmail/Analyzer/UnavailableAnalyzer.php new file mode 100644 index 0000000..4a76d8b --- /dev/null +++ b/tests/modules/inmail_test/src/Plugin/inmail/Analyzer/UnavailableAnalyzer.php @@ -0,0 +1,60 @@ +getAnalyzerResult(DefaultAnalyzerResult::TOPIC); + + // Do the fake body update. This should not be executed as we only execute + // available analyzers. + $default_result->setBody('The body has been updated by UnavailableAnalyzer.'); + } + + /** + * {@inheritdoc} + */ + public static function checkPluginRequirements() { + return [ + 'title' => t('Unavailable Analyzer'), + 'description' => t('Unavailable Analyzer cannot be used.'), + 'severity' => REQUIREMENT_ERROR, + ]; + } + + /** + * {@inheritdoc} + */ + public function checkInstanceRequirements() { + return [ + 'description' => $this->t('Wrong instance configuration.'), + 'severity' => REQUIREMENT_ERROR, + ]; + } + + /** + * {@inheritdoc} + */ + public function isAvailable() { + return FALSE; + } + +} diff --git a/tests/src/Kernel/ProcessorTest.php b/tests/src/Kernel/ProcessorTest.php index e203425..126cc42 100644 --- a/tests/src/Kernel/ProcessorTest.php +++ b/tests/src/Kernel/ProcessorTest.php @@ -47,9 +47,9 @@ class ProcessorTest extends KernelTestBase { } /** - * Tests account switching mechanism. + * Tests the sample message processing. */ - public function testAccountSwitching() { + public function testMessageProcessing() { $raw = << @@ -62,6 +62,14 @@ EOF; $processor = \Drupal::service('inmail.processor'); AnalyzerConfig::create(['id' => 'test_analyzer', 'plugin' => 'test_analyzer'])->save(); + // Add an unavailable analyzer. + $unavailable_analyzer = AnalyzerConfig::create([ + 'id' => 'unavailable_analyzer', + 'label' => 'Unavailable Analyzer', + 'plugin' => 'unavailable_analyzer', + ]); + $unavailable_analyzer->save(); + HandlerConfig::create(['id' => 'result_keeper', 'plugin' => 'result_keeper'])->save(); $processor->process($raw, DelivererConfig::create(['id' => 'test'])); @@ -73,6 +81,22 @@ EOF; $this->assertEquals('Demo User', $default_result->getAccount()->getDisplayName()); // Assert the account was switched on handler's level. $this->assertEquals('Demo User', ResultKeeperHandler::getAccountName()); + + // Assert the requirements messages. + $plugin = $unavailable_analyzer->getPluginInstance(); + $this->assertEquals([ + 'title' => t('Unavailable Analyzer'), + 'description' => t('Unavailable Analyzer cannot be used.'), + 'severity' => REQUIREMENT_ERROR, + ], $plugin::checkPluginRequirements()); + $this->assertEquals([ + 'description' => t('Wrong instance configuration.'), + 'severity' => REQUIREMENT_ERROR, + ], $plugin->checkInstanceRequirements()); + $this->assertEquals(FALSE, $unavailable_analyzer->isAvailable()); + // The body message has not changed. It implies UnavailableAnalyzer + // did not run. + $this->assertEquals('Hello world!', $default_result->getBody()); } }