form_field_access-1.0.0-alpha1/src/FormFieldAccess.php

src/FormFieldAccess.php
<?php

namespace Drupal\form_field_access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Session\AccountInterface;

class FormFieldAccess implements TrustedCallbackInterface {

  /**
   * Implements hook_entity_field_access().
   *
   * @param $operation
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   * @param \Drupal\Core\Session\AccountInterface $account
   * @param \Drupal\Core\Field\FieldItemListInterface|NULL $items
   *
   * @return \Drupal\Core\Access\AccessResultForbidden|\Drupal\Core\Access\AccessResultNeutral
   *   Access result.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function entityFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
    $result = AccessResult::neutral();

    if ($operation === 'edit'
      && !empty($items)
    ) {
      $parent_data_definition = $items->getParent()->getDataDefinition();
      $parent_entity_type_id = $parent_data_definition->getEntityTypeId();
      $parent_bundles = $parent_data_definition->getBundles();
      $parent_bundle = reset($parent_bundles);

      if ($form_field_access = self::loadFormFieldAccess($parent_entity_type_id, $parent_bundle)) {
        if (!empty($form_field_access)) {
          $field_roles = $form_field_access->getDisallowedFieldRoles($field_definition->getName());
          if (!empty($field_roles)) {
            $matched_roles = array_intersect($field_roles, $account->getRoles());
            if (!empty($matched_roles)) {
              $result = AccessResult::forbidden();
            }
          }
        }
      }
    }

    return $result;
  }

  /**
   * Implements hook_element_info_alter().
   *
   * @param array $info
   *   Elements list.
   */
  public function elementInfoAlter(array &$info): void {
    foreach ($info as $key => &$value) {
      $value['#pre_render'][] = [FormFieldAccess::class, 'preRenderAccess'];
      if (isset($value['#input']) && $value['#input'] === TRUE) {
        $value['#process'][] = [FormFieldAccess::class, 'processAccess'];
      }
    }
  }

  /**
   * {@inheritDoc}
   */
  public static function trustedCallbacks() {
    return ['processAccess', 'preRenderAccess'];
  }

  /**
   * Pre-render method to visually hide sections without fields accessed.
   *
   * @param array $element
   *   Form element.
   *
   * @return array
   *   Form element.
   */
  public static function preRenderAccess(array $element) {
    if (isset($element['#type'])
      && in_array($element['#type'], ['form', 'container', 'details'])
    ) {
      $child_access = TRUE;

      $children = Element::children($element);
      foreach ($children as $child) {
        $sub_element = $element[$child];
        $child_access &= isset($sub_element['#access']) && $sub_element['#access'] === FALSE;
      }
      if ($child_access) {
        $element['#attributes']['class'][] = 'visually-hidden';
        if (isset($element['widget'])) {
          $element['widget']['#attributes']['class'][] = 'visually-hidden';
        }
      }
    }

    return $element;
  }

  /**
   * Enforce form fields to be required based on given roles.
   *
   * @param $element
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   * @param $complete_form
   *
   * @return mixed
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public static function processAccess(&$element, FormStateInterface $form_state, &$complete_form) {
    $form_object = $form_state->getFormObject();
    if (empty($form_object)
      || is_callable([
        $form_state,
        'getOperation',
      ]) && $form_object->getOperation() !== 'edit'
    ) {
      return $element;
    }

    if (!is_callable([$form_object, 'getEntity'])) {
      return $element;
    }

    $entity = $form_object->getEntity();
    if (empty($entity)) {
      return $element;
    }

    $entity_type_id = $entity->getEntityTypeId();
    $bundle = $entity->bundle();


    if ($form_field_access = self::loadFormFieldAccess($entity_type_id, $bundle)) {
      $account_roles = \Drupal::currentUser()->getRoles();

      // Does not support fields eg revision_log[0][value].
      $field_name = preg_replace('/\[.*$/', '', $element['#name']);

      // Set require flag.
      $required_field_roles = $form_field_access->getRequiredFieldRoles($field_name);
      if (!empty($required_field_roles)) {
        $matched_roles = array_intersect($required_field_roles, $account_roles);
        if (!empty($matched_roles)) {
          $element['#required'] = TRUE;
        }
      }

      // Set disabled access flag.
      // Operates on form field level. To make it works on field level entityFieldAccess method is used.
      $disallowed_field_roles = $form_field_access->getDisallowedFieldRoles($field_name);
      if (!empty($disallowed_field_roles)) {
        $matched_roles = array_intersect($disallowed_field_roles, $account_roles);
        if (!empty($matched_roles)) {
          $element['#access'] = FALSE;
        }
      }
    }

    return $element;
  }

  /**
   * Load Form Field Access configuration.
   *
   * @param string $entity_type_id
   *   Entity Type ID.
   * @param string $bundle
   *   Entity Bundle.
   *
   * @return \Drupal\form_field_access\Entity\FormFieldAccess|null
   *   Form Field Access configuration.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected static function loadFormFieldAccess(string $entity_type_id, string $bundle) {
    /** @var \Drupal\form_field_access\Entity\FormFieldAccess $form_field_access */
    $form_field_access = \Drupal::entityTypeManager()
      ->getStorage('form_field_access')
      ->load($entity_type_id . '.' . $bundle);

    return $form_field_access;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc