Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebuild the container when a reaction rule is saved #364

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
69 changes: 67 additions & 2 deletions src/Form/ReactionRuleEditForm.php
Expand Up @@ -7,9 +7,12 @@

namespace Drupal\rules\Form;

use Drupal\Core\DrupalKernelInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\rules\Engine\RulesEventManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
* Provides a form to edit a reaction rule.
Expand All @@ -25,21 +28,50 @@ class ReactionRuleEditForm extends RulesComponentFormBase {
*/
protected $eventManager;

/**
* The event dispatcher.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface.
*/
protected $eventDispatcher;

/**
* The generic event subscriber.
*
* @var \Symfony\Component\EventDispatcher\EventSubscriberInterface
*/
protected $genericEventSubscriber;

/**
* The Drupal kernel.
*
* @var \Drupal\Core\DrupalKernelInterface.
*/
protected $drupalKernel;

/**
* Constructs a new object of this class.
*
* @param \Drupal\rules\Engine\RulesEventManager $event_manager
* The event plugin manager.
*/
public function __construct(RulesEventManager $event_manager) {
public function __construct(RulesEventManager $event_manager, EventDispatcherInterface $event_dispatcher, EventSubscriberInterface $generic_event_subscriber, DrupalKernelInterface $drupal_kernel) {
$this->eventManager = $event_manager;
$this->eventDispatcher = $event_dispatcher;
$this->genericEventSubscriber = $generic_event_subscriber;
$this->drupalKernel = $drupal_kernel;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('plugin.manager.rules_event'));
return new static(
$container->get('plugin.manager.rules_event'),
$container->get('event_dispatcher'),
$container->get('rules.event_subscriber'),
$container->get('kernel')
);
}

/**
Expand Down Expand Up @@ -76,6 +108,14 @@ public function save(array $form, FormStateInterface $form_state) {
// Also remove the temporarily stored rule, it has been persisted now.
$this->deleteFromTempStore();

// After the reaction rule is saved, we need to rebuild the container,
// otherwise the reaction rule will not fire. However, we can do an
// optimization: if our generic event subscriber is already registered to
// the event in the kernel/container then we don't need to rebuild.
if (!$this->isRuleEventRegistered()) {
$this->drupalKernel->rebuildContainer();
}

drupal_set_message($this->t('Reaction rule %label has been updated.', ['%label' => $this->entity->label()]));
}

Expand All @@ -95,4 +135,29 @@ protected function getRuleConfig() {
return $this->entity;
}

/**
* Checks if the event of the current rule is registered into the container.
*
* @return bool
* TRUE if the event is registered, FALSE otherwise.
*/
protected function isRuleEventRegistered() {
// To check if the event of the rule is registered, we have to check if the
// generic subscriber is registered for the event. In order to check if the
// generic subscriber is already registered for the event, we have to search
// in the listeners list for an object with the same class as our generic
// event subscriber which is registered for that event.
$event_name = $this->getRuleConfig()->getEvent();
$listeners = $this->eventDispatcher->getListeners();
if (!empty($listeners[$event_name])) {
$generic_subscriber_class = get_class($this->genericEventSubscriber);
foreach ($listeners[$event_name] as $listener) {
if (is_object($listener[0]) && get_class($listener[0]) == $generic_subscriber_class) {
return TRUE;
}
}
}
return FALSE;
}

}
4 changes: 0 additions & 4 deletions tests/src/Functional/ConfigureAndExecuteTest.php
Expand Up @@ -91,10 +91,6 @@ public function testConfigureAndExecute() {
// One more save to permanently store the rule.
$this->pressButton('Save');

// Rebuild the container so that the new Rules event is picked up.
$this->drupalGet('admin/config/development/performance');
$this->pressButton('Clear all caches');

// Add a node now and check if our rule triggers.
$this->drupalGet('node/add/article');
$this->fillField('Title', 'Test title');
Expand Down