access_policy-1.0.x-dev/access_policy.module

access_policy.module
<?php

/**
 * @file
 * Hook implementations for the access_policy module.
 */

use Drupal\access_policy\AccessPolicyEntityAccessControlHandler;
use Drupal\access_policy\AccessPolicyQueryAlter;
use Drupal\access_policy\EntityFieldAccessPolicyData;
use Drupal\access_policy\EntityOperations;
use Drupal\access_policy\EntityTypeInfo;
use Drupal\access_policy\FieldMatchAccessPolicyData;
use Drupal\access_policy\NodeFormAlter;
use Drupal\access_policy\UserFieldAccessPolicyData;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\node\NodeForm;
use Drupal\views\Plugin\views\cache\CachePluginBase;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\Plugin\views\query\Sql;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;

/**
 * Implements hook_entity_access().
 */
function access_policy_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(AccessPolicyEntityAccessControlHandler::class)
    ->access($entity, $account, $operation);
}

/**
 * Implements hook_module_implements_alter().
 */
function access_policy_module_implements_alter(&$implementations, $hook) {
  // Make sure that access_policy query alters happen last.
  if (in_array($hook, ['views_query_alter'], TRUE)) {
    $access_policy = $implementations['access_policy'];
    unset($implementations['access_policy']);
    $implementations['access_policy'] = $access_policy;
  }
}

/**
 * Implements hook_query_alter().
 */
function access_policy_query_alter(AlterableInterface $query) {
  $accessPolicyInfo = \Drupal::service('access_policy.information');
  $has_tag = FALSE;
  // If the entity type is provided then use that so we don't need to do a
  // lookup.
  $entity_type_id = $query->getMetaData('entity_type');
  if ($entity_type_id) {
    $entity_type_ids[] = $entity_type_id;
  }
  // Otherwise check all the currently supported entity types.
  else {
    $entity_types = $accessPolicyInfo->getAllEnabledEntityTypes();
    $entity_type_ids = array_map(function ($entity_type) {
      return $entity_type->id();
    }, $entity_types);
  }
  foreach ($entity_type_ids as $entity_type_id) {
    if ($query->hasTag($entity_type_id . '_access')) {
      $has_tag = TRUE;
      break;
    }
  }
  if ($has_tag) {
    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
    $is_access_controlled = $accessPolicyInfo->isAccessControlledEntityType($entity_type);
    if ($is_access_controlled) {
      \Drupal::service('class_resolver')
        ->getInstanceFromDefinition(AccessPolicyQueryAlter::class)
        ->queryAlter($query, $entity_type);
    }
  }
}

/**
 * Implements hook_views_query_alter().
 */
function access_policy_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($query instanceof Sql) {
    $table_info = $query->getEntityTableInfo();
    $base_table = reset($table_info);
    if (empty($base_table['entity_type']) || $base_table['relationship_id'] != 'none') {
      return;
    }

    // Add the entity type to the query so that it's easier to determine when
    // to run the query alter.
    $entity_type_id = $base_table['entity_type'];
    $query->build($view);
    $view->built = TRUE;

    // Add metadata to the DB query.
    $query = $view->build_info['query'];
    $query->addMetaData('entity_type', $entity_type_id);

    // Determine whether the access tag is missing from the view.
    // Sometimes a view will be missing an access tag. For example, it might not
    // have any applicable filters that rely on access checks.
    // If access policy is enabled then we always check access on views.
    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
    $accessPolicyInfo = \Drupal::service('access_policy.information');
    if (!$query->hasTag($entity_type_id . '_access') && $accessPolicyInfo->isAccessControlledEntityType($entity_type)) {
      $query->addTag($entity_type_id . '_access');
    }
  }
}

/**
 * Implements hook_query_entity_reference_alter().
 */
function access_policy_query_entity_reference_alter(AlterableInterface $query) {
  $entity_type_id = $query->getMetaData('entity_type');
  if ($query instanceof SelectInterface && $query->hasTag($entity_type_id . '_access')) {
    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
    $is_access_controlled = \Drupal::service('access_policy.information')->isAccessControlledEntityType($entity_type);
    if ($is_access_controlled) {
      return \Drupal::service('class_resolver')
        ->getInstanceFromDefinition(AccessPolicyQueryAlter::class)
        ->queryAlter($query, $entity_type);
    }
  }
}

/**
 * Implements hook_entity_type_alter().
 */
function access_policy_entity_type_alter(array &$entity_types) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityTypeInfo::class)
    ->entityTypeAlter($entity_types);
}

/**
 * Implements hook_entity_base_field_info().
 */
function access_policy_entity_base_field_info(EntityTypeInterface $entity_type) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityTypeInfo::class)
    ->entityBaseFieldInfo($entity_type);
}

/**
 * Implements hook_entity_operation_alter().
 */
function access_policy_entity_operation_alter(array &$operations, EntityInterface $entity) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->entityOperationAlter($operations, $entity);
}

/**
 * Implements hook_entity_presave().
 */
function access_policy_entity_presave(EntityInterface $entity) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->entityPresave($entity);
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function access_policy_access_policy_presave(EntityInterface $entity) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->accessPolicyPresave($entity);
}

/**
 * Implements hook_form_alter().
 */
function access_policy_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_state->getFormObject() instanceof EntityFormInterface) {
    \Drupal::service('class_resolver')
      ->getInstanceFromDefinition(EntityOperations::class)
      ->entityFormAlter($form, $form_state, $form_id);
  }

  if ($form_state->getFormObject() instanceof NodeForm) {
    \Drupal::service('class_resolver')
      ->getInstanceFromDefinition(NodeFormAlter::class)
      ->nodeFormAlter($form, $form_state, $form_id);
  }
}

/**
 * Implements hook_ENTITY_TYPE_update().
 */
function access_policy_access_policy_update(EntityInterface $entity) {
  // Clear field cache so extra field is added or removed.
  \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();

  // Clear the listing pages.
  $cache_tags = $entity->getTargetEntityType()->getListCacheTags();
  \Drupal::service('cache_tags.invalidator')->invalidateTags($cache_tags);

  // Clear the views data cache so the extra field is available in views.
  if (\Drupal::moduleHandler()->moduleExists('views')) {
    Views::viewsData()->clear();
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function access_policy_access_policy_insert(EntityInterface $entity) {
  $existing_policies = \Drupal::entityTypeManager()->getStorage('access_policy')
    ->loadByProperties(['target_entity_type_id' => $entity->getTargetEntityTypeId()]);
  // If this is the first policy for a given entity type then clear the
  // routes and register the access policy data.
  if (count($existing_policies) == 1) {
    \Drupal::service('router.builder')->setRebuildNeeded();
    \Drupal::service('access_policy.access_policy_data')->clear();
  }

  // Ensure that the access policy field is installed.
  _access_policy_install_access_policy_field($entity->getTargetEntityTypeId());

  // Clear field cache so extra field is added or removed.
  \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
  // Clear the views data cache so the extra field is available in views.
  if (\Drupal::moduleHandler()->moduleExists('views')) {
    Views::viewsData()->clear();
  }

  \Drupal::service('access_policy.information')->resetCache();
}

/**
 * Install the access policy field if it is missing.
 *
 * In rare cases the access_policy field might not be properly installed. This
 * can happen if an entity becomes compatible with Access policy after that
 * entity was originally installed. For example, perhaps a contrib module adds
 * bundle support to an entity that did not have it before.
 *
 * @param string $entity_type_id
 *   The entity type id.
 *
 * @see \Drupal\access_policy\EntityTypeInfo::entityBaseFieldInfo()
 */
function _access_policy_install_access_policy_field($entity_type_id) {
  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
  $exists = $definition_update_manager->getFieldStorageDefinition('access_policy', $entity_type_id);

  if (!$exists) {
    $field_manager = \Drupal::service('entity_field.manager');
    $schema_repository = \Drupal::service('entity.last_installed_schema.repository');
    $field_manager->useCaches(FALSE);
    $storage_definitions = $field_manager->getFieldStorageDefinitions($entity_type_id);
    $field_manager->useCaches(TRUE);
    $installed_storage_definitions = $schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id);
    foreach (array_diff_key($storage_definitions, $installed_storage_definitions) as $storage_definition) {
      if ($storage_definition->getProvider() == 'access_policy') {
        $definition_update_manager->installFieldStorageDefinition($storage_definition->getName(), $entity_type_id, 'access_policy', $storage_definition);
      }
    }
  }
}

/**
 * Implements hook_entity_insert().
 */
function access_policy_entity_insert(EntityInterface $entity) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->entityInsert($entity);
}

/**
 * Implements hook_entity_update().
 */
function access_policy_entity_update(EntityInterface $entity) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->entityUpdate($entity);
}

/**
 * Implements hook_entity_field_access().
 */
function access_policy_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface|null $items = NULL) {
  if ($items && $items->getEntity() instanceof AccountInterface) {
    return \Drupal::service('class_resolver')
      ->getInstanceFromDefinition(EntityOperations::class)
      ->userFieldAccess($operation, $field_definition, $account, $items);
  }

  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->entityFieldAccess($operation, $field_definition, $account, $items);
}

/**
 * Implements hook_field_widget_complete_form_alter().
 */
function access_policy_field_widget_complete_form_alter(&$elements, FormStateInterface $form_state, $context) {
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->fieldWidgetCompleteFormAlter($elements, $form_state, $context);
}

/**
 * Implements hook_field_config_insert().
 */
function access_policy_field_config_insert(FieldConfigInterface $field_config) {
  // When a new field is added, clear the access policy data definitions.
  \Drupal::service('access_policy.access_policy_data')->clear();
}

/**
 * Implements hook_access_policy_data().
 */
function access_policy_access_policy_data() {
  $data = [];

  // Define the broken access rule handler.
  $data['access_rule']['broken'] = [
    'label' => t('Broken/missing handler'),
    'description' => t('The handler is broken or missing.'),
    'plugin_id' => 'broken',
    'settings' => [
      'query' => FALSE,
    ],
    'selection_rule' => [
      'plugin_id' => 'broken',
    ],
  ];

  $data['global']['weekday_range'] = [
    'label' => t('Weekday range'),
    'description' => t('Grant access on certain days or hours of the week.'),
    'plugin_id' => 'weekday_range',
  ];

  $entity_data = \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityFieldAccessPolicyData::class)
    ->accessPolicyData();

  $user_data = \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(UserFieldAccessPolicyData::class)
    ->accessPolicyData();

  $matching_data = \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(FieldMatchAccessPolicyData::class)
    ->accessPolicyData();

  return NestedArray::mergeDeepArray([
    $data,
    $entity_data,
    $user_data,
    $matching_data,
  ], TRUE);
}

/**
 * Implements hook_views_post_render().
 */
function access_policy_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
  $accessPolicyInfo = \Drupal::service('access_policy.information');
  $entity_type = $view->getBaseEntityType();
  if ($entity_type instanceof EntityTypeInterface && $accessPolicyInfo->isAccessControlledEntityType($entity_type)) {
    $view->addCacheContext('user');
  }
}

/**
 * Implements hook_preprocess_HOOK() for dropbutton operations.
 *
 * This addresses a core bug where the operations links do not always have
 * proper cacheability support, causing the wrong dropbuttons to appear.
 *
 * @see https://www.drupal.org/project/drupal/issues/2473873
 */
function access_policy_preprocess_links__dropbutton__operations(&$variables) {
  if (!isset($variables['#cache']['contexts']) || !in_array('user', $variables['#cache']['contexts'])) {
    $variables['#cache']['contexts'][] = 'user';
  }
}

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

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