2015-08-17 17:00:26 -07:00
< ? php
/**
* @ file
* Content administration and module settings user interface .
*/
use Drupal\node\NodeInterface ;
/**
* 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 .
*/
function node_mass_update ( array $nodes , array $updates , $langcode = NULL , $load = FALSE , $revisions = FALSE ) {
// We use batch processing to prevent timeout when updating a large number
// of nodes.
if ( count ( $nodes ) > 10 ) {
2017-04-13 15:53:35 +01:00
$batch = [
'operations' => [
[ '_node_mass_update_batch_process' , [ $nodes , $updates , $langcode , $load , $revisions ]]
],
2015-08-17 17:00:26 -07:00
'finished' => '_node_mass_update_batch_finished' ,
'title' => t ( 'Processing' ),
// We use a single multi-pass operation, so the default
// 'Remaining x of y operations' message will be confusing here.
'progress_message' => '' ,
'error_message' => t ( 'The update has encountered an error.' ),
// The operations do not live in the .module file, so we need to
// tell the batch engine which file to load before calling them.
'file' => drupal_get_path ( 'module' , 'node' ) . '/node.admin.inc' ,
2017-04-13 15:53:35 +01:00
];
2015-08-17 17:00:26 -07:00
batch_set ( $batch );
}
else {
2017-04-13 15:53:35 +01:00
$storage = \Drupal :: entityTypeManager () -> getStorage ( 'node' );
2015-08-17 17:00:26 -07:00
if ( $load && ! $revisions ) {
2017-04-13 15:53:35 +01:00
$nodes = $storage -> loadMultiple ( $nodes );
2015-08-17 17:00:26 -07:00
}
foreach ( $nodes as $node ) {
if ( $load && $revisions ) {
2017-04-13 15:53:35 +01:00
$node = $storage -> loadRevision ( $node );
2015-08-17 17:00:26 -07:00
}
_node_mass_update_helper ( $node , $updates , $langcode );
}
drupal_set_message ( t ( 'The update has been performed.' ));
}
}
/**
* Updates individual nodes when fewer than 10 are queued .
*
* @ param \Drupal\node\NodeInterface $node
* A node to update .
* @ param array $updates
* Associative array of updates .
* @ param string $langcode
* ( optional ) The language updates should be applied to . If none is specified
* all available languages are processed .
*
* @ return \Drupal\node\NodeInterface
* An updated node object .
*
* @ see node_mass_update ()
*/
function _node_mass_update_helper ( NodeInterface $node , array $updates , $langcode = NULL ) {
2017-04-13 15:53:35 +01:00
$langcodes = isset ( $langcode ) ? [ $langcode ] : array_keys ( $node -> getTranslationLanguages ());
2015-08-17 17:00:26 -07:00
// For efficiency manually save the original node before applying any changes.
$node -> original = clone $node ;
foreach ( $langcodes as $langcode ) {
foreach ( $updates as $name => $value ) {
$node -> getTranslation ( $langcode ) -> $name = $value ;
}
}
$node -> save ();
return $node ;
}
/**
* Implements callback_batch_operation () .
*
* Executes a batch operation for node_mass_update () .
*
* @ param array $nodes
* An array of node IDs .
* @ param array $updates
* Associative array of updates .
2016-04-20 09:56:34 -07:00
* @ param string $langcode
* The language updates should be applied to . If none is specified all
* available languages are processed .
2015-08-17 17:00:26 -07:00
* @ param bool $load
* TRUE if $nodes contains an array of node IDs to be loaded , FALSE if it
* contains fully loaded nodes .
* @ 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 .
2017-04-13 15:53:35 +01:00
* @ param array | \ArrayAccess $context
2015-08-17 17:00:26 -07:00
* An array of contextual key / values .
*/
2016-04-20 09:56:34 -07:00
function _node_mass_update_batch_process ( array $nodes , array $updates , $langcode , $load , $revisions , & $context ) {
2015-08-17 17:00:26 -07:00
if ( ! isset ( $context [ 'sandbox' ][ 'progress' ])) {
$context [ 'sandbox' ][ 'progress' ] = 0 ;
$context [ 'sandbox' ][ 'max' ] = count ( $nodes );
$context [ 'sandbox' ][ 'nodes' ] = $nodes ;
}
// Process nodes by groups of 5.
2017-04-13 15:53:35 +01:00
$storage = \Drupal :: entityTypeManager () -> getStorage ( 'node' );
2015-08-17 17:00:26 -07:00
$count = min ( 5 , count ( $context [ 'sandbox' ][ 'nodes' ]));
for ( $i = 1 ; $i <= $count ; $i ++ ) {
// For each nid, load the node, reset the values, and save it.
$node = array_shift ( $context [ 'sandbox' ][ 'nodes' ]);
if ( $load ) {
$node = $revisions ?
2017-04-13 15:53:35 +01:00
$storage -> loadRevision ( $node ) : $storage -> load ( $node );
2015-08-17 17:00:26 -07:00
}
2016-04-20 09:56:34 -07:00
$node = _node_mass_update_helper ( $node , $updates , $langcode );
2015-08-17 17:00:26 -07:00
// Store result for post-processing in the finished callback.
$context [ 'results' ][] = \Drupal :: l ( $node -> label (), $node -> urlInfo ());
// Update our progress information.
$context [ 'sandbox' ][ 'progress' ] ++ ;
}
// Inform the batch engine that we are not finished,
// and provide an estimation of the completion level we reached.
if ( $context [ 'sandbox' ][ 'progress' ] != $context [ 'sandbox' ][ 'max' ]) {
$context [ 'finished' ] = $context [ 'sandbox' ][ 'progress' ] / $context [ 'sandbox' ][ 'max' ];
}
}
/**
* Implements callback_batch_finished () .
*
* Reports the 'finished' status of batch operation for node_mass_update () .
*
* @ param bool $success
* A boolean indicating whether the batch mass update operation successfully
* concluded .
* @ param string [] $results
* An array of rendered links to nodes updated via the batch mode process .
* @ param array $operations
* An array of function calls ( not used in this function ) .
*
* @ see _node_mass_update_batch_process ()
*/
function _node_mass_update_batch_finished ( $success , $results , $operations ) {
if ( $success ) {
drupal_set_message ( t ( 'The update has been performed.' ));
}
else {
drupal_set_message ( t ( 'An error occurred and processing did not complete.' ), 'error' );
$message = \Drupal :: translation () -> formatPlural ( count ( $results ), '1 item successfully processed:' , '@count items successfully processed:' );
2017-04-13 15:53:35 +01:00
$item_list = [
2015-08-17 17:00:26 -07:00
'#theme' => 'item_list' ,
'#items' => $results ,
2017-04-13 15:53:35 +01:00
];
2015-08-17 17:00:26 -07:00
$message .= drupal_render ( $item_list );
drupal_set_message ( $message );
}
}