You are here

business_rules.module in Business Rules 8

Same filename and directory in other branches
  1. 2.x business_rules.module

Business Rules module.

File

business_rules.module
View source
<?php

/**
 * @file
 * Business Rules module.
 */
use Drupal\business_rules\Entity\Schedule;
use Drupal\business_rules\Events\BusinessRulesEvent;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\quickedit\Form\QuickEditFieldForm;
use Drupal\user\Entity\User;

/**
 * Implements hook_help().
 */
function business_rules_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the business_rules module.
    case 'help.page.business_rules':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Business Rules') . '</p>';
      $output .= '<p>' . Link::fromTextAndUrl(t('Click here to access the online Business Rules documentation.'), Url::fromUri('https://www.drupal.org/docs/8/modules/business-rules'))
        ->toString() . '</p>';
      return $output;
    default:
  }
}

/**
 * Implements hook_entity_presave().
 */
function business_rules_entity_presave(EntityInterface $entity) {

  // Only handle content entities and ignore config entities.
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('entity_presave', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('entity_presave');
    $entity_type_id = $entity
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => $entity->original,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_entity_update().
 */
function business_rules_entity_update(EntityInterface $entity) {

  // Only handle content entities and ignore config entities.
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('entity_update', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('entity_update');
    $entity_type_id = $entity
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => $entity->original,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_entity_insert().
 */
function business_rules_entity_insert(EntityInterface $entity) {

  // Only handle content entities and ignore config entities.
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('entity_insert', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('entity_insert');
    $entity_type_id = $entity
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => $entity->original,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_entity_delete().
 */
function business_rules_entity_delete(EntityInterface $entity) {

  // Only handle content entities and ignore config entities.
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('entity_delete', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('entity_delete');
    $entity_type_id = $entity
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => $entity->original,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_form_alter().
 */
function business_rules_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (method_exists($form_state
    ->getFormObject(), 'getEntity') && !$form_state
    ->isCached() && (!isset($_GET['ajax_form']) || $_GET['ajax_form'] != 1) && (!isset($_GET['_wrapper_format']) || $_GET['_wrapper_format'] != 'drupal_ajax')) {
    $entity = $form_state
      ->getFormObject()
      ->getEntity();
    if (\Drupal::service('business_rules.processor')
      ->ruleExists('form_validation', $entity)) {

      // Prepare the event for formValidation.
      $form_validation_reacts_on_definition = \Drupal::getContainer()
        ->get('plugin.manager.business_rules.reacts_on')
        ->getDefinition('form_validation');
      $form_validation_event = new BusinessRulesEvent($entity, [
        'form_id' => $form_id,
        'form_state' => $form_state,
        'form' => $form,
        'entity_type_id' => $entity
          ->getEntityTypeId(),
        'bundle' => $entity
          ->bundle(),
        'entity' => $entity,
        'entity_unchanged' => $entity->original,
        'reacts_on' => $form_validation_reacts_on_definition,
        'loop_control' => $entity
          ->getEntityTypeId() . $entity
          ->id(),
      ]);
      $form_state
        ->set('business_rules_event', $form_validation_event);

      // We can't dispatch this event here, otherwise it would be processed
      // before the form validation. In this case, the FormValidator will take
      // care of the event process and we are just adding this validation.
      $form['#validate'][] = 'Drupal\\business_rules\\Plugin\\BusinessRulesReactsOn\\FormValidation::validateForm';
    }
  }
}

/**
 * Implements hook_field_widget_form_alter().
 */
function business_rules_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {

  // @todo check patch inline_entity_form_2973571_1.patch.
  $form_object = $form_state
    ->getFormObject();

  // Establish whether we're in a normal EntityForm context or an inline
  // QuickeditFieldForm context and retrieve the entity from the respectively
  // appropriate place.
  if ($form_object instanceof EntityFormInterface) {
    $entity = $form_object
      ->getEntity();
  }
  else {
    if ($form_object instanceof QuickEditFieldForm) {
      $entity = $form_state
        ->getBuildInfo()['args'][0];
    }
    else {
      $entity = new stdClass();
    }
  }
  if ($entity instanceof EntityInterface) {

    // Check if the field is a dependent field.

    /** @var \Drupal\Core\Field\FieldItemList $items */
    $items = $context['items'];
    $current_field = $items
      ->getFieldDefinition()
      ->getName();

    // Check if field is configured as parent of one dependent field.
    if (method_exists($entity, 'getFieldDefinitions')) {
      $fields_definitions = $entity
        ->getFieldDefinitions();
      $parent_field = NULL;

      // Check if current field has children.
      $child_fields = [];
      foreach ($fields_definitions as $field_name => $field_definition) {
        $handler = $field_definition
          ->getSetting('handler');
        if ($handler == 'business_rules_views') {
          $handle_settings = $field_definition
            ->getSetting('handler_settings');
          $parent_field = $handle_settings['business_rules_view']['parent_field'];
          $has_children = $parent_field == $current_field;
          if ($has_children) {
            $child_fields[] = $field_name;
          }
        }
      }

      // Add ajax to parent field.
      if (count($child_fields)) {
        $children = isset($element['#ajax']['br_children']) ? $element['#ajax']['br_children'] : [];
        $children += $child_fields;
        $ajax_definition = [
          'callback' => '\\Drupal\\business_rules\\Plugin\\EntityReferenceSelection\\BusinessRulesViewsSelection::updateDependentField',
          'event' => 'change',
          'progress' => [
            'type' => 'throbber',
          ],
          'br_children' => $children,
        ];
        if (!empty($context['widget']) && $context['widget'] instanceof EntityReferenceAutocompleteWidget && !empty($element['target_id'])) {
          $ajax_definition['event'] = 'autocompleteclose';
          $element['target_id']['#ajax'] = $ajax_definition;
        }
        else {
          $element['#ajax'] = $ajax_definition;
        }
        $element['#attached']['library'][] = 'business_rules/dependentField';
      }
    }

    // Prepare the event to FormFieldAlter.
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('form_field_alter');

    // Business rules processor needs to process this event every time it's
    // called by Drupal. There is no necessity of loop control here. In this
    // case we are creating an uuid because there is no risk of infinite loop.
    $loop_control = \Drupal::getContainer()
      ->get('uuid')
      ->generate();
    $event = new BusinessRulesEvent($element, [
      'form_state' => $form_state,
      'element' => $element,
      'context' => $context,
      'entity_type_id' => $entity
        ->getEntityTypeId(),
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => property_exists($entity, 'original') ? $entity->original : $entity,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $loop_control,
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);

    // Now we need to replace the current element by the changed one.
    $element = $event
      ->getArgument('element');
  }
}

/**
 * Implements hook_entity_view().
 */
function business_rules_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {

  // Only handle content entities and ignore config entities.
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('entity_is_viewed', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('entity_is_viewed');
    $entity_type_id = $entity
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => $entity->original,
      'build' => &$build,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_entity_load().
 */
function business_rules_entity_load(array $entities, $entity_type_id) {
  foreach ($entities as $entity) {
    if (\Drupal::service('business_rules.processor')
      ->ruleExists('entity_is_loaded', $entity)) {
      $reacts_on_definition = \Drupal::getContainer()
        ->get('plugin.manager.business_rules.reacts_on')
        ->getDefinition('entity_is_loaded');
      $entity_type_id = $entity
        ->getEntityTypeId();
      $event = new BusinessRulesEvent($entity, [
        'entity_type_id' => $entity_type_id,
        'bundle' => $entity
          ->bundle(),
        'entity' => $entity,
        'entity_unchanged' => $entity->original,
        'reacts_on' => $reacts_on_definition,
        'loop_control' => $entity
          ->getEntityTypeId() . $entity
          ->id(),
      ]);

      /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
      $event_dispatcher = \Drupal::service('event_dispatcher');
      $event_dispatcher
        ->dispatch($reacts_on_definition['eventName'], $event);
    }
  }
}

/**
 * Implements hook_user_login().
 */
function business_rules_user_login($account) {
  $entity = $account;
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('user_login', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('user_login');
    $entity_type_id = $account
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => NULL,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_user_logout().
 */
function business_rules_user_logout($account) {
  $entity = User::load($account
    ->id());
  if (\Drupal::service('business_rules.processor')
    ->ruleExists('user_logout', $entity)) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('user_logout');
    if (method_exists($account, 'getAccount')) {
      $account = $account
        ->getAccount();
    }
    $entity_type_id = $entity
      ->getEntityTypeId();
    $event = new BusinessRulesEvent($entity, [
      'entity_type_id' => $entity_type_id,
      'bundle' => $entity
        ->bundle(),
      'entity' => $entity,
      'entity_unchanged' => NULL,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $entity
        ->getEntityTypeId() . $entity
        ->id(),
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_cache_flush().
 */
function business_rules_cache_flush() {
  $key_value = \Drupal::keyValueExpirable('business_rules.debug');
  $key_value
    ->deleteAll();
  $key_value = \Drupal::keyValueExpirable('business_rules.token_tree');
  $key_value
    ->deleteAll();
}

/**
 * Implements hook_mail().
 */
function business_rules_mail($key, &$message, $params) {
  if ($key === 'business_rules_mail') {
    $message['headers'] = array_merge($message['headers'], $params['headers']);
    $message['subject'] = $params['subject'];
    $message['body'][] = $params['message'];
  }
}

/**
 * Page load event dispatcher.
 */
function business_rules_page_load_event() {
  if (Drupal::hasContainer()) {
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('page_load');
    $path = $_SERVER['REQUEST_URI'];
    $event = new BusinessRulesEvent($path, [
      'entity_type_id' => '',
      'bundle' => NULL,
      'entity' => NULL,
      'entity_unchanged' => NULL,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $path,
    ]);
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);
  }
}

/**
 * Implements hook_page_top().
 */
function business_rules_page_top(array &$page_top) {
  business_rules_page_load_event();
}

/**
 * Implements hook_cron().
 */
function business_rules_cron() {
  if (Drupal::hasContainer()) {

    // Dispatch the cron runs business rules items.
    $reacts_on_definition = \Drupal::getContainer()
      ->get('plugin.manager.business_rules.reacts_on')
      ->getDefinition('cron_runs');
    $loop_control = time();
    $dummy = new stdClass();
    $event = new BusinessRulesEvent($dummy, [
      'entity_type_id' => '',
      'bundle' => NULL,
      'entity' => NULL,
      'entity_unchanged' => NULL,
      'reacts_on' => $reacts_on_definition,
      'loop_control' => $loop_control,
    ]);
    $event_dispatcher = \Drupal::service('event_dispatcher');
    $event_dispatcher
      ->dispatch($reacts_on_definition['eventName'], $event);

    // Dispatch the scheduled items.
    Schedule::executeSchedule($event);
  }
}

/**
 * Implements hook_entity_type_alter().
 */
function business_rules_entity_type_alter(array &$entity_types) {
  $form_modes = \Drupal::service('entity_display.repository')
    ->getAllFormModes();
  $skip_names = [
    'register',
    'add_to_cart',
  ];
  foreach ($form_modes as $entity_type => $display_modes) {
    $type = $entity_types[$entity_type];
    foreach ($display_modes as $machine_name => $form_display) {
      if (!in_array($machine_name, $skip_names) && isset($type
        ->getHandlerClasses()['form']['default'])) {
        $default_handler_class = $type
          ->getHandlerClasses()['form']['default'];
        $type
          ->setFormClass($machine_name, $default_handler_class);
      }
    }
  }
}

/**
 * Implements hook_entity_form_display_alter().
 *
 * The trick here is to pass the $form_display as a reference.
 */
function business_rules_entity_form_display_alter(EntityFormDisplayInterface &$form_display, array $context) {
  $reacts_on_definition = \Drupal::getContainer()
    ->get('plugin.manager.business_rules.reacts_on')
    ->getDefinition('form_display_mode_alter');
  $loop_control = $form_display
    ->id();
  $event = new BusinessRulesEvent($form_display, [
    'entity_type_id' => $context['entity_type'],
    'bundle' => $context['bundle'],
    'reacts_on' => $reacts_on_definition,
    'loop_control' => $loop_control,
    'form_display' => NULL,
  ]);

  /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
  $event_dispatcher = \Drupal::service('event_dispatcher');
  $event_dispatcher
    ->dispatch($reacts_on_definition['eventName'], $event);
  $new_form_display = $event
    ->getArgument('form_display');
  if ($new_form_display instanceof EntityFormDisplayInterface) {
    $form_display = $new_form_display;
  }
}