node.module

Same filename and directory in other branches
  1. 11.x core/modules/node/node.module
  2. 10 core/modules/node/node.module
  3. 9 core/modules/node/node.module
  4. 8.9.x core/modules/node/node.module
  5. 7.x modules/node/node.module

File

core/modules/node/node.module

View source
<?php


/**
 * @file
 */

use Drupal\Component\Utility\Environment;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeBulkUpdate;
use Drupal\node\NodeInterface;

/**
 * Returns a list of available node type names.
 *
 * This list can include types that are queued for addition or deletion.
 *
 * @return string[]
 *   An array of node type labels, keyed by the node type name.
 *
 * @deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use \Drupal::service('entity_type.bundle.info')->getBundleLabels('node') instead.
 * @see https://www.drupal.org/node/3534849
 */
function node_type_get_names() {
  @trigger_error(__FUNCTION__ . '() is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use \\Drupal::service(\'entity_type.bundle.info\')->getBundleLabels(\'node\') instead. See https://www.drupal.org/node/3534849', E_USER_DEPRECATED);
  return \Drupal::service('entity_type.bundle.info')->getBundleLabels('node');
}

/**
 * Returns the node type label for the passed node.
 *
 * @param \Drupal\node\NodeInterface $node
 *   A node entity to return the node type's label for.
 *
 * @return string|false
 *   The node type label or FALSE if the node type is not found.
 *
 * @deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use $node->getBundleEntity()->label() instead.
 * @see https://www.drupal.org/node/3533301
 */
function node_get_type_label(NodeInterface $node) {
  @trigger_error(__FUNCTION__ . '() is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use $node->getBundleEntity()->label(). See https://www.drupal.org/node/3533301', E_USER_DEPRECATED);
  $type = NodeType::load($node->bundle());
  return $type ? $type->label() : FALSE;
}

/**
 * Checks whether the current page is the full page view of the passed-in node.
 *
 * @param \Drupal\node\NodeInterface $node
 *   A node entity.
 *
 * @return bool
 *   TRUE if this is a full page view, otherwise FALSE.
 *
 * @deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. There is no
 *    replacement, check the view mode instead during rendering.
 *
 * @see https://www.drupal.org/node/3458593
 */
function node_is_page(NodeInterface $node) {
  @trigger_error(__FUNCTION__ . '() is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. There is no replacement, check the view mode instead during rendering. See https://www.drupal.org/node/3531945', E_USER_DEPRECATED);
  $route_match = \Drupal::routeMatch();
  if ($route_match->getRouteName() == 'entity.node.canonical') {
    $page_node = $route_match->getParameter('node');
  }
  return !empty($page_node) ? $page_node->id() == $node->id() : FALSE;
}

/**
 * Updates all nodes in the passed-in array with the passed-in field values.
 *
 * IMPORTANT NOTE: This function is intended to work when called from a form
 * submission handler. Calling it outside of the form submission process may not
 * work correctly.
 *
 * @param array $nodes
 *   Array of node nids or nodes to update.
 * @param array $updates
 *   Array of key/value pairs with node field names and the value to update that
 *   field to.
 * @param string $langcode
 *   (optional) The language updates should be applied to. If none is specified
 *   all available languages are processed.
 * @param bool $load
 *   (optional) TRUE if $nodes contains an array of node IDs to be loaded, FALSE
 *   if it contains fully loaded nodes. Defaults to FALSE.
 * @param bool $revisions
 *   (optional) TRUE if $nodes contains an array of revision IDs instead of
 *   node IDs. Defaults to FALSE; will be ignored if $load is FALSE.
 *
 * @deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use \Drupal::service(\Drupal\node\NodeBulkUpdate::class)->process() instead.
 * @see https://www.drupal.org/node/3533315
 */
function node_mass_update(array $nodes, array $updates, $langcode = NULL, $load = FALSE, $revisions = FALSE) : void {
  @trigger_error(__FUNCTION__ . '() is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use \\Drupal::service(\\Drupal\\node\\NodeBulkUpdate::class)->process() instead. See https://www.drupal.org/node/3533315', E_USER_DEPRECATED);
  \Drupal::service(NodeBulkUpdate::class)->process($nodes, $updates, $langcode, $load, $revisions);
}

/**
 * @addtogroup node_access
 * @{
 */

/**
 * Fetches an array of permission IDs granted to the given user ID.
 *
 * The implementation here provides only the universal "all" grant. A node
 * access module should implement hook_node_grants() to provide a grant list for
 * the user.
 *
 * After the default grants have been loaded, we allow modules to alter the
 * grants array by reference. This hook allows for complex business logic to be
 * applied when integrating multiple node access modules.
 *
 * @param string $operation
 *   The operation that the user is trying to perform.
 * @param \Drupal\Core\Session\AccountInterface $account
 *   The account object for the user performing the operation.
 *
 * @return array
 *   An associative array in which the keys are realms, and the values are
 *   arrays of grants for those realms.
 */
function node_access_grants($operation, AccountInterface $account) {
  // Fetch node access grants from other modules.
  $grants = \Drupal::moduleHandler()->invokeAll('node_grants', [
    $account,
    $operation,
  ]);
  // Allow modules to alter the assigned grants.
  \Drupal::moduleHandler()->alter('node_grants', $grants, $account, $operation);
  return array_merge([
    'all' => [
      0,
    ],
  ], $grants);
}

/**
 * Toggles or reads the value of a flag for rebuilding the node access grants.
 *
 * When the flag is set, a message is displayed to users with 'access
 * administration pages' permission, pointing to the 'rebuild' confirm form.
 * This can be used as an alternative to direct node_access_rebuild calls,
 * allowing administrators to decide when they want to perform the actual
 * (possibly time consuming) rebuild.
 *
 * When unsure if the current user is an administrator, node_access_rebuild()
 * should be used instead.
 *
 * @param bool|null $rebuild
 *   (optional) The boolean value to be written. Defaults to NULL, which returns
 *   the current value.
 *
 * @return bool|null
 *   The current value of the flag if no value was provided for $rebuild. If a
 *   value was provided for $rebuild, nothing (NULL) is returned.
 *
 * @see node_access_rebuild()
 */
function node_access_needs_rebuild($rebuild = NULL) {
  if (!isset($rebuild)) {
    return \Drupal::state()->get('node.node_access_needs_rebuild', FALSE);
  }
  elseif ($rebuild) {
    \Drupal::state()->set('node.node_access_needs_rebuild', TRUE);
  }
  else {
    \Drupal::state()->delete('node.node_access_needs_rebuild');
  }
}

/**
 * Rebuilds the node access database.
 *
 * This rebuild is occasionally needed by modules that make system-wide changes
 * to access levels. When the rebuild is required by an admin-triggered action
 * (e.g module settings form), calling node_access_needs_rebuild(TRUE) instead
 * of node_access_rebuild() lets the user perform changes and actually rebuild
 * only once done.
 *
 * Note : As of Drupal 6, node access modules are not required to (and actually
 * should not) call node_access_rebuild() in hook_install/uninstall anymore.
 *
 * @param bool $batch_mode
 *   (optional) Set to TRUE to process in 'batch' mode, spawning processing over
 *   several HTTP requests (thus avoiding the risk of PHP timeout if the site
 *   has a large number of nodes). hook_update_N() and any form submit handler
 *   are safe contexts to use the 'batch mode'. Less decidable cases (such as
 *   calls from hook_user(), hook_taxonomy(), etc.) might consider using the
 *   non-batch mode. Defaults to FALSE. Calling this method multiple times in
 *   the same request with $batch_mode set to TRUE will only result in one batch
 *   set being added.
 *
 * @see node_access_needs_rebuild()
 */
function node_access_rebuild($batch_mode = FALSE) : void {
  $node_storage = \Drupal::entityTypeManager()->getStorage('node');
  /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */
  $access_control_handler = \Drupal::entityTypeManager()->getAccessControlHandler('node');
  // If node_access_rebuild() fails to complete, and node_access_needs_rebuild
  // is not set to TRUE, the node_access table is left in an incomplete state.
  // Force node_access_needs_rebuild to TRUE once existing grants are deleted,
  // to signal that the node access table still needs to be rebuilt if this
  // function does not finish.
  node_access_needs_rebuild(TRUE);
  $access_control_handler->deleteGrants();
  // Only recalculate if the site is using a node_access module.
  if (\Drupal::moduleHandler()->hasImplementations('node_grants')) {
    if ($batch_mode) {
      if (!BatchBuilder::isSetIdRegistered(__FUNCTION__)) {
        $batch_builder = (new BatchBuilder())->setTitle(t('Rebuilding content access permissions'))
          ->addOperation('_node_access_rebuild_batch_operation', [])
          ->setFinishCallback('_node_access_rebuild_batch_finished')
          ->registerSetId(__FUNCTION__);
        batch_set($batch_builder->toArray());
      }
    }
    else {
      // Try to allocate enough time to rebuild node grants.
      Environment::setTimeLimit(240);
      // Rebuild newest nodes first so that recent content becomes available
      // quickly.
      $entity_query = \Drupal::entityQuery('node');
      $entity_query->sort('nid', 'DESC');
      // Disable access checking since all nodes must be processed even if the
      // user does not have access. And unless the current user has the bypass
      // node access permission, no nodes are accessible since the grants have
      // just been deleted.
      $entity_query->accessCheck(FALSE);
      $nids = $entity_query->execute();
      foreach ($nids as $nid) {
        $node_storage->resetCache([
          $nid,
        ]);
        $node = Node::load($nid);
        // To preserve database integrity, only write grants if the node
        // loads successfully.
        if (!empty($node)) {
          $grants = $access_control_handler->acquireGrants($node);
          \Drupal::service('node.grant_storage')->write($node, $grants);
        }
      }
    }
  }
  else {
    // Not using any node_access modules. Add the default grant.
    $access_control_handler->writeDefaultGrant();
  }
  if (!isset($batch_builder)) {
    \Drupal::messenger()->addStatus(t('Content permissions have been rebuilt.'));
    node_access_needs_rebuild(FALSE);
  }
}

/**
 * Implements callback_batch_operation().
 *
 * Performs batch operation for node_access_rebuild().
 *
 * This is a multistep operation: we go through all nodes by packs of 20. The
 * batch processing engine interrupts processing and sends progress feedback
 * after 1 second execution time.
 *
 * @param array $context
 *   An array of contextual key/value information for rebuild batch process.
 */
function _node_access_rebuild_batch_operation(&$context) : void {
  $node_storage = \Drupal::entityTypeManager()->getStorage('node');
  if (empty($context['sandbox'])) {
    // Initiate multistep processing.
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['current_node'] = 0;
    $context['sandbox']['max'] = \Drupal::entityQuery('node')->accessCheck(FALSE)
      ->count()
      ->execute();
  }
  // Process the next 20 nodes.
  $limit = 20;
  $nids = \Drupal::entityQuery('node')->condition('nid', $context['sandbox']['current_node'], '>')
    ->sort('nid', 'ASC')
    ->accessCheck(FALSE)
    ->range(0, $limit)
    ->execute();
  $node_storage->resetCache($nids);
  $nodes = Node::loadMultiple($nids);
  foreach ($nids as $nid) {
    // To preserve database integrity, only write grants if the node
    // loads successfully.
    if (!empty($nodes[$nid])) {
      $node = $nodes[$nid];
      /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */
      $access_control_handler = \Drupal::entityTypeManager()->getAccessControlHandler('node');
      $grants = $access_control_handler->acquireGrants($node);
      \Drupal::service('node.grant_storage')->write($node, $grants);
    }
    $context['sandbox']['progress']++;
    $context['sandbox']['current_node'] = $nid;
  }
  // Multistep processing : report progress.
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}

/**
 * Implements callback_batch_finished().
 *
 * Performs post-processing for node_access_rebuild().
 *
 * @param bool $success
 *   A boolean indicating whether the re-build process has completed.
 * @param array $results
 *   An array of results information.
 * @param array $operations
 *   An array of function calls (not used in this function).
 */
function _node_access_rebuild_batch_finished($success, $results, $operations) : void {
  if ($success) {
    \Drupal::messenger()->addStatus(t('The content access permissions have been rebuilt.'));
    node_access_needs_rebuild(FALSE);
  }
  else {
    \Drupal::messenger()->addError(t('The content access permissions have not been properly rebuilt.'));
  }
}

/**
 * @} End of "addtogroup node_access".
 */

Functions

Title Deprecated Summary
node_access_grants Fetches an array of permission IDs granted to the given user ID.
node_access_needs_rebuild Toggles or reads the value of a flag for rebuilding the node access grants.
node_access_rebuild Rebuilds the node access database.
node_get_type_label

in drupal:11.3.0 and is removed from drupal:13.0.0. Use $node->getBundleEntity()->label() instead.

Returns the node type label for the passed node.
node_is_page

in drupal:11.3.0 and is removed from drupal:13.0.0. There is no replacement, check the view mode instead during rendering.

Checks whether the current page is the full page view of the passed-in node.
node_mass_update

in drupal:11.3.0 and is removed from drupal:13.0.0. Use \Drupal::service(\Drupal\node\NodeBulkUpdate::class)->process() instead.

Updates all nodes in the passed-in array with the passed-in field values.
node_type_get_names

in drupal:11.3.0 and is removed from drupal:13.0.0. Use \Drupal::service('entity_type.bundle.info')->getBundleLabels('node') instead.

Returns a list of available node type names.
_node_access_rebuild_batch_finished Implements callback_batch_finished().
_node_access_rebuild_batch_operation Implements callback_batch_operation().

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.