domain_access.module in Domain Access 8
Domain-based access control for content.
File
domain_access/domain_access.moduleView source
<?php
/**
* @file
* Domain-based access control for content.
*/
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\node\NodeInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Form\FormState;
use Drupal\domain_access\DomainAccessManagerInterface;
/**
* The name of the node access control field.
*
* @deprecated This constant will be replaced in the final release by
* Drupal\domain\DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD.
*/
const DOMAIN_ACCESS_FIELD = 'field_domain_access';
/**
* The name of the all affiliates field.
*
* @deprecated This constant will be replaced in the final release by
* Drupal\domain\DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD.
*/
const DOMAIN_ACCESS_ALL_FIELD = 'field_domain_all_affiliates';
/**
* Implements hook_node_grants().
*/
function domain_access_node_grants(AccountInterface $account, $op) {
$grants = [];
/** @var \Drupal\domain\Entity\Domain $active */
$active = \Drupal::service('domain.negotiator')
->getActiveDomain();
if (empty($active)) {
$active = \Drupal::entityTypeManager()
->getStorage('domain')
->loadDefaultDomain();
}
// No domains means no permissions.
if (empty($active)) {
return $grants;
}
$id = $active
->getDomainId();
// Advanced grants for edit/delete require permissions.
/** @var \Drupal\user\UserInterface $user */
$user = \Drupal::entityTypeManager()
->getStorage('user')
->load($account
->id());
$user_domains = \Drupal::service('domain_access.manager')
->getAccessValues($user);
// Grants for view are simple. Use the active domain and all affiliates.
// Note that "X to any domain" is a global permission designed for admins.
if ($op == 'view') {
$grants['domain_id'][] = $id;
$grants['domain_site'][] = 0;
if ($user
->hasPermission('view unpublished domain content')) {
if ($user
->hasPermission('publish to any domain') || in_array($id, $user_domains) || !empty($user
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value)) {
$grants['domain_unpublished'][] = $id;
}
}
}
elseif ($op == 'update' && $user
->hasPermission('edit domain content')) {
if ($user
->hasPermission('publish to any domain') || in_array($id, $user_domains) || !empty($user
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value)) {
$grants['domain_id'][] = $id;
}
}
elseif ($op == 'delete' && $user
->hasPermission('delete domain content')) {
if ($user
->hasPermission('publish to any domain') || in_array($id, $user_domains) || !empty($user
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value)) {
$grants['domain_id'][] = $id;
}
}
return $grants;
}
/**
* Implements hook_node_access_records().
*/
function domain_access_node_access_records(NodeInterface $node) {
$grants = [];
// Create grants for each translation of the node. See the report at
// https://www.drupal.org/node/2825419 for the logic here. Note that right
// now, grants may not be the same for all languages.
$translations = $node
->getTranslationLanguages();
foreach ($translations as $langcode => $language) {
$translation = $node
->getTranslation($langcode);
// If there are no domains set, use the current one.
$domains = \Drupal::service('domain_access.manager')
->getAccessValues($translation);
/** @var \Drupal\domain\DomainInterface $active */
if (empty($domains) && ($active = \Drupal::service('domain.negotiator')
->getActiveDomain())) {
$domains[$active
->id()] = $active
->getDomainId();
}
foreach ($domains as $id => $domainId) {
/** @var \Drupal\domain\DomainInterface $domain */
if ($domain = \Drupal::entityTypeManager()
->getStorage('domain')
->load($id)) {
$grants[] = [
'realm' => $translation
->isPublished() ? 'domain_id' : 'domain_unpublished',
'gid' => $domain
->getDomainId(),
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 1,
'langcode' => $langcode,
];
}
}
// Set the domain_site grant.
if ($translation
->hasField(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD) && !empty($translation
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value) && $translation
->isPublished()) {
$grants[] = [
'realm' => 'domain_site',
'gid' => 0,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'langcode' => $langcode,
];
}
else {
$grants[] = [
'realm' => 'domain_site',
'gid' => 1,
'grant_view' => 0,
'grant_update' => 0,
'grant_delete' => 0,
'langcode' => $langcode,
];
}
}
return $grants;
}
/**
* Implements hook_ENTITY_TYPE_presave().
*
* Fires only if Devel Generate module is present, to assign test nodes to
* domains.
*/
function domain_access_node_presave(EntityInterface $node) {
domain_access_presave_generate($node);
}
/**
* Implements hook_ENTITY_TYPE_presave().
*
* Fires only if Devel Generate module is present, to assign test nodes to
* domains.
*/
function domain_access_user_presave(EntityInterface $account) {
domain_access_presave_generate($account);
}
/**
* Handles presave operations for devel generate.
*/
function domain_access_presave_generate(EntityInterface $entity) {
if (!$entity
->hasField(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)) {
return;
}
// There is a core bug https://www.drupal.org/node/2609252 that causes a
// fatal database errors if the boolean DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD is set when
// a user cannot access the field. See domain_access_entity_field_access().
// To overcome this issue, we cast the boolean to integer, which prevents the
// failure.
$value = (int) $entity
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value;
$entity
->set(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD, $value);
// Handle devel module settings.
$exists = \Drupal::moduleHandler()
->moduleExists('devel_generate');
$values = [];
if ($exists && isset($entity->devel_generate)) {
// If set by the form.
if (isset($entity->devel_generate['domain_access'])) {
$selection = array_filter($entity->devel_generate['domain_access']);
if (isset($selection['random-selection'])) {
$domains = \Drupal::entityTypeManager()
->getStorage('domain')
->loadMultiple();
$values[DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD] = array_rand($domains, ceil(rand(1, count($domains))));
}
else {
$values[DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD] = array_keys($selection);
}
}
if (isset($entity->devel_generate['domain_all'])) {
$selection = $entity->devel_generate['domain_all'];
if ($selection == 'random-selection') {
$values[DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD] = rand(0, 1);
}
else {
$values[DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD] = $selection = 'yes' ? 1 : 0;
}
}
foreach ($values as $name => $value) {
$entity
->set($name, $value);
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add options for domains when using Devel Generate.
*/
function domain_access_form_devel_generate_form_content_alter(&$form, &$form_state, $form_id) {
// Add our element to the Devel generate form.
$form['submit']['#weight'] = 10;
$list = [
'random-selection' => t('Random selection'),
];
$list += \Drupal::entityTypeManager()
->getStorage('domain')
->loadOptionsList();
$form['domain_access'] = [
'#title' => t('Domains'),
'#type' => 'checkboxes',
'#options' => $list,
'#weight' => 2,
'#multiple' => TRUE,
'#size' => count($list) > 5 ? 5 : count($list),
'#default_value' => [
'random-selection',
],
'#description' => t('Sets the domains for created nodes. Random selection overrides other choices.'),
];
$form['domain_all'] = [
'#title' => t('Send to all affiliates'),
'#type' => 'radios',
'#options' => [
'random-selection' => t('Random selection'),
'yes' => t('Yes'),
'no' => t('No'),
],
'#default_value' => 'random-selection',
'#weight' => 3,
'#description' => t('Sets visibility across all affiliates.'),
];
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add options for domains when using Devel Generate.
*/
function domain_access_form_devel_generate_form_user_alter(&$form, &$form_state, $form_id) {
domain_access_form_devel_generate_form_content_alter($form, $form_state, $form_id);
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
*
* Move Domain Access fields to an advanced tab like other node settings.
*/
function domain_access_form_node_form_alter(&$form, FormState $form_state, $form_id) {
$move_enabled = \Drupal::config('domain_access.settings')
->get('node_advanced_tab');
if ($move_enabled && isset($form[DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]) && isset($form[DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD]) && empty($form[DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]['#group']) && empty($form[DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD]['#group'])) {
// Move to the tabs on the entity form.
$form[DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]['#group'] = 'domain';
$form[DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD]['#group'] = 'domain';
$form['domain'] = [
'#type' => 'details',
'#open' => (bool) \Drupal::config('domain_access.settings')
->get('node_advanced_tab_open'),
'#title' => t('Domain settings'),
'#group' => 'advanced',
'#attributes' => [
'class' => [
'node-form-options',
],
],
'#attached' => [
'library' => [
'node/drupal.node',
],
],
'#weight' => 100,
'#optional' => TRUE,
];
}
// Add the options hidden from the user silently to the form.
$manager = \Drupal::service('domain.element_manager');
$form = $manager
->setFormOptions($form, $form_state, DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD);
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for \Drupal\user\UserForm.
*
* Handle settings that the user cannot access.
*/
function domain_access_form_user_form_alter(&$form, &$form_state, $form_id) {
// Add the options hidden from the user silently to the form.
$manager = \Drupal::service('domain.element_manager');
$form = $manager
->setFormOptions($form, $form_state, DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD);
}
/**
* Implements hook_domain_references_alter().
*/
function domain_access_domain_references_alter($query, $account, $context) {
// Restrict domains by editorial assignment.
if ($context['field_type'] != 'editor') {
return;
}
switch ($context['entity_type']) {
case 'node':
if ($account
->hasPermission('publish to any domain')) {
break;
}
elseif ($account
->hasPermission('publish to any assigned domain')) {
if (!empty($account
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value)) {
break;
}
$allowed = \Drupal::service('domain_access.manager')
->getAccessValues($account);
$query
->condition('id', array_keys($allowed), 'IN');
}
else {
// Remove all options.
$query
->condition('id', '-no-possible-match-');
}
break;
case 'user':
if ($account
->hasPermission('assign editors to any domain')) {
// Do nothing.
}
elseif ($account
->hasPermission('assign domain editors')) {
if (!empty($account
->get(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD)->value)) {
break;
}
$allowed = \Drupal::service('domain_access.manager')
->getAccessValues($account);
$query
->condition('id', array_keys($allowed), 'IN');
}
else {
// Remove all options.
$query
->condition('id', '-no-possible-match-');
}
break;
default:
// No action taken.
break;
}
}
/**
* Implements hook_node_access().
*/
function domain_access_node_access(NodeInterface $node, $op, AccountInterface $account) {
static $active_domain;
if (!isset($active_domain)) {
// Ensure that the loader has run. In some tests, the kernel event has not.
$active = \Drupal::service('domain.negotiator')
->getActiveDomain();
if (empty($active)) {
$active = \Drupal::service('domain.negotiator')
->getActiveDomain(TRUE);
}
$active_domain = $active;
}
// Check to see that we have a valid active domain.
// Without one, we cannot assert an opinion about access.
if (!$active_domain || empty($active_domain
->getDomainId())) {
return AccessResult::neutral()
->addCacheableDependency($node);
}
$type = $node
->bundle();
$manager = \Drupal::service('domain_access.manager');
$allowed = FALSE;
// In order to access update or delete, the user must be able to view.
// Domain-specific permissions are relevant only if the node is not published.
if ($op == 'view') {
if ($node
->isPublished()) {
// Explicit restatement of the condition, for clarity.
$allowed = FALSE;
}
elseif ($account
->hasPermission('view unpublished domain content') && $manager
->checkEntityAccess($node, $account)) {
$allowed = TRUE;
}
}
if ($op == 'update') {
if ($account
->hasPermission('update ' . $type . ' content on assigned domains') && $manager
->checkEntityAccess($node, $account)) {
$allowed = TRUE;
}
elseif ($account
->hasPermission('edit domain content') && $manager
->checkEntityAccess($node, $account)) {
$allowed = TRUE;
}
}
if ($op == 'delete') {
if ($account
->hasPermission('delete ' . $type . ' content on assigned domains') && $manager
->checkEntityAccess($node, $account)) {
$allowed = TRUE;
}
elseif ($account
->hasPermission('delete domain content') && $manager
->checkEntityAccess($node, $account)) {
$allowed = TRUE;
}
}
if ($allowed) {
return AccessResult::allowed()
->cachePerPermissions()
->cachePerUser()
->addCacheableDependency($node);
}
// No opinion on FALSE.
return AccessResult::neutral()
->addCacheableDependency($node);
}
/**
* Implements hook_node_create_access().
*
* @link https://www.drupal.org/node/2348203
*/
function domain_access_node_create_access(AccountInterface $account, $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 . ' 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();
}
/**
* Implements hook_entity_field_access().
*
* Hides the domain access fields from the entity add/edit forms
* when the user cannot access them.
*/
function domain_access_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
// If not editing an entity, do nothing.
if ($operation !== 'edit' || empty($items)) {
return AccessResult::neutral();
}
// The entity the field is attached to.
$entity = $items
->getEntity();
if ($field_definition
->getName() == DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD) {
if ($entity instanceof AccountInterface) {
$access = AccessResult::allowedIfHasPermissions($account, [
'assign domain editors',
'assign editors to any domain',
], 'OR');
}
elseif ($entity instanceof NodeInterface) {
// Treat any other entity as content.
$access = AccessResult::allowedIfHasPermissions($account, [
'publish to any domain',
'publish to any assigned domain',
], 'OR');
}
// allowedIfHasPermissions returns allowed() or neutral().
// In this case, we want it to be forbidden,
// if user doesn't have the permissions above.
if (isset($access) && !$access
->isAllowed()) {
return AccessResult::forbidden();
}
}
elseif ($field_definition
->getName() == DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD) {
if ($entity instanceof AccountInterface) {
return AccessResult::forbiddenIf(!$account
->hasPermission('assign editors to any domain'));
}
elseif ($entity instanceof NodeInterface) {
// Treat any other entity as content.
return AccessResult::forbiddenIf(!$account
->hasPermission('publish to any domain'));
}
}
return AccessResult::neutral();
}
/**
* Implements hook_ENTITY_TYPE_insert().
*
* Creates our fields when new node types are created.
*/
function domain_access_node_type_insert(EntityInterface $entity) {
/** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
if (!$entity
->isSyncing()) {
// Do not fire hook when config sync in progress.
domain_access_confirm_fields('node', $entity
->id());
}
}
/**
* Implements hook_ENTITY_TYPE_insert().
*
* In some cases, form display modes are not set when the node type is created.
* be sure to update our field definitions on creation of form_display for
* node types.
*/
function domain_access_entity_form_display_insert(EntityInterface $entity) {
if (!$entity
->isSyncing() && $entity
->getTargetEntityTypeId() == 'node' && ($bundle = $entity
->getTargetBundle())) {
domain_access_confirm_fields('node', $bundle);
}
}
/**
* Creates our fields for an entity bundle.
*
* @param string $entity_type
* The entity type being created. Node and user are supported.
* @param string $bundle
* The bundle being created.
* @param array $text
* The text to use for the field. Keys are:
* 'name' -- the lower-case, human-readable name of the entity.
* 'label' -- the form label for the all affiliates field.
* 'description' -- the help text for the all affiliates field.
*
* If calling this function for entities other than user or node, it is the
* caller's responsibility to provide this text.
*
* This function is here for convenience during installation. It is not really
* an API function. Modules wishing to add fields to non-node entities must
* provide their own field storage. See the field storage YML sample in
* tests/modules/domain_access_test for an example of field storage
* definitions.
*
* @see domain_access_node_type_insert()
* @see domain_access_install()
*/
function domain_access_confirm_fields($entity_type, $bundle, array $text = []) {
// We have reports that importing config causes this function to fail.
try {
$text['node'] = [
'name' => 'content',
'label' => 'Send to all affiliates',
'description' => 'Make this content available on all domains.',
];
$text['user'] = [
'name' => 'user',
'label' => 'Editor for all affiliates',
'description' => 'Make this user an editor on all domains.',
];
$id = $entity_type . '.' . $bundle . '.' . DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD;
$field_storage = \Drupal::entityTypeManager()
->getStorage('field_config');
if (!($field = $field_storage
->load($id))) {
$field = [
'field_name' => DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD,
'entity_type' => $entity_type,
'label' => 'Domain Access',
'bundle' => $bundle,
// Users should not be required to be a domain editor.
'required' => $entity_type !== 'user',
'description' => 'Select the affiliate domain(s) for this ' . $text[$entity_type]['name'],
'default_value_callback' => 'Drupal\\domain_access\\DomainAccessManager::getDefaultValue',
'settings' => [
'handler' => 'default:domain',
// Handler_settings are deprecated but seem to be necessary here.
'handler_settings' => [
'target_bundles' => NULL,
'sort' => [
'field' => 'weight',
'direction' => 'ASC',
],
],
'target_bundles' => NULL,
'sort' => [
'field' => 'weight',
'direction' => 'ASC',
],
],
];
$field_config = $field_storage
->create($field);
$field_config
->save();
}
// Assign the all affiliates field.
$id = $entity_type . '.' . $bundle . '.' . DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD;
if (!($field = $field_storage
->load($id))) {
$field = [
'field_name' => DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD,
'entity_type' => $entity_type,
'label' => $text[$entity_type]['label'],
'bundle' => $bundle,
'required' => FALSE,
'description' => $text[$entity_type]['description'],
];
$field_config = $field_storage
->create($field);
$field_config
->save();
}
// Tell the form system how to behave. Default to radio buttons.
if ($display = \Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load($entity_type . '.' . $bundle . '.default')) {
$display
->setComponent(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD, [
'type' => 'options_buttons',
'weight' => 40,
])
->setComponent(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD, [
'type' => 'boolean_checkbox',
'settings' => [
'display_label' => 1,
],
'weight' => 41,
])
->save();
}
} catch (Exception $e) {
\Drupal::logger('domain_access')
->notice('Field installation failed.');
}
}
/**
* Implements hook_views_data_alter().
*/
function domain_access_views_data_alter(array &$data) {
$table = 'node__' . DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD;
$data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]['field']['id'] = 'domain_access_field';
$data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '_target_id']['filter']['id'] = 'domain_access_filter';
$data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '_target_id']['argument']['id'] = 'domain_access_argument';
// Current domain filter.
$data[$table]['current_all'] = [
'title' => t('Current domain'),
'group' => t('Domain'),
'filter' => [
'field' => DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '_target_id',
'id' => 'domain_access_current_all_filter',
'title' => t('Available on current domain'),
'help' => t('Filters out nodes available on current domain (published to current domain or all affiliates).'),
],
];
// Since domains are not stored in the database, relationships cannot be used.
unset($data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]['relationship']);
// Set the user data.
$table = 'user__' . DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD;
$data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]['field']['id'] = 'domain_access_field';
$data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '_target_id']['filter']['id'] = 'domain_access_filter';
$data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '_target_id']['argument']['id'] = 'domain_access_argument';
// Since domains are not stored in the database, relationships cannot be used.
unset($data[$table][DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD]['relationship']);
}
/**
* Implements hook_ENTITY_TYPE_insert().
*/
function domain_access_domain_insert($entity) {
/** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
if ($entity
->isSyncing()) {
// Do not fire hook when config sync in progress.
return;
}
$id = 'domain_access_add_action.' . $entity
->id();
$controller = \Drupal::entityTypeManager()
->getStorage('action');
if (!$controller
->load($id)) {
/** @var \Drupal\system\Entity\Action $action */
$action = $controller
->create([
'id' => $id,
'type' => 'node',
'label' => t('Add selected content to the @label domain', [
'@label' => $entity
->label(),
]),
'configuration' => [
'domain_id' => $entity
->id(),
],
'plugin' => 'domain_access_add_action',
]);
$action
->trustData()
->save();
}
$remove_id = 'domain_access_remove_action.' . $entity
->id();
if (!$controller
->load($remove_id)) {
/** @var \Drupal\system\Entity\Action $action */
$action = $controller
->create([
'id' => $remove_id,
'type' => 'node',
'label' => t('Remove selected content from the @label domain', [
'@label' => $entity
->label(),
]),
'configuration' => [
'domain_id' => $entity
->id(),
],
'plugin' => 'domain_access_remove_action',
]);
$action
->trustData()
->save();
}
$id = 'domain_access_add_editor_action.' . $entity
->id();
if (!$controller
->load($id)) {
/** @var \Drupal\system\Entity\Action $action */
$action = $controller
->create([
'id' => $id,
'type' => 'user',
'label' => t('Add editors to the @label domain', [
'@label' => $entity
->label(),
]),
'configuration' => [
'domain_id' => $entity
->id(),
],
'plugin' => 'domain_access_add_editor_action',
]);
$action
->trustData()
->save();
}
$remove_id = 'domain_access_remove_editor_action.' . $entity
->id();
if (!$controller
->load($remove_id)) {
/** @var \Drupal\system\Entity\Action $action */
$action = $controller
->create([
'id' => $remove_id,
'type' => 'user',
'label' => t('Remove editors from the @label domain', [
'@label' => $entity
->label(),
]),
'configuration' => [
'domain_id' => $entity
->id(),
],
'plugin' => 'domain_access_remove_editor_action',
]);
$action
->trustData()
->save();
}
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function domain_access_domain_delete(EntityInterface $entity) {
$controller = \Drupal::entityTypeManager()
->getStorage('action');
$actions = $controller
->loadMultiple([
'domain_access_add_action.' . $entity
->id(),
'domain_access_remove_action.' . $entity
->id(),
'domain_access_add_editor_action.' . $entity
->id(),
'domain_access_remove_editor_action.' . $entity
->id(),
]);
foreach ($actions as $action) {
$action
->delete();
}
}
/**
* Implements hook_form_alter().
*
* Find forms that contain the domain access field and allow those to handle
* default values properly. Note that here we just care if the form saves an
* entity. We then pass that entity to a helper function.
*
* @see domain_access_default_form_values()
*/
function domain_access_form_alter(&$form, &$form_state, $form_id) {
if ($object = $form_state
->getFormObject() && !empty($object) && is_callable([
$object,
'getEntity',
]) && ($entity = $object
->getEntity())) {
domain_access_default_form_values($form, $form_state, $entity);
}
}
/**
* Defines default values for domain access field.
*
* This function is a workaround for a core bug. When the domain access field
* is not accessible to some users, the existing values are not preserved.
*
* @see domain_access_entity_field_access()
*/
function domain_access_default_form_values(&$form, &$form_state, $entity) {
// Set domain access default value when the user does not have access
// to edit the field. This seems to work fine for all affiliates, which
// suggests a core bug in entity reference handling.
if (!$entity
->isNew() && isset($form['field_domain_access']) && !$form['field_domain_access']['#access'] && empty($form['field_domain_access']['widget']['#default_value'])) {
// Set the default values correctly.
$values = \Drupal::service('domain_access.manager')
->getAccessValues($entity);
$form['field_domain_access']['widget']['#default_value'] = array_keys($values);
}
}
Functions
Constants
Name | Description |
---|---|
DOMAIN_ACCESS_ALL_FIELD Deprecated | The name of the all affiliates field. |
DOMAIN_ACCESS_FIELD Deprecated | The name of the node access control field. |