You are here

entity_access_by_field.module in Open Social 8.9

Entity Access By Field module file.

@todo: Prevent creating multiple visibility fields on one node. @todo: Add support for multiple entity types.

File

modules/custom/entity_access_by_field/entity_access_by_field.module
View source
<?php

/**
 * @file
 * Entity Access By Field module file.
 *
 * @todo: Prevent creating multiple visibility fields on one node.
 * @todo: Add support for multiple entity types.
 */
use Drupal\entity_access_by_field\EntityAccessHelper;
use Drupal\node\NodeInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\social_post\Entity\PostInterface;
use Drupal\field\Entity\FieldConfig;

/**
 * Here we define a constant for our node access grant ID.
 */
define('ENTITY_ACCESS_BY_FIELD_ALLOWED_REALM', 1);

/**
 * Implements hook_node_access().
 */
function entity_access_by_field_node_access(NodeInterface $node, $op, AccountInterface $account) {
  return EntityAccessHelper::getEntityAccessResult($node, $op, $account);
}

/**
 * Implements hook_node_grants().
 */
function entity_access_by_field_node_grants(AccountInterface $account, $op) {
  $grants = [];
  if ($op === 'view') {

    // @TODO Check performance hit, this is not cached.
    $entityAccessPermissions = \Drupal::getContainer()
      ->get('entity_access_by_field.permissions');
    $permissions = $entityAccessPermissions
      ->getRealmWithPermission();
    if (!empty($permissions)) {
      foreach ($permissions as $realm => $permission) {
        if ($account
          ->hasPermission($permission)) {
          $grants[$realm][] = ENTITY_ACCESS_BY_FIELD_ALLOWED_REALM;
        }
        $grants[$realm . '_author'] = [
          $account
            ->id(),
        ];
      }
    }
  }
  return $grants;
}

/**
 * Implements hook_node_access_records().
 */
function entity_access_by_field_node_access_records(NodeInterface $node) {
  $grants = [];

  // Get the field definitions of the node.
  $field_definitions = $node
    ->getFieldDefinitions();

  /* @var \Drupal\Core\Field\FieldConfigInterface $field_definition */
  foreach ($field_definitions as $field_name => $field_definition) {

    // Lets add a node access realm if the field is implemented.
    if ($field_definition
      ->getType() === 'entity_access_field') {
      $field_values = $node
        ->get($field_name)
        ->getValue();
      if (!empty($field_values)) {
        foreach ($field_values as $field_value) {
          if (isset($field_value['value'])) {
            $entityAccessPermissions = \Drupal::getContainer()
              ->get('entity_access_by_field.permissions');
            $realm = $entityAccessPermissions
              ->getRealmForFieldValue('view', 'node', $node
              ->getType(), $field_name, $field_value['value']);
            if ($node
              ->isPublished()) {
              $grants[] = [
                'realm' => $realm,
                'gid' => ENTITY_ACCESS_BY_FIELD_ALLOWED_REALM,
                'grant_view' => 1,
                'grant_update' => 0,
                'grant_delete' => 0,
                'priority' => 0,
              ];
            }
            $grants[] = [
              'realm' => $realm . '_author',
              'gid' => $node
                ->getOwnerId(),
              'grant_view' => 1,
              'grant_update' => 1,
              'grant_delete' => 1,
              'priority' => 0,
            ];
          }
        }
      }
    }
  }
  return $grants;
}

/**
 * Implements hook_node_access_explain().
 */
function entity_access_by_field_node_access_explain($row) {
  $entityAccessPermissions = \Drupal::getContainer()
    ->get('entity_access_by_field.permissions');
  $permissions = $entityAccessPermissions
    ->getRealmWithPermission();
  foreach ($permissions as $realm => $permission) {
    if ($row->realm === $realm) {
      return 'Users with permission "' . $permission . '" may view this node.';
    }
  }
}

/**
 * Implements hook_field_widget_info_alter().
 */
function entity_access_by_field_field_widget_info_alter(&$info) {
  if (isset($info['options_buttons'])) {
    $info['options_buttons']['field_types'][] = 'entity_access_field';
  }
}

/**
 * Implements hook_field_formatter_info_alter().
 */
function entity_access_by_field_field_formatter_info_alter(array &$info) {
  if (isset($info['list_default'])) {
    $info['list_default']['field_types'][] = 'entity_access_field';
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function entity_access_by_field_node_presave(NodeInterface $node) {
  $original = $node->original;

  // Get the field definitions of the node.
  $field_definitions = $node
    ->getFieldDefinitions();

  /* @var \Drupal\Core\Field\FieldConfigInterface $field_definition */
  foreach ($field_definitions as $field_name => $field_definition) {

    // Lets add a node access realm if the field is implemented.
    if ($field_definition
      ->getType() === 'entity_access_field') {
      if (isset($node->status) && isset($original->status) && $node->status->value != $original->status->value) {

        // Invalidate cache tags.
        Cache::invalidateTags([
          'activity_list',
        ]);
      }
      if ($node
        ->get($field_name)
        ->isEmpty()) {
        $default_visibility = _entity_access_by_field_get_default_visibility($node);
        $node
          ->get($field_name)
          ->setValue($default_visibility);
      }
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function entity_access_by_field_post_presave(PostInterface $post) {
  $field_definitions = $post
    ->getFieldDefinitions();
  foreach ($field_definitions as $field_name => $field_definition) {
    if ($field_definition
      ->getType() == 'entity_access_field' && $post
      ->get($field_name)
      ->isEmpty()) {
      $default_visibility = _entity_access_by_field_get_default_visibility($post);
      $post
        ->get($field_name)
        ->setValue($default_visibility);
    }
  }
}

/**
 * Implements hook_field_widget_form_alter().
 */
function entity_access_by_field_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
  $field_definition = $context['items']
    ->getFieldDefinition();
  if ($field_definition
    ->getType() != 'entity_access_field' && $field_definition
    ->getName() != 'field_visibility') {
    return;
  }
  $form_object = $form_state
    ->getFormObject();
  if (!$form_object instanceof EntityFormInterface) {
    return;
  }
  $config = \Drupal::config('entity_access_by_field.settings');

  // Load the current user.
  $account = \Drupal::currentUser();

  // Set public visibility by default.
  $entity = $form_object
    ->getEntity();
  $field_name = $field_definition
    ->getName();
  if ($entity instanceof FieldConfig || !$entity
    ->hasField($field_name)) {
    return;
  }

  // Do not check if visibility already set and user has access to override
  // this option because SM can change the visibility.
  if (!$entity
    ->get($field_name) || !$entity
    ->get($field_name)
    ->isEmpty() && $account
    ->hasPermission('override disabled public visibility')) {
    return;
  }
  $element['#default_value'] = _entity_access_by_field_get_default_visibility($entity);

  // Check if the option is enabled and the current user has no permission
  // to override disabled public visibility.
  if ($config
    ->get('disable_public_visibility') === 1 && !$account
    ->hasPermission('override disabled public visibility')) {
    switch ($entity
      ->getEntityTypeId()) {
      case 'node':
        if ($entity
          ->get($field_name)
          ->getString() !== 'public') {
          $element['public']['#disabled'] = TRUE;
          $element['#description'] = t('The public visibility setting has been disabled. In order to change the visibility to public, please contact a site manager.')
            ->render();
        }
        break;
      case 'post':

        // Remove the public option.
        unset($element['#options'][1]);
        break;
    }
  }
}

/**
 * Returns default value for content visibility fields.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity object to prepare correct value.
 *
 * @return string
 *   Default value of the field.
 */
function _entity_access_by_field_get_default_visibility(EntityInterface $entity) {
  $default_visibility =& drupal_static(__FUNCTION__ . '_' . $entity
    ->getEntityTypeId());
  if ($default_visibility) {
    return $default_visibility;
  }
  $config = \Drupal::config('entity_access_by_field.settings');
  switch ($entity
    ->getEntityTypeId()) {
    case 'node':
      $account = $entity
        ->get('uid')->entity;
      $default_visibility = $config
        ->get('default_visibility');
      break;
    case 'post':
      $account = $entity
        ->get('user_id')->entity;
      $post_visibility = [
        'public' => '1',
        'community' => '2',
      ];
      $default_visibility = $post_visibility[$config
        ->get('default_visibility')];
      break;
    default:
      return $default_visibility;
  }
  if ($config
    ->get('disable_public_visibility') === 1 && !$account
    ->hasPermission('override disabled public visibility')) {
    switch ($entity
      ->getEntityTypeId()) {
      case 'node':
        if ($default_visibility === 'public') {
          $default_visibility = 'community';
        }
        break;
      case 'post':
        if ($default_visibility === '1') {
          $default_visibility = '2';
        }
        break;
    }
  }
  return $default_visibility;
}