You are here

BehaviorInvoker.php in Rabbit Hole 8

Same filename and directory in other branches
  1. 2.x src/BehaviorInvoker.php

Namespace

Drupal\rabbit_hole

File

src/BehaviorInvoker.php
View source
<?php

namespace Drupal\rabbit_hole;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPluginInterface;
use Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPluginManager;
use Drupal\rabbit_hole\Plugin\RabbitHoleEntityPluginManager;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\KernelEvent;

/**
 * Default implementation of Rabbit Hole behaviors invoker.
 */
class BehaviorInvoker implements BehaviorInvokerInterface {

  /**
   * Behavior settings manager.
   *
   * @var \Drupal\rabbit_hole\BehaviorSettingsManager
   */
  protected $rhBehaviorSettingsManager;

  /**
   * Behavior plugin manager.
   *
   * @var \Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPluginManager
   */
  protected $rhBehaviorPluginManager;

  /**
   * Entity plugin manager.
   *
   * @var \Drupal\rabbit_hole\Plugin\RabbitHoleEntityPluginManager
   */
  protected $rhEntityPluginManager;

  /**
   * Entity extender service.
   *
   * @var \Drupal\rabbit_hole\EntityExtender
   */
  protected $rhEntityExtender;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * BehaviorInvoker constructor.
   *
   * @param \Drupal\rabbit_hole\BehaviorSettingsManager $rabbit_hole_behavior_settings_manager
   *   Behavior settings manager.
   * @param \Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPluginManager $plugin_manager_rabbit_hole_behavior_plugin
   *   Behavior plugin manager.
   * @param \Drupal\rabbit_hole\Plugin\RabbitHoleEntityPluginManager $plugin_manager_rabbit_hole_entity_plugin
   *   Entity plugin manager.
   * @param \Drupal\rabbit_hole\EntityExtender $entity_extender
   *   Entity extender service.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   */
  public function __construct(BehaviorSettingsManager $rabbit_hole_behavior_settings_manager, RabbitHoleBehaviorPluginManager $plugin_manager_rabbit_hole_behavior_plugin, RabbitHoleEntityPluginManager $plugin_manager_rabbit_hole_entity_plugin, EntityExtender $entity_extender, AccountProxyInterface $current_user, ModuleHandlerInterface $module_handler = NULL) {
    $this->rhBehaviorSettingsManager = $rabbit_hole_behavior_settings_manager;
    $this->rhBehaviorPluginManager = $plugin_manager_rabbit_hole_behavior_plugin;
    $this->rhEntityPluginManager = $plugin_manager_rabbit_hole_entity_plugin;
    $this->rhEntityExtender = $entity_extender;
    $this->currentUser = $current_user;
    if (!$module_handler) {
      @trigger_error('The module_handler service must be passed to ' . __NAMESPACE__ . '\\BehaviorInvoker::__construct(). It was added in 8.x-1.0-beta8 and will be required in 2.0 version.', E_USER_DEPRECATED);
      $module_handler = \Drupal::moduleHandler();
    }
    $this->moduleHandler = $module_handler;
  }

  /**
   * {@inheritdoc}
   */
  public function getEntity(KernelEvent $event) {
    $request = $event
      ->getRequest();

    // Don't process events with HTTP exceptions - those have either been thrown
    // by us or have nothing to do with rabbit hole.
    if ($request
      ->get('exception') != NULL) {
      return FALSE;
    }

    // Get the route from the request.
    if ($route = $request
      ->get('_route')) {

      // Only continue if the request route is the an entity canonical.
      if (preg_match('/^entity\\.(.+)\\.canonical$/', $route)) {

        // We check for all of our known entity keys that work with rabbit hole
        // and invoke rabbit hole behavior on the first one we find (which
        // should also be the only one).
        $entity_keys = $this
          ->getPossibleEntityTypeKeys();
        foreach ($entity_keys as $ekey) {
          $entity = $request
            ->get($ekey);
          if (isset($entity) && $entity instanceof ContentEntityInterface) {
            return $entity;
          }
        }
      }
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function processEntity(ContentEntityInterface $entity, Response $current_response = NULL) {
    $plugin = $this
      ->getBehaviorPlugin($entity);
    if ($plugin === NULL) {
      return NULL;
    }
    $resp_use = $plugin
      ->usesResponse();
    $response_required = $resp_use == RabbitHoleBehaviorPluginInterface::USES_RESPONSE_ALWAYS;
    $response_allowed = $resp_use == $response_required || $resp_use == RabbitHoleBehaviorPluginInterface::USES_RESPONSE_SOMETIMES;

    // Most plugins never make use of the response and only run when it's not
    // provided (i.e. on a request event).
    if (!$response_allowed && $current_response == NULL || $response_allowed || $response_required && $current_response != NULL) {
      $response = $plugin
        ->performAction($entity, $current_response);

      // Execute a fallback action until we have correct response object.
      // It allows us to have a chain of fallback actions until we execute the
      // final one.
      while (!$response instanceof Response && is_string($response) && $this->rhBehaviorPluginManager
        ->getDefinition($response, FALSE) !== NULL) {
        $fallback_plugin = $this->rhBehaviorPluginManager
          ->createInstance($response, []);
        $response = $fallback_plugin
          ->performAction($entity, $current_response);
      }

      // Alter the response before it is returned.
      $this->moduleHandler
        ->alter('rabbit_hole_response', $response, $entity);
      return $response;
    }
    else {
      return NULL;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getPossibleEntityTypeKeys() {
    $entity_type_keys = [];
    foreach ($this->rhEntityPluginManager
      ->getDefinitions() as $def) {
      $entity_type_keys[] = $def['entityType'];
    }
    return $entity_type_keys;
  }

  /**
   * {@inheritdoc}
   */
  public function getRabbitHoleValuesForEntity(ContentEntityInterface $entity) {
    $field_keys = array_keys($this->rhEntityExtender
      ->getGeneralExtraFields());
    $values = [];
    $config = $this->rhBehaviorSettingsManager
      ->loadBehaviorSettingsAsConfig($entity
      ->getEntityType()
      ->getBundleEntityType() ?: $entity
      ->getEntityType()
      ->id(), $entity
      ->getEntityType()
      ->getBundleEntityType() ? $entity
      ->bundle() : NULL);

    // We trigger the default bundle action under the following circumstances:
    $trigger_default_bundle_action = !$config
      ->get('allow_override') || !$entity
      ->hasField('rh_action') || $entity
      ->get('rh_action')->value == NULL || $entity
      ->get('rh_action')->value == 'bundle_default';
    if ($trigger_default_bundle_action) {
      foreach ($field_keys as $field_key) {
        $config_field_key = substr($field_key, 3);
        $values[$field_key] = $config
          ->get($config_field_key);
      }
    }
    else {
      foreach ($field_keys as $field_key) {
        if ($entity
          ->hasField($field_key)) {
          $values[$field_key] = $entity->{$field_key}->value;
        }
      }
    }
    return $values;
  }

  /**
   * {@inheritdoc}
   */
  public function getRabbitHoleValuesForEntityType($entity_type_id, $bundle_id = NULL) {
    $field_keys = array_keys($this->rhEntityExtender
      ->getGeneralExtraFields());
    $values = [];
    $config = $this->rhBehaviorSettingsManager
      ->loadBehaviorSettingsAsConfig($entity_type_id, $bundle_id);
    foreach ($field_keys as $field_key) {
      $config_field_key = substr($field_key, 3);
      $values[$field_key] = $config
        ->get($config_field_key);
    }
    return $values;
  }

  /**
   * {@inheritdoc}
   */
  public function getBehaviorPlugin(ContentEntityInterface $entity) {
    $values = $this
      ->getRabbitHoleValuesForEntity($entity);
    $permission = 'rabbit hole bypass ' . $entity
      ->getEntityTypeId();
    $values['bypass_access'] = $this->currentUser
      ->hasPermission($permission);

    // Allow altering Rabbit Hole values.
    $this->moduleHandler
      ->alter('rabbit_hole_values', $values, $entity);

    // Do nothing if action is missing or access is bypassed.
    if (empty($values['rh_action']) || $values['bypass_access']) {
      return NULL;
    }
    return $this->rhBehaviorPluginManager
      ->createInstance($values['rh_action'], $values);
  }

}

Classes

Namesort descending Description
BehaviorInvoker Default implementation of Rabbit Hole behaviors invoker.