class GenericEventSubscriber

Subscribes to Symfony events and maps them to Rules events.

Hierarchy

  • class \Drupal\rules\EventSubscriber\GenericEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface

Expanded class hierarchy of GenericEventSubscriber

1 string reference to 'GenericEventSubscriber'
rules.services.yml in ./rules.services.yml
rules.services.yml
1 service uses GenericEventSubscriber
rules.event_subscriber in ./rules.services.yml
Drupal\rules\EventSubscriber\GenericEventSubscriber

File

src/EventSubscriber/GenericEventSubscriber.php, line 19

Namespace

Drupal\rules\EventSubscriber
View source
class GenericEventSubscriber implements EventSubscriberInterface {
    
    /**
     * The entity type manager used for loading reaction rule config entities.
     *
     * @var \Drupal\Core\Entity\EntityTypeManagerInterface
     */
    protected $entityTypeManager;
    
    /**
     * The Rules event manager.
     *
     * @var \Drupal\rules\Core\RulesEventManager
     */
    protected $eventManager;
    
    /**
     * The component repository.
     *
     * @var \Drupal\rules\Engine\RulesComponentRepositoryInterface
     */
    protected $componentRepository;
    
    /**
     * The rules debug logger channel.
     *
     * @var \Drupal\Core\Logger\LoggerChannelInterface
     */
    protected $rulesDebugLogger;
    
    /**
     * Constructor.
     *
     * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
     *   The entity type manager.
     * @param \Drupal\rules\Core\RulesEventManager $event_manager
     *   The Rules event manager.
     * @param \Drupal\rules\Engine\RulesComponentRepositoryInterface $component_repository
     *   The component repository.
     * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
     *   The Rules debug logger channel.
     */
    public function __construct(EntityTypeManagerInterface $entity_type_manager, RulesEventManager $event_manager, RulesComponentRepositoryInterface $component_repository, LoggerChannelInterface $logger) {
        $this->entityTypeManager = $entity_type_manager;
        $this->eventManager = $event_manager;
        $this->componentRepository = $component_repository;
        $this->rulesDebugLogger = $logger;
    }
    
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents() {
        // Register this listener for every event that is used by a reaction rule.
        $events = [];
        $callback = [
            'onRulesEvent',
            100,
        ];
        // If there is no state service there is nothing we can do here. This static
        // method could be called early when the container is built, so the state
        // service might not always be available.
        if (!\Drupal::hasService('state')) {
            return [];
        }
        // Since we cannot access the reaction rule config storage here we have to
        // use the state system to provide registered Rules events. The Reaction
        // Rule storage is responsible for keeping the registered events up to date
        // in the state system.
        // @see \Drupal\rules\Entity\ReactionRuleStorage
        $state = \Drupal::state();
        $registered_event_names = $state->get('rules.registered_events');
        if (!empty($registered_event_names)) {
            foreach ($registered_event_names as $event_name) {
                $events[$event_name][] = $callback;
            }
        }
        return $events;
    }
    
    /**
     * Reacts on the given event and invokes configured reaction rules.
     *
     * @param object $event
     *   The event object containing context for the event.
     *   In Drupal 9 this will be a \Symfony\Component\EventDispatcher\Event,
     *   In Drupal 10 this will be a \Symfony\Contracts\EventDispatcher\Event.
     * @param string $event_name
     *   The event name.
     */
    public function onRulesEvent(object $event, $event_name) {
        // @todo The 'object' type hint should be replaced with the appropriate
        // class once Symfony 4 is no longer supported, and the assert() should be
        // removed.
        assert($event instanceof SymfonyComponentEvent || $event instanceof SymfonyContractsEvent);
        // Get event metadata and the to-be-triggered events.
        $event_definition = $this->eventManager
            ->getDefinition($event_name);
        $handler_class = $event_definition['class'];
        $triggered_events = [
            $event_name,
        ];
        if (is_subclass_of($handler_class, RulesConfigurableEventHandlerInterface::class)) {
            $qualified_event_suffixes = $handler_class::determineQualifiedEvents($event, $event_name, $event_definition);
            foreach ($qualified_event_suffixes as $qualified_event_suffix) {
                // This is where we add the bundle-specific event suffix, e.g.
                // rules_entity_insert:node--page if the content entity was type 'page'.
                $triggered_events[] = "{$event_name}--{$qualified_event_suffix}";
            }
        }
        // Setup the execution state.
        $state = ExecutionState::create();
        foreach ($event_definition['context_definitions'] as $context_name => $context_definition) {
            // If there is a getter method set in the event definition, use that.
            // @see https://www.drupal.org/project/rules/issues/2762517
            if ($context_definition->hasGetter()) {
                $value = $event->{$context_definition->getGetter()}();
            }
            elseif ($event instanceof GenericEvent) {
                $value = $event->getArgument($context_name);
            }
            else {
                $getter = function ($property) {
                    return $this->{$property};
                };
                $value = $getter->call($event, $context_name);
            }
            $state->setVariable($context_name, $context_definition, $value);
        }
        $components = $this->componentRepository
            ->getMultiple($triggered_events, 'rules_event');
        foreach ($components as $component) {
            $this->rulesDebugLogger
                ->info('Reacting on event %label.', [
                '%label' => $event_definition['label'],
                'element' => NULL,
                'scope' => TRUE,
            ]);
            $component->getExpression()
                ->executeWithState($state);
            $this->rulesDebugLogger
                ->info('Finished reacting on event %label.', [
                '%label' => $event_definition['label'],
                'element' => NULL,
                'scope' => FALSE,
            ]);
        }
        $state->autoSave();
    }

}

Members

Title Sort descending Modifiers Object type Summary
GenericEventSubscriber::$componentRepository protected property The component repository.
GenericEventSubscriber::$entityTypeManager protected property The entity type manager used for loading reaction rule config entities.
GenericEventSubscriber::$eventManager protected property The Rules event manager.
GenericEventSubscriber::$rulesDebugLogger protected property The rules debug logger channel.
GenericEventSubscriber::getSubscribedEvents public static function
GenericEventSubscriber::onRulesEvent public function Reacts on the given event and invokes configured reaction rules.
GenericEventSubscriber::__construct public function Constructor.