You are here

form_mode_control.module in Form Mode Control 8.2

Same filename and directory in other branches
  1. 8 form_mode_control.module

File

form_mode_control.module
View source
<?php

/**
 * @file
 * Contains form_mode_control.module.
 */
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\user\Entity\Role;

/**
 * Implements hook_entity_form_display_alter().
 */
function form_mode_control_entity_form_display_alter(&$form_display, $context) {
  $request = \Drupal::request();
  $display_name = $request->query
    ->get('display');

  // Load the right entity form display. Works for any entity / bundle.
  $id = $context['entity_type'] . '.' . $context['bundle'] . '.' . $display_name;
  $storage = \Drupal::entityTypeManager()
    ->getStorage('entity_form_display');
  $configuration = \Drupal::configFactory()
    ->getEditable('form_mode_control.settings')
    ->getRawData();
  $mode = NULL;
  switch ($context['form_mode']) {
    case "default":
    case "add":
      $mode = 'creation';
      break;
    case "edit":
      $mode = 'modification';
      break;
    case 'register':
      $mode = 'default';
      break;
  }
  if ($mode) {
    form_mode_control_control_access_form_mode($configuration, $mode, $display_name, $storage, $id, $form_display, $context);
  }
}

/**
 * Implements hook_form_alter().
 */
function form_mode_control_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == "entity_form_mode_add_form" || $form_id == "entity_form_mode_edit_form") {
    $form['markup'] = [
      '#type' => "markup",
      '#markup' => t('If you want to change to another form mode , add <strong style="color: #ff0000">?display=machine_name_form_mode.</strong>') . ' ',
    ];
  }
}

/**
 * Use the configuration to assemble an array for use by the configuration form.
 *
 * @param array $configurations
 *   Configuration to process.
 * @param string $mode
 *   Mode whose permission to check for.
 * @param string $id_role
 *   Which role to check for permission.
 *
 * @return array
 *   An array of form states.
 */
function form_mode_control_extract_config_form_states(array $configurations, $mode = 'creation', $id_role = "authenticated") {
  $configuration_form_state = [];
  foreach ($configurations as $form_state_key => $display) {
    if (empty($display)) {
      continue;
    }
    $form_state_key_parts = explode('+', $form_state_key);
    if (empty($form_state_key_parts)) {

      // Should not be an empty array.
      continue;
    }
    if (count($form_state_key_parts) != 4) {

      // Not a valid form state key.
      continue;
    }
    if ($form_state_key_parts[0] === $mode && $form_state_key_parts[1] === $id_role) {
      $configuration_form_state[$form_state_key] = $display;
    }
  }
  return $configuration_form_state;
}

/**
 * Extract the configuration to an array of permissions by form state.
 *
 * @param array $configurations
 *   Configuration to process.
 *
 * @return array
 *   An array of permissions.
 */
function form_mode_control_extract_config_permission_by_display(array $configurations) {
  $configuration_form_state = [];
  foreach ($configurations as $permission => $form_state_key) {
    if (substr_count($permission, "linked to") != 0) {
      $configuration_form_state[$form_state_key] = $permission;
    }
  }
  return $configuration_form_state;
}

/**
 * Determine the permission for an entity type, form mode, and role.
 *
 * @param string $display_query
 *   The form mode to use.
 * @param array $configuration
 *   Configuration to process.
 * @param array $context
 *   The entity type and bundle being examined.
 *
 * @return mixed
 *   The configured permission.
 */
function form_mode_control_get_permission_by_mode_and_role($display_query, array $configuration, array $context) {
  $permission_by_display = form_mode_control_extract_config_permission_by_display($configuration);
  $entity_type = $context['entity_type'];
  $bundle = $context['bundle'];
  $id = "{$entity_type}.{$bundle}.{$display_query}";
  if (!empty($permission_by_display[$id]) && EntityFormDisplay::load($id)
    ->status() == TRUE) {
    return $permission_by_display[$id];
  }
}

/**
 * Control the access to the form mode.
 *
 * @param array $configuration
 *   Configuration to process.
 * @param string $mode
 *   The form mode to check.
 * @param string $display_name
 *   The display to check.
 * @param \Drupal\Core\Entity\EntityStorageInterface $storage
 *   Storage interface for entity_form_display.
 * @param string $id
 *   Full display id in the form of entity_type.bundle.display_name.
 * @param mixed $form_display
 *   The EntityFormDisplay object being checked, and possibly modified.
 * @param array $context
 *   An array of additional context parameters including entity type and bundle.
 */
function form_mode_control_control_access_form_mode(array $configuration, $mode, $display_name, EntityStorageInterface $storage, $id, &$form_display, array $context) {

  // The role which has a maximum weight.
  $id_role = form_mode_control_get_role_id_with_max_weight();
  $permission_access_all = "access_all_form_modes";

  // Get the right permission by mode( creation or edit), the role and display
  // name used ( ?display_name = display ).
  $permission = form_mode_control_get_permission_by_mode_and_role($display_name, $configuration, $context);

  /*
   * Control the access to the form mode.
   * We have 3 conditions:
   * if the current user has access to all form modes , the default form mode is
   * activated ( default) else if you use ?display= correct_display else if the
   * user has access only to different form modes, the form mode used by default
   * is the form modes which the user has configured in
   * (www.your-site.com//admin/structure/display-modes/form/config-form-modes)
   * else finally, if the user does'nt has the permission to access to the form
   * mode, automatically, the form will returned with the default form mode
   * configured.
   */

  // Default display id is a backup when a specified display was not found.
  $default_display_id = form_mode_control_get_the_right_display($configuration, $mode, $id_role, $context);
  $default_display_id_parts = explode('.', $default_display_id);
  $form_mode_id = explode('.', $id)[2];
  $current_id = $id;
  if (empty($form_mode_id)) {

    // The form mode is not specified.
    // Try to retrieve at least the default form mode for the current user.
    if (!empty($default_display_id_parts[2])) {

      // The form mode is not specified and there is a default form mode for the
      // current user.
      $current_id = $default_display_id;
    }
  }
  if (\Drupal::currentUser()
    ->hasPermission($permission_access_all)) {

    // Load and replace the form display.

    /* @var \Drupal\Core\Entity\Entity\ $change_display */
    $change_display = $storage
      ->load($current_id);
    if ($change_display) {

      // The form mode exists and will be used instead.
      $form_display = $change_display;
      return;
    }

    // The form mode likely does not exist.
    if ($current_id === $default_display_id) {

      // We already tried to load the default display. Nothing more to be done.
      return;
    }
  }
  elseif (\Drupal::currentUser()
    ->hasPermission($permission)) {
    $change_display = $storage
      ->load($current_id);
    if ($change_display) {

      // The form mode exists.
      $form_display = $change_display;
      return;
    }

    // The user has permission but the display does not exist (anymore).
    if ($current_id === $default_display_id) {

      // We already tried to load the default display. Nothing more to be done.
      return;
    }
  }

  // At least try to use a default one.
  if (empty($default_display_id_parts[2])) {

    // There is no default display for the current user. Abort.
    return;
  }
  $change_display = $storage
    ->load($default_display_id);
  if (empty($change_display) || !$change_display
    ->status()) {

    // Couldn't get anything. Abort.
    return;
  }
  $form_display = $change_display;
}

/**
 * Choose the maximum weight for current user's role.
 *
 * @return int|string
 *   A maximum weight value to use.
 */
function form_mode_control_get_role_id_with_max_weight() {

  // Get all roles.

  /* @var \Drupal\user\Entity\Role[] $all_role_entities */
  $all_role_entities = Role::loadMultiple();
  $all_id_roles = array_keys($all_role_entities);

  // Get roles of current user.
  $roles_current_user = \Drupal::currentUser()
    ->getRoles();
  $roles_intersect = array_values(array_intersect($all_id_roles, $roles_current_user));

  // Get weight and id of the first role.
  $first_role = $roles_intersect[0];
  $max_weight = $all_role_entities[$first_role]
    ->getWeight();
  $id_role_max_weight = $first_role;
  foreach ($roles_intersect as $id_role) {
    if ($all_role_entities[$id_role]
      ->getWeight() > $max_weight) {

      // Use this role instead.
      $max_weight = $all_role_entities[$id_role]
        ->getWeight();
      $id_role_max_weight = $id_role;
    }
  }
  return $id_role_max_weight;
}

/**
 * If a user lacks permission for a form mode, redirect them to the default.
 *
 * @param array $configuration
 *   Configuration to process.
 * @param string $mode
 *   The form mode to check.
 * @param string $id_role
 *   Which role to check for permission.
 * @param array $context
 *   An array of additional context parameters including entity type and bundle.
 *
 * @return string
 *   The form display mode to use.
 */
function form_mode_control_get_the_right_display(array $configuration, $mode, $id_role, array $context) {
  $config_form_states = form_mode_control_extract_config_form_states($configuration, $mode, $id_role);
  foreach ($config_form_states as $form_state_key => $form_mode_id) {
    $display_settings = explode('.', $form_mode_id);
    $entity_type = $display_settings[0];
    $bundle = $display_settings[1];
    if ($context['entity_type'] == $entity_type && $context['bundle'] == $bundle) {

      // Build the display id to use for the given entity type, bundle, role and
      // mode.
      $display_name = $display_settings[2];
      $id = $context['entity_type'] . '.' . $context['bundle'] . '.' . $display_name;
      return $id;
    }
  }
}

/**
 * Get the label for a form display mode.
 *
 * @param string $entity_type
 *   Machine name of the entity type.
 * @param string $bundle
 *   Which bundle is being used.
 * @param string $display_searched
 *   The display whose label we want.
 *
 * @return mixed
 *   The display's label, possibly a render array, or a rendered string.
 */
function form_mode_control_get_label_from_machine_name($entity_type, $bundle, $display_searched) {
  $displays = \Drupal::service('entity_display.repository')
    ->getFormModeOptionsByBundle($entity_type, $bundle);
  foreach ($displays as $machine_name_display => $label_display) {
    if (is_object($label_display) && $display_searched == $machine_name_display) {
      return $label_display
        ->render();
    }
    else {
      if (!is_object($label_display) && $display_searched == $machine_name_display) {
        return $label_display;
      }
    }
  }
}

/**
 * Return the label of the bundle. (Ex. article => Article)
 *
 * @param string $entity_type
 *   Machine name of the entity type.
 * @param string $bundle_searched
 *   Which bundle is being used.
 *
 * @return mixed
 *   The label for the bundle (if found) or NULL.
 */
function form_mode_control_get_bundle_label($entity_type, $bundle_searched) {
  $bundles = \Drupal::service('entity_type.bundle.info')
    ->getBundleInfo($entity_type);
  return empty($bundles[$bundle_searched]) ? NULL : $bundles[$bundle_searched]['label'];
}

/**
 * Return the label of the entity type. Ex.(node => Content)
 *
 * @param string $entity_type
 *   Machine name of the entity type.
 *
 * @return mixed
 *   The entity type's label, possibly a render array, or a rendered string.
 */
function form_mode_control_get_entity_type_label($entity_type) {
  $label = \Drupal::service('entity_type.repository')
    ->getEntityTypeLabels()[$entity_type];
  if (is_object($label)) {
    return $label
      ->render();
  }
  return $label;
}

Functions

Namesort descending Description
form_mode_control_control_access_form_mode Control the access to the form mode.
form_mode_control_entity_form_display_alter Implements hook_entity_form_display_alter().
form_mode_control_extract_config_form_states Use the configuration to assemble an array for use by the configuration form.
form_mode_control_extract_config_permission_by_display Extract the configuration to an array of permissions by form state.
form_mode_control_form_alter Implements hook_form_alter().
form_mode_control_get_bundle_label Return the label of the bundle. (Ex. article => Article)
form_mode_control_get_entity_type_label Return the label of the entity type. Ex.(node => Content)
form_mode_control_get_label_from_machine_name Get the label for a form display mode.
form_mode_control_get_permission_by_mode_and_role Determine the permission for an entity type, form mode, and role.
form_mode_control_get_role_id_with_max_weight Choose the maximum weight for current user's role.
form_mode_control_get_the_right_display If a user lacks permission for a form mode, redirect them to the default.