You are here

content_access.module in Content Access 8

Same filename and directory in other branches
  1. 5 content_access.module
  2. 6 content_access.module
  3. 7 content_access.module

Content access module file.

File

content_access.module
View source
<?php

/**
 * @file
 * Content access module file.
 */
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Drupal\node\NodeTypeInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Cache\Cache;
use Drupal\user\RoleInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;
use Drupal\user\Entity\Role;
use Drupal\node\Entity\Node;
use Drupal\content_access\ContentAccessInterface;

/**
 * Implements hook_help().
 */
function content_access_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.content_access':
    case 'entity.node.content_access':
    case 'entity.node_type.content_access_form':
      $hint_service = FALSE;
      if (!empty(\Drupal::hasService('advanced_help_hint.gethint'))) {
        $hint_service = \Drupal::service('advanced_help_hint.gethint');
      }
      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The <strong>Content Access</strong> module let you content manage access permission in a flexible and transparant way.') . '</p>';
      $output .= '<h3>' . t('Use') . '</h3>';
      $output .= '<p>' . t('It provides two new permissions: <em>view all</em> (allows anyone to view the content) and <em>view own</em> (allows  only the content creator to see his/her own content). It also gives access to the existing core permissions <em>edit</em> and <em>delete</em> on the same settings page.') . '</p>';
      $output .= '<p>' . t('It provides the following modalities:') . '</p><ul>';
      $output .= '<li>' . t('Each <a href=":url"><em>content type</em></a> can have its own default content access settings by role.', [
        ':url' => Url::fromRoute('entity.node_type.collection')
          ->toString(),
      ]) . '</li>';
      $output .= '<li>' . t('Optionally you can enable  role based access control settings per <em>content node</em>.') . '</li>';
      $output .= '<li>' . t('Access control can be further customized per <em>user</em> if you have the <a href=":url"><strong>ACL</strong></a> module enabled.', [
        ':url' => Url::fromUri('https://www.drupal.org/project/acl/')
          ->toString(),
      ]) . '</li></ul>';
      if ($hint_service) {
        $output .= '<p>' . $hint_service
          ->produceHint('content_access', 'https://www.drupal.org/docs/7/modules/content-access', TRUE) . '</p>';
      }
      else {
        $output .= '<p>' . t('If you install and enable the module <a href=":url"><strong>Advanced Help Hint</strong></a>, you will get more help for <strong>Content Access</strong>.', [
          ':url' => Url::fromUri('https://www.drupal.org/project/advanced_help_hint')
            ->toString(),
        ]) . '</p>';
      }
      return $output;
  }
}

/**
 * Implements hook_node_grants().
 */
function content_access_node_grants(AccountInterface $account, $op) {
  $gids = [];
  $roles = $account
    ->getRoles();
  foreach ($roles as $role) {
    $gids[] = content_access_get_role_gid($role);
  }
  return [
    'content_access_author' => [
      $account
        ->id(),
    ],
    'content_access_roles' => $gids,
  ];
}

/**
 * Implements hook_node_access_records().
 */
function content_access_node_access_records(NodeInterface $node) {
  if (content_access_disabling() || !$node
    ->isPublished()) {
    return;
  }

  // Apply per node settings if necessary.
  if (content_access_get_settings('per_node', $node
    ->getType())) {
    $grants = [];
    foreach ([
      'view',
      'update',
      'delete',
    ] as $op) {
      foreach (content_access_get_rids_per_node_op($op, $node) as $rid) {
        $gid = content_access_get_role_gid($rid);
        $grants[$gid]['grant_' . $op] = 1;
      }
    }
    foreach ($grants as $gid => $grant) {
      $grants[$gid] = content_access_proccess_grant($grant, $gid, $node);
    }

    // Care for the author grant.
    $grant = [];
    foreach ([
      'view',
      'update',
      'delete',
    ] as $op) {

      // Get all roles that have access to use $op on this node.
      $per_node_settings = content_access_per_node_setting($op, $node);
      $any_roles = array_combine($per_node_settings, $per_node_settings);
      $any_roles = $any_roles ? $any_roles : [];
      $any_roles += $op != 'view' ? content_access_get_settings($op, $node
        ->getType()) : [];
      $grant['grant_' . $op] = content_access_own_op($node, $any_roles, content_access_get_rids_per_node_op($op . '_own', $node));
    }
    if (array_filter($grant)) {
      $grant['realm'] = 'content_access_author';
      $grants[] = content_access_proccess_grant($grant, $node
        ->getOwnerId(), $node);
    }
  }
  else {

    // Apply the content type defaults.
    $grants = content_access_get_type_grant($node);
  }
  if (empty($grants)) {

    // This means we grant no access.
    $grants[] = content_access_proccess_grant([], 0, $node);
  }
  else {
    content_access_optimize_grants($grants, $node);
  }
  return $grants;
}

/**
 * Implements hook_node_delete().
 */
function content_access_node_delete(NodeInterface $node) {
  \Drupal::database()
    ->delete('content_access')
    ->condition('nid', $node
    ->id())
    ->execute();
}

/**
 * Implements hook_entity_insert().
 */
function content_access_entity_insert(EntityInterface $entity) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');
  if ($entity instanceof RoleInterface) {
    $roles_gids = array_flip($config
      ->get('content_access_roles_gids'));
    $roles_gids[] = $entity
      ->id();
    $config
      ->set('content_access_roles_gids', array_flip($roles_gids));
    $config
      ->save();
  }
}

/**
 * Implements hook_entity_operation().
 */
function content_access_entity_operation(EntityInterface $entity) {
  $operations = [];
  $info = $entity
    ->getEntityType();
  if ($info
    ->getBundleOf() == 'node') {
    $account = \Drupal::currentUser();
    if ($account
      ->hasPermission('bypass node access') && $account
      ->hasPermission('administer content types')) {
      $operations['access-control'] = [
        'title' => t('Access control'),
        'weight' => 25,
        'url' => Url::fromRoute('entity.node_type.content_access_form', [
          'node_type' => $entity
            ->id(),
        ]),
      ];
    }
  }
  return $operations;
}

/**
 * Implements hook_entity_delete().
 */
function content_access_entity_delete(EntityInterface $entity) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');
  if ($entity instanceof RoleInterface) {
    $roles_gids = $config
      ->get('content_access_roles_gids');
    unset($roles_gids[$entity
      ->id()]);
    $config
      ->set('content_access_roles_gids', $roles_gids)
      ->save();
  }
}

/**
 * Used by the ACL module.
 */
function content_access_enabled() {
  return !content_access_disabling();
}

/**
 * Remembers if we have disabled access.
 */
function content_access_disabling($set = NULL) {
  static $disabling = FALSE;
  if (isset($set)) {
    $disabling = $set;
  }
  return $disabling;
}

/**
 * Return content_access' settings.
 *
 * @param string $setting
 *   One of the content_access_available_settings(), e.g. 'view' or 'per_node'.
 *   If 'all' is passed, all available settings are returned.
 * @param string $type_name
 *   The name of the content type to return settings for.
 *
 * @return mixed
 *   The value of the given setting or an array of all settings.
 */
function content_access_get_settings($setting, $type_name) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');
  $settings = unserialize($config
    ->get('content_access_node_type.' . $type_name));
  if (empty($settings)) {
    $settings = [];
  }
  $settings += content_access_get_setting_defaults($type_name);
  if ($setting == 'all') {
    return $settings;
  }
  return isset($settings[$setting]) ? $settings[$setting] : NULL;
}

/**
 * Save content_access settings of a content type.
 */
function content_access_set_settings($settings, $type_name) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');

  // Do not store default values so we do not have to care about syncing our
  // settings with the permissions.
  foreach (content_access_get_setting_defaults($type_name) as $setting => $default_value) {
    if (isset($settings[$setting]) && $settings[$setting] == $default_value) {
      unset($settings[$setting]);
    }
  }
  $config
    ->set('content_access_node_type.' . $type_name, serialize($settings));
  $config
    ->save();
}

/**
 * Return an array containing all available content_access settings.
 */
function content_access_available_settings() {
  return [
    'view',
    'update',
    'delete',
    'view_own',
    'update_own',
    'delete_own',
    'per_node',
    'priority',
  ];
}

/**
 * Defines default values for settings.
 */
function content_access_get_setting_defaults($type) {
  $defaults = [];
  $defaults['view'] = $defaults['view_own'] = [
    AccountInterface::ANONYMOUS_ROLE,
    AccountInterface::AUTHENTICATED_ROLE,
  ];
  foreach ([
    'update',
    'delete',
  ] as $op) {
    $defaults[$op] = content_access_get_permission_access(content_access_get_permission_by_op($op, $type));
    $defaults[$op . '_own'] = content_access_get_permission_access(content_access_get_permission_by_op($op . '_own', $type));
  }
  $defaults['priority'] = 0;
  $defaults['per_node'] = FALSE;
  return $defaults;
}

/**
 * Returns an array of role ids that contain the given permission.
 */
function content_access_get_permission_access($perm, $reset = FALSE) {
  $roles =& drupal_static(__FUNCTION__, []);
  if ($reset) {
    $roles = [];
  }
  if (!isset($roles[$perm]) && $perm) {
    $user_roles = Role::loadMultiple();
    foreach ($user_roles as $role) {
      if ($role
        ->hasPermission($perm)) {
        $roles[$perm][] = $role
          ->id();
      }
    }
  }
  return isset($roles[$perm]) ? $roles[$perm] : [];
}

/**
 * Gets the name of a perm for the given operation, if there is a suiting one.
 */
function content_access_get_permission_by_op($op, $type) {
  switch ($op) {
    case 'update':
      return 'edit any ' . $type . ' content';
    case 'update_own':
      return 'edit own ' . $type . ' content';
    case 'delete':
      return 'delete any ' . $type . ' content';
    case 'delete_own':
      return 'delete own ' . $type . ' content';
    default:
      return FALSE;
  }
}

/**
 * Returns the default grants for a given node type.
 */
function content_access_get_type_grant(NodeInterface $node) {

  // Cache per type default grants in a static array.
  static $defaults = [];
  $node_type = $node
    ->getType();
  if (!isset($defaults[$node_type])) {
    $grants = [];

    // Only process the 'view' op as node_access() will take care of
    // edit and delete.
    foreach (content_access_get_settings('view', $node_type) as $rid) {
      $gid = content_access_get_role_gid($rid);
      $grant['grant_view'] = 1;
      $grants[] = content_access_proccess_grant($grant, $gid, $node);
    }
    $defaults[$node_type] = $grants;
  }

  // Care for the author grant.
  $grant = $grants = [];
  $settings = [
    'view' => content_access_get_settings('view', $node_type),
    'view_own' => content_access_get_settings('view_own', $node_type),
  ];
  $grant['grant_view'] = content_access_own_op($node, $settings['view'], $settings['view_own']);
  if ($grant['grant_view']) {
    $grant['realm'] = 'content_access_author';
    $grants = [
      'author' => content_access_proccess_grant($grant, $node
        ->getOwnerId(), $node),
    ];
  }
  return $defaults[$node_type] + $grants;
}

/**
 * Process a grant, which means add priority, realm and other properties.
 */
function content_access_proccess_grant($grant, $gid, NodeInterface $node) {
  $grant += [
    'grant_view' => 0,
    'grant_update' => 0,
    'grant_delete' => 0,
    'realm' => 'content_access_roles',
  ];
  $grant['gid'] = $gid;
  $grant['priority'] = content_access_get_settings('priority', $node
    ->getType());
  return $grant;
}

/**
 * Determines grant for node author and the gives allowed roles of operation.
 *
 * @param array $any_roles
 *   The roles with which anybody has access (not optimized!).
 * @param array $own_roles
 *   The roles with which only the author has access (optimized!).
 *
 * @return int
 *   Returns 0 if permission is granted, otherwise 1.
 */
function content_access_own_op(NodeInterface $node, array $any_roles, array $own_roles) {
  static $roles = [];
  $owner = $node
    ->getOwner();
  if (!isset($roles[$owner
    ->id()])) {
    $roles[$owner
      ->id()] = $owner
      ->id() ? [
      AccountInterface::AUTHENTICATED_ROLE,
    ] : [
      AccountInterface::ANONYMOUS_ROLE,
    ];
    $result = $owner
      ->get('roles');
    foreach ($result as $role) {
      $roles[$owner
        ->id()][] = $role->target_id;
    }
  }
  if (array_intersect($roles[$owner
    ->id()], $any_roles)) {

    // If there is access due to "any permissions" there is no need to
    // add an author grant.
    return 0;
  }
  return array_intersect($roles[$owner
    ->id()], $own_roles) ? 1 : 0;
}

/**
 * Get rids per node.
 *
 * Returns optimized role ids for the given operation and node to
 * grant access for.
 *
 * If to a role access is granted by permissions, it's not necessary
 * to write a grant for it. So it won't be returned.
 *
 * @param string $op
 *   One of the supported operations.
 * @param \Drupal\node\NodeInterface $node
 *   The node object.
 */
function content_access_get_rids_per_node_op($op, NodeInterface $node) {
  $rids = content_access_per_node_setting($op, $node);
  if ($permission = content_access_get_permission_by_op($op, $node
    ->getType())) {
    $perm_roles = content_access_get_permission_access($permission);
    $rids = array_diff($rids, $perm_roles);
    if (in_array(AccountInterface::AUTHENTICATED_ROLE, $perm_roles)) {
      if (in_array(AccountInterface::ANONYMOUS_ROLE, $rids)) {
        return [
          AccountInterface::ANONYMOUS_ROLE,
          AccountInterface::AUTHENTICATED_ROLE,
        ];
      }
      else {
        return [
          AccountInterface::AUTHENTICATED_ROLE,
        ];
      }
    }
  }
  return $rids;
}

/**
 * Access per node setting.
 *
 * Returns the per node role settings. If no per node settings are available,
 * it will return the content type settings.
 *
 * @param string $op
 *   One of the supported operations.
 * @param \Drupal\node\NodeInterface $node
 *   The node object.
 * @param array $settings
 *   Optional array used to update the settings cache with the given settings.
 *
 * @return array
 *   An array of role ids which have access.
 */
function content_access_per_node_setting($op, NodeInterface $node, array $settings = NULL) {
  static $grants = [];
  if (isset($settings)) {

    // Update settings cache.
    $grants[$node
      ->id()] = $settings;
    return $settings;
  }
  if (!isset($grants[$node
    ->id()]) || $grants[$node
    ->id()] === FALSE) {
    $grants[$node
      ->id()] = content_access_get_per_node_settings($node);
  }

  // Return the content type defaults if no per node settings are available.
  return isset($grants[$node
    ->id()][$op]) ? $grants[$node
    ->id()][$op] : content_access_get_settings($op, $node
    ->getType());
}

/**
 * Gets the per node settings of a node.
 *
 * @note
 *   This function won't apply defaults, so if there are no other settings
 *   it will return an empty array.
 */
function content_access_get_per_node_settings(NodeInterface $node) {
  $query = \Drupal::database()
    ->query("SELECT settings FROM {content_access} WHERE nid = :nid", [
    ':nid' => $node
      ->id(),
  ]);
  $result = $query
    ->fetch(PDO::FETCH_OBJ);
  if (!empty($result->settings)) {
    return unserialize($result->settings);
  }
  return [];
}

/**
 * Saves custom per node settings in the own content_access table.
 */
function content_access_save_per_node_settings(NodeInterface $node, $settings) {
  $database = \Drupal::database();
  $count = $database
    ->select('content_access')
    ->fields('c', [
    'settings',
  ])
    ->condition('nid', $node
    ->id())
    ->countQuery()
    ->execute()
    ->fetchField();
  if ($count > 0) {
    $database
      ->update('content_access')
      ->condition('nid', $node
      ->id())
      ->fields([
      'settings' => serialize($settings),
    ])
      ->execute();
  }
  else {
    $database
      ->insert('content_access')
      ->fields([
      'nid' => $node
        ->id(),
      'settings' => serialize($settings),
    ])
      ->execute();
  }

  // Make content_access_per_node_setting() use the new settings.
  content_access_per_node_setting(NULL, $node, $settings);
}

/**
 * Delete per node settings.
 *
 * Deletes all custom per node settings, so that content type defaults
 * are used again.
 */
function content_access_delete_per_node_settings(NodeInterface $node) {
  \Drupal::database()
    ->delete('content_access')
    ->condition('nid', $node
    ->id())
    ->execute();

  // Clear the cache.
  content_access_per_node_setting(NULL, $node);

  // Delete possible acl settings.
  if (\Drupal::moduleHandler()
    ->moduleExists('acl')) {
    module_load_include('inc', 'content_access', 'content_access.admin');
    foreach ([
      'view',
      'update',
      'delete',
    ] as $op) {
      $acl_id = content_access_get_acl_id($node, $op);
      acl_delete_acl($acl_id);
    }
  }
}

/**
 * Removes grants that doesn't change anything.
 *
 * @note
 *   The grants are compared with the normal access control settings.
 */
function content_access_optimize_grants(&$grants, NodeInterface $node) {
  $rids = [
    'view' => [],
    'update' => [],
    'delete' => [],
  ];
  foreach ($grants as $key => $grant) {
    foreach ([
      'view',
      'update',
      'delete',
    ] as $op) {
      if (!empty($grant['grant_' . $op])) {
        $rids[$op][] = $grant['gid'];
      }
    }
  }

  // Detect if all are allowed to view.
  $anonymous_gid = content_access_get_role_gid(AccountInterface::ANONYMOUS_ROLE);
  $authenticated_gid = content_access_get_role_gid(AccountInterface::AUTHENTICATED_ROLE);
  $all = [
    $anonymous_gid,
    $authenticated_gid,
  ];
  if (empty(array_diff($all, $rids['view']))) {

    // Grant view access to all instead of single roles.
    $rids['view'] = [
      'all',
    ];
    $grants['all'] = [
      'realm' => 'all',
      'gid' => 0,
      'grant_view' => 1,
      'grant_update' => 0,
      'grant_delete' => 0,
      'priority' => content_access_get_settings('priority', $node
        ->getType()),
    ];
  }

  // If authenticated users are involved, remove unnecessary other roles.
  foreach ([
    'view',
    'update',
    'delete',
  ] as $op) {
    if (in_array($authenticated_gid, $rids[$op])) {
      $rids[$op] = in_array($anonymous_gid, $rids[$op]) ? [
        $anonymous_gid,
        $authenticated_gid,
      ] : [
        $authenticated_gid,
      ];
    }
  }

  // Now let's remove unnecessary grants, if any.
  foreach ($grants as $key => $grant) {
    if (!is_numeric($key)) {
      continue;
    }
    foreach ([
      'view',
      'update',
      'delete',
    ] as $op) {
      if ($grant['grant_' . $op] && in_array($grant['gid'], $rids[$op])) {

        // It is still here, so we cannot remove this grant.
        continue 2;
      }
    }

    // ok, remove it.
    unset($grants[$key]);
  }
}

/**
 * Implements hook_node_type_delete().
 */
function content_access_node_type_delete(NodeTypeInterface $info) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');
  $config
    ->clear('content_access_node_type.' . $info
    ->id())
    ->save();
}

/**
 * Implements hook_node_type_update().
 *
 * Updates settings on node type name change.
 */
function content_access_node_type_update(NodeTypeInterface $info) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');
  $original_id = $info
    ->getOriginalId();
  if (!empty($original_id) && $info
    ->getOriginalId() != $info
    ->id()) {
    $settings = content_access_get_settings('all', $info
      ->getOriginalId());
    content_access_set_settings($settings, $info
      ->id());
    $config
      ->clear('content_access_node_type.' . $info
      ->getOriginalId())
      ->save();
  }
}

/**
 * Implements hook_node_access_explain().
 */
function content_access_node_access_explain($row) {
  static $roles;
  if (!isset($roles)) {
    $roles = user_roles();
  }
  if (!$row->gid && $row->realm == 'content_access_roles') {
    return t('Content access: No access is granted.');
  }
  switch ($row->realm) {
    case 'content_access_author':
      return t('Content access: author of the content can access');
    case 'content_access_roles':
      return t('Content access: %role can access', [
        '%role' => $roles[$row->gid],
      ]);
  }
}

/**
 * Implements hook_form_alter().
 */
function content_access_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'user_admin_perm') {
    $build_info = $form_state
      ->getBuildInfo();
    $build_info['files'][] = [
      'module' => 'content_access',
      'type' => 'inc',
      'name' => 'content_access.admin',
    ];
    $form_state
      ->setBuildInfo($build_info);
    $form['actions']['submit']['#submit'][] = 'content_access_user_admin_perm_submit';
  }
}

/**
 * Returns an array of possible operations on content and their labels.
 */
function _content_access_get_operations($type = NULL) {
  $operations = [
    'view' => t('View any @type content', [
      '@type' => $type,
    ]),
    'view_own' => t('View own @type content', [
      '@type' => $type,
    ]),
    'update' => t('Edit any @type content', [
      '@type' => $type,
    ]),
    'update_own' => t('Edit own @type content', [
      '@type' => $type,
    ]),
    'delete' => t('Delete any @type content', [
      '@type' => $type,
    ]),
    'delete_own' => t('Delete own @type content', [
      '@type' => $type,
    ]),
  ];
  return $operations;
}

/**
 * Gets node's access permissions.
 */
function _content_access_get_node_permissions($type) {
  return array_filter(array_map('content_access_get_permission_by_op', array_flip(_content_access_get_operations()), array_fill(0, 6, $type)));
}

/**
 * Helper providing numeric id for role.
 */
function content_access_get_role_gid($role) {
  $config = \Drupal::configFactory()
    ->getEditable('content_access.settings');
  $roles_gids = $config
    ->get('content_access_roles_gids');
  if (empty($roles_gids) || !array_key_exists($role, $roles_gids)) {
    return null;
  }
  return $roles_gids[$role];
}

/**
 * Gets the content access acl id of the node.
 */
function content_access_get_acl_id(NodeInterface $node, $op) {
  $acl_id = acl_get_id_by_name('content_access', $op . '_' . $node
    ->id());
  if (!$acl_id) {
    $acl_id = acl_create_acl('content_access', $op . '_' . $node
      ->id());
  }
  return $acl_id;
}

/**
 * Detaches all our ACLs for the nodes of the given type.
 */
function _content_access_remove_acls($type) {
  $result = \Drupal::database()
    ->query("SELECT n.nid FROM {node} n WHERE type = :type", [
    'type' => $type,
  ]);
  foreach ($result as $node) {
    acl_node_clear_acls($node->nid, 'content_access');
  }
}

/**
 * Mass updates node access records for nodes of the given types.
 *
 * @param array $types
 *   An array of content type names.
 *
 * @return bool
 *   Whether the operation has been processed successfully or postponed.
 */
function content_access_mass_update(array $types) {
  $query = \Drupal::database()
    ->select('node', 'n')
    ->fields('n', [
    'nid',
  ])
    ->condition('n.type', $types, 'IN');
  $count = $query
    ->countQuery()
    ->execute()
    ->fetchField();
  node_access_needs_rebuild(TRUE);

  // If there not too much nodes affected, try to do it.
  if ($count <= ContentAccessInterface::CONTENT_ACCESS_MASS_UPDATE_THRESHOLD) {
    $records = $query
      ->execute();
    foreach ($records as $node) {
      $node = Node::load($node->nid);
      $grants = \Drupal::entityTypeManager()
        ->getAccessControlHandler('node')
        ->acquireGrants($node);
      \Drupal::service('node.grant_storage')
        ->write($node, $grants);
    }
    foreach (Cache::getBins() as $cache_backend) {
      $cache_backend
        ->deleteAll();
    }
    node_access_needs_rebuild(FALSE);
    return TRUE;
  }
  return FALSE;
}

/**
 * Submit callback for the user permissions form.
 *
 * Trigger changes to node permissions to rebuild our grants.
 */
function content_access_user_admin_perm_submit($form, FormStateInterface $form_state) {

  // Check for each content type, which has per node access activated
  // whether permissions have been changed.
  $types = [];
  foreach (array_filter(content_access_get_settings('per_node', 'all')) as $type => $value) {
    foreach (_content_access_get_node_permissions($type) as $perm) {
      foreach (user_roles() as $rid => $role) {
        $values = $form_state
          ->getValues();
        if (isset($values[$rid]) && in_array($perm, $form['checkboxes'][$rid]['#default_value']) != in_array($perm, $values[$rid])) {

          // Permission changed.
          $types[$type] = node_type_get_names();
          continue 2;
        }
      }
    }
  }
  if ($types && content_access_mass_update(array_keys($types))) {
    \Drupal::messenger()
      ->addMessage(\Drupal::translation()
      ->formatPlural(count($types), 'Permissions have been successfully rebuilt for the content type @types.', 'Permissions have been successfully rebuilt for the content types @types.', [
      '@types' => implode(', ', $types),
    ]));
  }
}

Functions

Namesort descending Description
content_access_available_settings Return an array containing all available content_access settings.
content_access_delete_per_node_settings Delete per node settings.
content_access_disabling Remembers if we have disabled access.
content_access_enabled Used by the ACL module.
content_access_entity_delete Implements hook_entity_delete().
content_access_entity_insert Implements hook_entity_insert().
content_access_entity_operation Implements hook_entity_operation().
content_access_form_alter Implements hook_form_alter().
content_access_get_acl_id Gets the content access acl id of the node.
content_access_get_permission_access Returns an array of role ids that contain the given permission.
content_access_get_permission_by_op Gets the name of a perm for the given operation, if there is a suiting one.
content_access_get_per_node_settings Gets the per node settings of a node.
content_access_get_rids_per_node_op Get rids per node.
content_access_get_role_gid Helper providing numeric id for role.
content_access_get_settings Return content_access' settings.
content_access_get_setting_defaults Defines default values for settings.
content_access_get_type_grant Returns the default grants for a given node type.
content_access_help Implements hook_help().
content_access_mass_update Mass updates node access records for nodes of the given types.
content_access_node_access_explain Implements hook_node_access_explain().
content_access_node_access_records Implements hook_node_access_records().
content_access_node_delete Implements hook_node_delete().
content_access_node_grants Implements hook_node_grants().
content_access_node_type_delete Implements hook_node_type_delete().
content_access_node_type_update Implements hook_node_type_update().
content_access_optimize_grants Removes grants that doesn't change anything.
content_access_own_op Determines grant for node author and the gives allowed roles of operation.
content_access_per_node_setting Access per node setting.
content_access_proccess_grant Process a grant, which means add priority, realm and other properties.
content_access_save_per_node_settings Saves custom per node settings in the own content_access table.
content_access_set_settings Save content_access settings of a content type.
content_access_user_admin_perm_submit Submit callback for the user permissions form.
_content_access_get_node_permissions Gets node's access permissions.
_content_access_get_operations Returns an array of possible operations on content and their labels.
_content_access_remove_acls Detaches all our ACLs for the nodes of the given type.