node.admin.inc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. /**
  3. * @file
  4. * Content administration and module settings user interface.
  5. */
  6. use Drupal\node\NodeInterface;
  7. use Drupal\node\Entity\Node;
  8. /**
  9. * Updates all nodes in the passed-in array with the passed-in field values.
  10. *
  11. * IMPORTANT NOTE: This function is intended to work when called from a form
  12. * submission handler. Calling it outside of the form submission process may not
  13. * work correctly.
  14. *
  15. * @param array $nodes
  16. * Array of node nids or nodes to update.
  17. * @param array $updates
  18. * Array of key/value pairs with node field names and the value to update that
  19. * field to.
  20. * @param string $langcode
  21. * (optional) The language updates should be applied to. If none is specified
  22. * all available languages are processed.
  23. * @param bool $load
  24. * (optional) TRUE if $nodes contains an array of node IDs to be loaded, FALSE
  25. * if it contains fully loaded nodes. Defaults to FALSE.
  26. * @param bool $revisions
  27. * (optional) TRUE if $nodes contains an array of revision IDs instead of
  28. * node IDs. Defaults to FALSE; will be ignored if $load is FALSE.
  29. */
  30. function node_mass_update(array $nodes, array $updates, $langcode = NULL, $load = FALSE, $revisions = FALSE) {
  31. // We use batch processing to prevent timeout when updating a large number
  32. // of nodes.
  33. if (count($nodes) > 10) {
  34. $batch = array(
  35. 'operations' => array(
  36. array('_node_mass_update_batch_process', array($nodes, $updates, $langcode, $load, $revisions))
  37. ),
  38. 'finished' => '_node_mass_update_batch_finished',
  39. 'title' => t('Processing'),
  40. // We use a single multi-pass operation, so the default
  41. // 'Remaining x of y operations' message will be confusing here.
  42. 'progress_message' => '',
  43. 'error_message' => t('The update has encountered an error.'),
  44. // The operations do not live in the .module file, so we need to
  45. // tell the batch engine which file to load before calling them.
  46. 'file' => drupal_get_path('module', 'node') . '/node.admin.inc',
  47. );
  48. batch_set($batch);
  49. }
  50. else {
  51. if ($load && !$revisions) {
  52. $nodes = Node::loadMultiple($nodes);
  53. }
  54. foreach ($nodes as $node) {
  55. if ($load && $revisions) {
  56. $node = entity_revision_load('node', $node);
  57. }
  58. _node_mass_update_helper($node, $updates, $langcode);
  59. }
  60. drupal_set_message(t('The update has been performed.'));
  61. }
  62. }
  63. /**
  64. * Updates individual nodes when fewer than 10 are queued.
  65. *
  66. * @param \Drupal\node\NodeInterface $node
  67. * A node to update.
  68. * @param array $updates
  69. * Associative array of updates.
  70. * @param string $langcode
  71. * (optional) The language updates should be applied to. If none is specified
  72. * all available languages are processed.
  73. *
  74. * @return \Drupal\node\NodeInterface
  75. * An updated node object.
  76. *
  77. * @see node_mass_update()
  78. */
  79. function _node_mass_update_helper(NodeInterface $node, array $updates, $langcode = NULL) {
  80. $langcodes = isset($langcode) ? array($langcode) : array_keys($node->getTranslationLanguages());
  81. // For efficiency manually save the original node before applying any changes.
  82. $node->original = clone $node;
  83. foreach ($langcodes as $langcode) {
  84. foreach ($updates as $name => $value) {
  85. $node->getTranslation($langcode)->$name = $value;
  86. }
  87. }
  88. $node->save();
  89. return $node;
  90. }
  91. /**
  92. * Implements callback_batch_operation().
  93. *
  94. * Executes a batch operation for node_mass_update().
  95. *
  96. * @param array $nodes
  97. * An array of node IDs.
  98. * @param array $updates
  99. * Associative array of updates.
  100. * @param string $langcode
  101. * The language updates should be applied to. If none is specified all
  102. * available languages are processed.
  103. * @param bool $load
  104. * TRUE if $nodes contains an array of node IDs to be loaded, FALSE if it
  105. * contains fully loaded nodes.
  106. * @param bool $revisions
  107. * (optional) TRUE if $nodes contains an array of revision IDs instead of
  108. * node IDs. Defaults to FALSE; will be ignored if $load is FALSE.
  109. * @param array|\ArrayAccess $context.
  110. * An array of contextual key/values.
  111. */
  112. function _node_mass_update_batch_process(array $nodes, array $updates, $langcode, $load, $revisions, &$context) {
  113. if (!isset($context['sandbox']['progress'])) {
  114. $context['sandbox']['progress'] = 0;
  115. $context['sandbox']['max'] = count($nodes);
  116. $context['sandbox']['nodes'] = $nodes;
  117. }
  118. // Process nodes by groups of 5.
  119. $count = min(5, count($context['sandbox']['nodes']));
  120. for ($i = 1; $i <= $count; $i++) {
  121. // For each nid, load the node, reset the values, and save it.
  122. $node = array_shift($context['sandbox']['nodes']);
  123. if ($load) {
  124. $node = $revisions ?
  125. entity_revision_load('node', $node) : Node::load($node);
  126. }
  127. $node = _node_mass_update_helper($node, $updates, $langcode);
  128. // Store result for post-processing in the finished callback.
  129. $context['results'][] = \Drupal::l($node->label(), $node->urlInfo());
  130. // Update our progress information.
  131. $context['sandbox']['progress']++;
  132. }
  133. // Inform the batch engine that we are not finished,
  134. // and provide an estimation of the completion level we reached.
  135. if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
  136. $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  137. }
  138. }
  139. /**
  140. * Implements callback_batch_finished().
  141. *
  142. * Reports the 'finished' status of batch operation for node_mass_update().
  143. *
  144. * @param bool $success
  145. * A boolean indicating whether the batch mass update operation successfully
  146. * concluded.
  147. * @param string[] $results
  148. * An array of rendered links to nodes updated via the batch mode process.
  149. * @param array $operations
  150. * An array of function calls (not used in this function).
  151. *
  152. * @see _node_mass_update_batch_process()
  153. */
  154. function _node_mass_update_batch_finished($success, $results, $operations) {
  155. if ($success) {
  156. drupal_set_message(t('The update has been performed.'));
  157. }
  158. else {
  159. drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
  160. $message = \Drupal::translation()->formatPlural(count($results), '1 item successfully processed:', '@count items successfully processed:');
  161. $item_list = array(
  162. '#theme' => 'item_list',
  163. '#items' => $results,
  164. );
  165. $message .= drupal_render($item_list);
  166. drupal_set_message($message);
  167. }
  168. }