domain_entity-8.x-1.0-beta1/domain_entity.module

domain_entity.module
<?php

/**
 * @file
 * Enables domain access for entities, and access query alter.
 *
 * @todo Add hook_entity_presave().
 * @todo Add domain_entity_query_alter().
 * @todo Add batching for field operations.
 * Check d7 code at https://github.com/skilld-labs/domain_entity/blob/7.x-1.x/domain_entity.module
 */

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\domain\DomainInterface;
use Drupal\domain_entity\DomainEntityMapper;
use Drupal\user\Entity\User;

/**
 * Implements hook_help().
 */
function domain_entity_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.domain_entity':
      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Domain Entity module allows users to manage domain fields on site content, assign access permissions for visibility of content.') . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Enabling domain fields on any entity') . '</dt>';
      $output .= '<dd>' . t('Overview page for all entities') . '</dd>';
      $output .= '<dt>' . t('Configuring query access') . '</dt>';
      $output .= '<dd>' . t('Allowing to load entities for all domains') . '</dd>';
      $output .= '<dt>' . t('Overriding default settings') . '</dt>';
      $output .= '<dd>' . t('Users with the appropriate permissions can override the default domain settings of an entity type.') . '</dd>';
      $output .= '</dl>';
      return $output;

    case 'domain_entity.ui':
      $output = '<p>' . t('Choose which entities are under Domain Access control, and choose domain entity widget behavior of bundles.') . '</p>';
      return $output;
  }
}

/**
 * Returns default values for entity reference field with domains.
 *
 * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
 *   The entity that contains field.
 * @param \Drupal\Core\Field\FieldDefinitionInterface $definition
 *   The field of the domain entity access.
 *
 * @return array
 *   Domains configured for the field.
 */
function domain_entity_field_default_domains(FieldableEntityInterface $entity, FieldDefinitionInterface $definition) {
  return $definition->getThirdPartySetting('domain_entity', 'domains', []);
}

/**
 * Implements hook_form_FORM_ID_alter() for 'field_storage_config_edit_form'.
 */
function domain_entity_form_field_storage_config_edit_form_alter(&$form, FormStateInterface $form_state) {
  /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
  $field_storage = $form_state->getFormObject()->getEntity();
  if ($field_storage->getName() === DomainEntityMapper::FIELD_NAME) {
    $form['cardinality_container']['cardinality']['#access'] = FALSE;
    $form['cardinality_container']['cardinality_number']['#access'] = FALSE;
    $form['cardinality_container']['#description'] = t('This field widget allow only unlimited values (the number of active domain).');
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for 'field_config_edit_form'.
 */
function domain_entity_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state) {
  /** @var \Drupal\field\FieldConfigInterface $field */
  $field = $form_state->getFormObject()->getEntity();
  if ($field->getName() === DomainEntityMapper::FIELD_NAME) {
    $form['required']['#disabled'] = TRUE;
  }
}

/**
 * Implements hook_entity_field_access().
 */
function domain_entity_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
  if ($field_definition->getName() === DomainEntityMapper::FIELD_NAME && $operation == 'edit') {
    /** @var \Drupal\field\Entity\FieldConfig $field_definition */
    $behavior = $field_definition->getThirdPartySetting('domain_entity', 'behavior', DomainEntityMapper::BEHAVIOR_AUTO);
    $access = AccessResult::allowedIfHasPermission($account, 'set domain access status for all entities');
    $access = $access->orIf(AccessResult::allowedIf($behavior == DomainEntityMapper::BEHAVIOR_USER));
    $access->addCacheableDependency($field_definition);
    // @todo Add remaining conditions.
    return $access;
  }
  return AccessResult::neutral();
}

/**
 * Returns the currently active domain.
 *
 * @return \Drupal\domain\DomainInterface
 *   The currently active domain.
 */
function domain_entity_get_domain() {
  $active_domain = \Drupal::service('domain.negotiator')->getActiveDomain();

  // @todo remove after https://www.drupal.org/project/domain/issues/3226427 is fixed?
  if (empty($active_domain)) {
    $active_domain = \Drupal::service('domain.negotiator')->getActiveDomain(TRUE);
  }

  return $active_domain;
}

/**
 * Returns the list domains for user.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *   Drupal user account.
 *
 * @return \Drupal\domain\DomainInterface[]
 *   List of domains.
 */
function domain_entity_get_user_domains(AccountInterface $account = NULL) {
  if (!isset($account)) {
    $account = \Drupal::currentUser();
  }
  $user = User::load($account->id());

  $user_domains = [];
  foreach ($user->get(DomainInterface::DOMAIN_ADMIN_FIELD) as $item) {
    if (is_object($item->entity)) {
      $user_domains[] = $item->entity->id();
    }
    else {
      \Drupal::logger('domain_entity')->error('The User-ID @uid attempt to load a user domain entity from an empty field.', ['@uid' => $user->id()]);
    }
  }
  return $user_domains;
}

/**
 * Return a list of domain id's, accessible by the current user.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *   Drupal user account.
 *
 * @return array
 *   List of domain id's.
 */
function domain_entity_get_user_available_domains(AccountInterface $account = NULL) {
  if (!isset($account)) {
    $account = \Drupal::currentUser();
  }

  // Get the current user list of granted domain id:
  // the current domain id OR for middle-office editors:
  // the list of assigned domain(s) id.
  $current_domain = domain_entity_get_domain();
  $accessible_domain_ids = [$current_domain->id()];

  // Middle office editors with permission see in administration,
  // entity from lists of assigned domains.
  $route = \Drupal::routeMatch()->getRouteObject();
  $is_admin = \Drupal::service('router.admin_context')->isAdminRoute($route);

  if ($is_admin && $account->hasPermission('access entities affiliate on assigned domains')) {
    $user_domain = domain_entity_get_user_domains($account);
    $accessible_domain_ids = !empty($user_domain) ? $user_domain : $accessible_domain_ids;
  }

  return $accessible_domain_ids;
}

/**
 * Returns the list of the domain_entity allowed entity types.
 *
 * @return \Drupal\Core\Entity\EntityTypeInterface[]
 *   Keyed array of enabled entity types.
 */
function domain_entity_allowed_entity_types() {
  $types = &drupal_static(__FUNCTION__);
  if (!isset($types)) {
    /** @var \Drupal\domain_entity\DomainEntityMapper $mapper */
    $mapper = \Drupal::service('domain_entity.mapper');
    $types = $mapper->getEnabledEntityTypes();
  }
  return $types;
}

/**
 * Implements hook_query_alter().
 *
 * Alter the enabled entities select query, add domain access conditions.
 */
function domain_entity_query_alter(AlterableInterface $query) {

  if (defined('MAINTENANCE_MODE') && (MAINTENANCE_MODE == 'install' || MAINTENANCE_MODE == 'update')) {
    // Do not fire at install & update time.
    return;
  }
  if (!\Drupal::config('domain_entity.settings')->get('bypass_access_conditions') && method_exists($query, 'getTables')) {
    // Have we to check access for this entity types.
    $allowed_types = domain_entity_allowed_entity_types();
    $entity_type_id = $query->getMetaData('entity_type');

    if (!isset($allowed_types[$entity_type_id])) {
      return;
    }
    // Skip access check for query without related tag.
    if (!$query->hasTag($entity_type_id . '_access')) {
      return;
    }
    if (!\Drupal::lock()->lockMayBeAvailable('router_rebuild')) {
      // Do not fire at route rebuild time.
      return;
    }
    // Get primary key of base table from entity type definition.
    $entity_key = $allowed_types[$entity_type_id]->getKey('id');

    // Get the accessible domain id's by the current user, in the current path.
    $accessible_domain_ids = domain_entity_get_user_available_domains();

    $tables = $query->getTables();
    $base_table_alias = key($tables);

    $field_name = DomainEntityMapper::FIELD_NAME;

    // This is an enabled domain entity,
    // prepare our custom access conditions.
    $domain_query = \Drupal::database()
      ->select($entity_type_id . '__' . $field_name, 'dom');
    $domain_query->where('dom.entity_id = ' . $base_table_alias . '.' . $entity_key);
    $domain_query->addExpression('1');

    // No domain restrictions found.
    $condition = new Condition('OR');
    $condition->notExists($domain_query);

    // Or restrictions contains allowed domains.
    $domain_query = clone $domain_query;
    $domain_query->condition('dom.' . $field_name . '_target_id', $accessible_domain_ids, 'IN');
    $condition->exists($domain_query);

    $query->condition($condition);
  }
}

// @codingStandardsIgnoreStart
/**
 * Implements hook_entity_presave().
 */
//function domain_entity_entity_presave($entity, $type) {
//  // Check if it's an allowed entity types:
//  $allowed_entity_types = domain_entity_allowed_entity_types();
//  if (!in_array($type, array_keys($allowed_entity_types))) {
//    return;
//  }
//  // Get domain_entity field type instances:
//  if ($field_instance = domain_entity_entity_field_instance($type)) {
//    $field_instance_name = $field_instance['name'];
//  }
//  else {
//    return FALSE;
//  }
//
//  // Get current domain:
//  $current_domain = domain_entity_get_domain();   // @fixme current = active domain
//  $entity_info = \Drupal::entityManager()->getDefinition($type);
//  // Get default bundle value
//  // e.g (all, current_domain, list(domain_id))
//  $bundle_key = $entity_info['entity keys']['bundle'];
//
//  if (isset($allowed_entity_types[$type][$entity->$bundle_key])) {
//    $default_values = reset($allowed_entity_types[$type][$entity->$bundle_key]);
//  }
//  else {
//    $default_values = array();
//  }
//  if (in_array(DOMAIN_ALL, $default_values)) {
//    $values = array();
//    $values[] = array(
//      'domain_id' => DOMAIN_ENTITY_SEND_TO_ALL,
//    );
//  }
//  elseif (in_array(DOMAIN_ACTIVE, $default_values)) {
//    $values = array(
//      0 => array(
//        'domain_id' => $current_domain['domain_id'],
//      ),
//    );
//  }
//  else {
//    $values = array();
//    foreach ($default_values as $did) {
//      $values[] = array(
//        'domain_id' => $did,
//      );
//    }
//  }
//  // Ensure this entities have almost a default value.
//  // Attach it to current domain if the entity is created,
//  // by bypassing entity creation form,
//  // do not let an unset domain entity saved,
//  // (or the entity became inaccessible everywhere).
//  if (!isset($entity->$field_instance_name)) {
//    // Populate field instance with the default bundle domain value,
//    // if is not already set or unassigned.
//    $entity->$field_instance_name = array(
//      \Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED => $values,
//    );
//  }
//  else {
//    // Populate field instance with the default bundle domain value,
//    // if is not already set or unassigned.
//    $value = $entity->$field_instance_name;
//    if (empty($value) || !isset($value[\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED][0]) || !$value[\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED][0]['domain_id']) {
//      $entity->$field_instance_name = array(
//        \Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED => $values,
//      );
//    }
//  }
//  return $entity;
//}

/**
 * Helper function to active domain field on bundles of entity types.
 *
 * @param array $entity_types
 *   List of Entity types, that list her bundles.
 */
//function domain_entity_types_enable_domain_field($entity_types) {
//  // Common settings.
//  $field_type = 'domain_entity';
//  $label = t('Domain');
//  $required = TRUE;
//  $entities_to_update = array();
//  // Reset the entity info, before enabling domain access on entity.
//  // Some entities are not fieldable, but this module force it to.
//  \Drupal::entityManager()->clearCachedDefinitions();
//  // Create fields instance.
//  foreach ($entity_types as $entity_type => $bundles) {
//    $field_name = domain_entity_get_entity_field_name($entity_type);
//    $entity_info = \Drupal::entityManager()->getDefinition($entity_type);
//
//    foreach ($bundles as $bundle => $widget) {
//      // Look for or add the specified field to the requested entity bundle.
//      $instance = field_info_instance($entity_type, $field_name, $bundle);
//      if (empty($instance)) {
//        domain_entity_create_field_instance($field_name, $field_type, $required, $entity_type, $bundle, $label, key($widget));
//        drupal_set_message(t("Domain Access behaviour '@widget' has been enabled on the bundle @type of @entity entity type", array(
//        '@widget' => key($widget),
//        '@type' => $bundle,
//        '@entity' => $entity_type,
//        )));
//      }
//    }
//
//    // Query to look at unafilliated entities.
//    $entity_key = $entity_info['entity keys']['id'];
//
//    $query = new EntityFieldQuery;
//    $query->entityCondition('entity_type', $entity_type);
//    $query->fieldCondition($field_name, 'domain_id', NULL);
//    $unaffiliated_entities = $query->execute();
//
//    if (!empty($unaffiliated_entities[$entity_type])) {
//      $entities_to_update[$entity_type] = array();
//      foreach ($unaffiliated_entities[$entity_type] as $key => $value) {
//        $id = $value->$entity_key;
//        $entities_to_update[$entity_type][] = $id;
//       }
//     }
//
//  }
//  // Clear cache as we are going to update existing entities field values.
//  \Drupal::entityManager()->clearCachedFieldDefinitions();
//
//  // Create a batch operation to update entities that are not affiliated to a domain.
//  $operations = array();
//  foreach ($entities_to_update as $entity_type => $entities) {
//    foreach ($entities as $entity_id) {
//      $operations[] = array('_domain_entity_update_entity_defaut_value', array(
//          $entity_type,
//          $entity_id,
//        ));
//    }
//  }
//  $batch = array(
//    'operations' => $operations,
//    'title' => t('Update existing entities domain affiliation default values'),
//    'error_message' => t('The domain access update has encountered an error.'),
//    'finished' => '_domain_entity_update_entity_defaut_value_finished',
//  );
//  if (count($operations)) {
//// Bypass access restriction to allow the current user,
//// to access the entity that are not already assigned.
//// @FIXME - dome, need checking
//// Could not extract the default value because it is either indeterminate, or
//// not scalar. You'll need to provide a default value in
//// config/install/domain_entity.settings.yml and config/schema/domain_entity.schema.yml.
//$domain_entity_allowed_entity_types_backup = \Drupal::config('domain_entity.settings')->get('allowed_entity_types');
//    \Drupal::configFactory()->getEditable('domain_entity.settings')->set('bypass_access_conditions_backup', \Drupal::config('domain_entity.settings')->get('bypass_access_conditions'))->save();
//    \Drupal::configFactory()->getEditable('domain_entity.settings')->set('bypass_access_conditions', TRUE)->save();
//    batch_set($batch);
//  }
//  else {
//    drupal_set_message(t('0 entities updated.'));
//  }
//}

/**
 * Batch operation processing callback.
 */
//function _domain_entity_update_entity_defaut_value($entity_type, $entity_id, &$context) {
//  $entity = entity_load_single($entity_type, $entity_id);
//  if ($entity) {
//    // Just call entity_save(), the hook domain_entity_entity_presave()
//    // take care of the field domain default assignation(s), if nothing is set.
//    $entity->save();
//    $context['results'][] = $entity_type . ' - Id : ' . $entity_id . ' updated.';
//    $context['message'] = t('Updated: %entity_type - ID : %entity_id.', array('%entity_type' => $entity_type, '%entity_id' => $entity_id));
//  }
//
//}

/**
 * Batch operation finished callback.
 */
//function _domain_entity_update_entity_defaut_value_finished($finished, $results) {
//  // Restore entity type domain access.
//  \Drupal::configFactory()->getEditable('domain_entity.settings')->set('bypass_access_conditions', \Drupal::config('domain_entity.settings')->get('bypass_access_conditions_backup'))->save();
//  \Drupal::config('domain_entity.settings')->clear('bypass_access_conditions_backup')->save();
//  drupal_set_message(t('%count entities updated.', array('%count' => count($results))));
//}

/**
 * Implements hook_entity_access().
 *
 * @see domain_access_node_access
 */
function domain_entity_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
  // Return a neutral result if hook is accessed through cli.
  if (php_sapi_name() == 'cli') {
    return AccessResult::neutral();
  }

  // Ensure quick administration.
  $is_admin = \Drupal::service('router.admin_context')->isAdminRoute();
  if ($is_admin && (in_array('administrator', $account->getRoles()) || $account->hasPermission('publish to any domain'))) {
    return AccessResult::neutral();
  }

  // Should be a fieldable entity with domain field.
  if (!($entity instanceof FieldableEntityInterface)) {
    return AccessResult::neutral();
  }
  if (!$entity->hasField(DomainEntityMapper::FIELD_NAME)) {
    return AccessResult::neutral();
  }

  // Restrict access like it's done in domain_access module.
  $type = $entity->bundle();
  $typeEntity = $entity->getEntityTypeId();
  $manager = \Drupal::service('domain_access.manager');
  if ($operation == 'view' && $manager->checkEntityAccess($entity, $account)) {
    if (method_exists($entity, "isPublished") && $entity->isPublished()) {
      return AccessResult::neutral();
    }
    elseif ($account->hasPermission('view unpublished domain content')) {
      return AccessResult::neutral();
    }
  }

  if ($operation == 'update') {
    if ($account->hasPermission('update ' . $type . ' '. $typeEntity . ' content on assigned domains') && $manager->checkEntityAccess($entity, $account)) {
      return AccessResult::neutral();
    }
    elseif ($account->hasPermission('edit domain content') && $manager->checkEntityAccess($entity, $account)) {
      return AccessResult::neutral();
    }
  }

  if ($operation == 'delete') {
    if ($account->hasPermission('delete ' . $type . ' '. $typeEntity . ' content on assigned domains') && $manager->checkEntityAccess($entity, $account)) {
      return AccessResult::neutral();
    }
    elseif ($account->hasPermission('delete domain content') && $manager->checkEntityAccess($entity, $account)) {
      return AccessResult::neutral();
    }
  }

  $domains = _domain_entity_get_related_domains($entity);

  // If specific domains was not selected means:
  // Should be accessible for all domains (no restrictions).
  if (!$domains) {
    return AccessResult::neutral();
  }

  $current_domain = domain_entity_get_domain();

  if (isset($domains[$current_domain->id()])) {
    return AccessResult::neutral();
  }

  return AccessResult::forbidden()->addCacheableDependency($current_domain);
}

/*
 * Implements hook_entity_create_access().
 *
 * @see domain_access_node_create_access
 */
function domain_entity_entity_create_access(AccountInterface $account, array $context, $entity_bundle) {
  // Check to see that we have a valid active domain.
  // Without one, we cannot assert an opinion about access.
  /** @var \Drupal\domain\DomainInterface $active */
  if ($active = \Drupal::service('domain.negotiator')->getActiveDomain()) {
    $id = $active->getDomainId();
  }
  else {
    return AccessResult::neutral();
  }
  // Load the full user record.
  $user = \Drupal::entityTypeManager()->getStorage('user')->load($account->id());
  $user_domains = \Drupal::service('domain_access.manager')->getAccessValues($user);
  if (($account->hasPermission('create ' . $entity_bundle . ' '. $context['entity_type_id'] . ' content on assigned domains')
      || $account->hasPermission('create domain content'))
    && in_array($id, $user_domains)) {
    // Note the cache context here!
    return AccessResult::allowed()->addCacheContexts(['user.permissions', 'url.site']);
  }
  // No opinion.
  return AccessResult::neutral();
}
/**
 * Return domain IDs list assigned to the requested entity.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   Entity object.
 *
 * @return array
 *   Domain IDs list assigned to the requested entity.
 */
function _domain_entity_get_related_domains(EntityInterface $entity) {

  $domains = [];
  $values = $entity->get(DomainEntityMapper::FIELD_NAME)->getValue();

  if (!$values) {
    return $domains;
  }

  foreach ($values as $value) {
    if (isset($value['target_id'])) {
      $domains[$value['target_id']] = $value['target_id'];
    }
  }

  return $domains;
}

/**
 * Implements hook_domain_references_alter().
 */
function domain_entity_domain_references_alter($query, $account, $context) {

  if ($account->hasPermission('publish to any domain')) {
    return;
  }

  // Limit list of domains that can be used by requested user.
  $allowed = \Drupal::service('domain_access.manager')->getAccessValues($account);
  $query->condition('id', array_keys($allowed), 'IN');
}

/**
 * Implements hook_field_widget_single_element_form_alter().
 */
function domain_entity_field_widget_single_element_form_alter(&$element, FormStateInterface $form_state, $context) {

  if ($context['items']->getFieldDefinition()->getName() !== DomainEntityMapper::FIELD_NAME) {
    return;
  }

  $form_object = $form_state->getFormObject();
  if (!$form_object instanceof EntityFormInterface) {
    return;
  }
  // Get the current Entity information.
  $entity = $form_object->getEntity();

  // Add Default value if we are creating a new Entity.
  if ((is_object($entity)) && ($entity->isNew())) {
    // Get active Domain ID.
    $active_id = \Drupal::service('domain.negotiator')->getActiveId();

    // Default value based on the current Active Domain.
    $element['#default_value'] = [$active_id];
  }

  // Make affiliate domain selection required in case if user
  // have no "publish to any domain" permission to avoid ambiguity.
  $element['#required'] = !\Drupal::currentUser()->hasPermission('publish to any domain');
}

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

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