You are here

lightning_core.module in Lightning Core 8.4

Contains core functionality for the Lightning distribution.

File

lightning_core.module
View source
<?php

/**
 * @file
 * Contains core functionality for the Lightning distribution.
 */
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\EntityDescriptionInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\file\Entity\File;
use Drupal\lightning_core\Element as ElementHelper;
use Drupal\lightning_core\Entity\EntityFormMode;
use Drupal\lightning_core\Entity\EntityViewMode;
use Drupal\lightning_core\Entity\Role;
use Drupal\lightning_core\Form\RoleForm;
use Drupal\lightning_core\OverrideHelper as Override;
use Drupal\lightning_core\Plugin\views\filter\Bundle;
use Drupal\lightning_core\UpdateManager;

/**
 * Implements hook_entity_base_field_info_alter().
 */
function lightning_core_entity_base_field_info_alter(array &$fields, EntityTypeInterface $entity_type) {

  /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
  if ($entity_type
    ->id() === 'user') {
    $fields['name']
      ->setDisplayConfigurable('view', TRUE);
  }
}

/**
 * Implements hook_local_tasks_alter().
 */
function lightning_core_local_tasks_alter(array &$local_tasks) {

  // When Content Moderation is installed, the "Edit" tab may have different
  // text, depending on the circumstances. In order for Behat tests to visit
  // the edit form, there must be a consistent way to target the tab. Rather
  // than rely on the text, set a consistent 'rel' attribute which step
  // definitions can reliably target.
  $local_tasks['entity.node.edit_form']['options']['attributes']['rel'] = 'edit-form';
}

/**
 * Implements hook_library_info_alter().
 */
function lightning_core_library_info_alter(array &$libraries, $extension) {
  if ($extension == 'seven') {
    $url = drupal_get_path('module', 'lightning_core') . '/css/admin-list.grid.css';
    $url = file_create_url($url);
    $url = file_url_transform_relative($url);
    $libraries['global-styling']['css']['component'][$url] = [];
  }
}

/**
 * Implements hook_config_schema_info_alter().
 */
function lightning_core_config_schema_info_alter(array &$definitions) {
  if (isset($definitions['views_filter'])) {
    $definitions['views_filter']['mapping']['expose']['mapping']['argument'] = [
      'type' => 'string',
      'label' => 'Yield to argument',
    ];
  }
}

/**
 * Implements hook_views_plugins_filter_alter().
 */
function lightning_core_views_plugins_filter_alter(array &$plugins) {
  Override::pluginClass($plugins['bundle'], Bundle::class);
}

/**
 * Implements hook_entity_type_alter().
 */
function lightning_core_entity_type_alter(array &$entity_types) {
  Override::entityClass($entity_types['user_role'], Role::class);
  Override::entityClass($entity_types['entity_view_mode'], EntityViewMode::class);
  Override::entityClass($entity_types['entity_form_mode'], EntityFormMode::class);
  Override::entityForm($entity_types['user_role'], RoleForm::class);
  if (\Drupal::moduleHandler()
    ->moduleExists('field_ui')) {
    Override::entityForm($entity_types['entity_view_mode'], '\\Drupal\\lightning_core\\Form\\EntityDisplayModeAddForm', 'add');
    Override::entityForm($entity_types['entity_view_mode'], '\\Drupal\\lightning_core\\Form\\EntityDisplayModeEditForm', 'edit');
    Override::entityForm($entity_types['entity_form_mode'], '\\Drupal\\lightning_core\\Form\\EntityFormModeAddForm', 'add');
    Override::entityForm($entity_types['entity_form_mode'], '\\Drupal\\lightning_core\\Form\\EntityDisplayModeEditForm', 'edit');
  }
}

/**
 * Implements hook_element_info_alter().
 */
function lightning_core_element_info_alter(array &$info) {

  // Add support for the #legend property to checkboxes and radios.
  // @see Element::processLegend()
  $info['radios']['#legend'] = $info['checkboxes']['#legend'] = [];
  $info['radios']['#process'][] = $info['checkboxes']['#process'][] = [
    ElementHelper::class,
    'processLegend',
  ];
}

/**
 * Implements hook_help().
 */
function lightning_core_help($route_name, RouteMatchInterface $route_match) {
  $matched = [];

  // Parse the route name to figure out what display mode we're looking at:
  // 0 is the entire string.
  // 1 is 'view' or 'form'.
  // 2 is the ID of the affected entity type.
  // 3 is 'view_mode' or 'form_mode'.
  // 4 is 'view' or 'form'.
  $expr = '/^entity\\.entity_(view|form)_display\\.([a-z_]+)\\.((view|form)_mode)$/';
  if (preg_match($expr, $route_name, $matched)) {
    $entity_id = sprintf('%s.%s', $route_match
      ->getParameter('entity_type_id'), $route_match
      ->getParameter($matched[3] . '_name'));
    $display_mode = \Drupal::entityTypeManager()
      ->getStorage('entity_' . $matched[3])
      ->load($entity_id);
    if ($display_mode instanceof EntityDescriptionInterface) {
      $description = $display_mode
        ->getDescription();
      if ($description) {
        return '<p>' . $description . '</p>';
      }
    }
  }
}

/**
 * Implements hook_modules_installed().
 */
function lightning_core_modules_installed(array $modules) {

  // Don't do anything during config sync.
  if (Drupal::isConfigSyncing()) {
    return;
  }

  // Record the semantic version of every module in config.
  $versions = Drupal::configFactory()
    ->getEditable(UpdateManager::CONFIG_NAME);

  /** @var \Drupal\lightning_core\UpdateManager $update_manager */
  $update_manager = \Drupal::service('lightning.update_manager');
  foreach ($modules as $module) {
    $versions
      ->set($module, $update_manager
      ->getVersion($module));
  }

  // Sort the list by key.
  $versions_sorted = $versions
    ->getRawData();
  ksort($versions_sorted);
  $versions
    ->setData($versions_sorted)
    ->save();
  if (in_array('token', $modules, TRUE)) {
    $view_modes = [];
    foreach (\Drupal::entityTypeManager()
      ->getDefinitions() as $entity_type) {
      $view_modes[] = $entity_type
        ->id() . '.token';
    }
    $view_modes = EntityViewMode::loadMultiple($view_modes);

    /** @var \Drupal\Core\Entity\EntityViewModeInterface $view_mode */
    foreach ($view_modes as $view_mode) {
      $view_mode
        ->setThirdPartySetting('lightning_core', 'internal', TRUE)
        ->save();
    }
  }
}

/**
 * Implements hook_block_view_alter().
 */
function lightning_core_block_view_alter(array &$build, BlockPluginInterface $block) {
  \Drupal::service('renderer')
    ->addCacheableDependency($build, $block);

  // Always add block_view:BASE_PLUGIN_ID as a cache tag.
  $build['#cache']['tags'][] = 'block_view:' . $block
    ->getBaseId();

  // If the plugin is a derivative, add block_view:FULL_PLUGIN_ID as well.
  if ($block
    ->getDerivativeId()) {
    $build['#cache']['tags'][] = 'block_view:' . $block
      ->getPluginId();
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function lightning_core_form_user_form_alter(array &$form) {
  if (isset($form['account']['roles'])) {

    /** @var \Drupal\user\RoleInterface $role */
    foreach (Role::loadMultiple() as $id => $role) {
      if ($role instanceof EntityDescriptionInterface) {
        $form['account']['roles']['#legend'][$id] = $role
          ->getDescription();
      }
    }
  }
}

/**
 * Implements hook_form_alter().
 */
function lightning_core_form_alter(array &$form, FormStateInterface $form_state) {
  $form_object = $form_state
    ->getFormObject();
  if ($form_object instanceof ContentEntityFormInterface && isset($form['revision_information']) && $form['revision_information']['#access']) {

    // Load the form mode and show the revision information if the form mode
    // allows the revision UI to be shown.
    $form_display = $form_object
      ->getFormDisplay($form_state);
    $form_mode = $form_display
      ->getTargetEntityTypeId() . '.' . $form_display
      ->getMode();
    $form_mode = EntityFormMode::load($form_mode);
    if ($form_mode) {
      $form['revision_information']['#access'] = $form_mode
        ->getThirdPartySetting('lightning_core', 'revision_ui', TRUE);
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function lightning_core_form_system_modules_alter(array &$form) {

  // This rule prevents acquia_telemetry module's description from increasing
  // the page width.
  $css = "#edit-modules-acquia-telemetry-enable-description { white-space: normal; overflow: hidden; }";
  $form['#attached']['html_head'][] = [
    [
      '#tag' => 'style',
      '#value' => $css,
    ],
    'acquia-telemetry-css',
  ];
}

/**
 * Rebuilds the service container.
 */
function lightning_core_rebuild_container() {
  require_once \Drupal::root() . '/core/includes/utility.inc';
  $class_loader = \Drupal::service('class_loader');
  $request = \Drupal::request();
  drupal_rebuild($class_loader, $request);
}

/**
 * Implements template_preprocess_block().
 */
function lightning_core_preprocess_block(array &$variables) {
  $variables['attributes']['data-block-plugin-id'] = $variables['elements']['#plugin_id'];
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function lightning_core_field_config_presave(FieldConfigInterface $field) {

  // Set the default image for user profiles.
  if ($field
    ->getTargetEntityTypeId() === 'user' && $field
    ->getName() === 'user_picture' && $field
    ->isNew() && !\Drupal::isConfigSyncing()) {
    $source = drupal_get_path('module', 'lightning_core') . '/images/default-avatar.png';
    $uri = 'public://default-avatar.png';
    try {
      \Drupal::service('file_system')
        ->copy($source, $uri, FileSystemInterface::EXISTS_ERROR);
      $file = File::create([
        'uri' => $uri,
      ]);
      $file
        ->setPermanent();
      $file
        ->save();
      $field
        ->setSetting('default_image', [
        'uuid' => $file
          ->uuid(),
        'alt' => (string) t('A generic silhouette of a person.'),
        'title' => '',
        'width' => 140,
        'height' => 140,
      ]);
    } catch (FileException $e) {

      // Fail silently.
    }
  }
}

/**
 * Returns the entity view display associated with a bundle and view mode.
 *
 * This is an exact copy of the deprecated entity_get_display() from Core 8.6.x
 *  except for one change: the default value of the $view_mode parameter.
 *
 * @todo Eliminate this in favor of
 *   \Drupal::service('entity_display.repository')->getViewDisplay() in Core
 *   8.8.x once that is the lowest supported version.
 *
 * @param string $entity_type
 *   The entity type.
 * @param string $bundle
 *   The bundle.
 * @param string $view_mode
 *   The view mode, or 'default' to retrieve the 'default' display object for
 *   this bundle.
 *
 * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface
 *   The entity view display associated with the view mode.
 *
 * @see \Drupal\Core\Entity\EntityStorageInterface::create()
 * @see \Drupal\Core\Entity\EntityStorageInterface::load()
 */
function lightning_core_entity_get_display($entity_type, $bundle, $view_mode = 'default') {

  // Try loading the display from configuration.
  $display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $view_mode);

  // If not found, create a fresh display object. We do not preemptively create
  // new entity_view_display configuration entries for each existing entity type
  // and bundle whenever a new view mode becomes available. Instead,
  // configuration entries are only created when a display object is explicitly
  // configured and saved.
  if (!$display) {
    $display = EntityViewDisplay::create([
      'targetEntityType' => $entity_type,
      'bundle' => $bundle,
      'mode' => $view_mode,
      'status' => TRUE,
    ]);
  }
  return $display;
}

/**
 * Returns the entity form display associated with a bundle and form mode.
 *
 * This is an exact copy of the deprecated entity_get_form_display() from Core
 * 8.6.x except for one change: the default value of the $form_mode parameter.
 *
 * @todo Eliminate this in favor of
 *   \Drupal::service('entity_display.repository')->getFormDisplay() in Core
 *   8.8.x once that is the lowest supported version.
 *
 * @param string $entity_type
 *   The entity type.
 * @param string $bundle
 *   The bundle.
 * @param string $form_mode
 *   The form mode.
 *
 * @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface
 *   The entity form display associated with the given form mode.
 *
 * @see \Drupal\Core\Entity\EntityStorageInterface::create()
 * @see \Drupal\Core\Entity\EntityStorageInterface::load()
 */
function lightning_core_entity_get_form_display($entity_type, $bundle, $form_mode = 'default') {

  // Try loading the entity from configuration.
  $entity_form_display = EntityFormDisplay::load($entity_type . '.' . $bundle . '.' . $form_mode);

  // If not found, create a fresh entity object. We do not preemptively create
  // new entity form display configuration entries for each existing entity type
  // and bundle whenever a new form mode becomes available. Instead,
  // configuration entries are only created when an entity form display is
  // explicitly configured and saved.
  if (!$entity_form_display) {
    $entity_form_display = EntityFormDisplay::create([
      'targetEntityType' => $entity_type,
      'bundle' => $bundle,
      'mode' => $form_mode,
      'status' => TRUE,
    ]);
  }
  return $entity_form_display;
}