0

I'm trying to write a module to duplicate a series of nodes and to make sure there is no timeout I want to use the Batch Api for this.

This is what I have at this moment in src/Controller/NodeCloneController.php:

namespace Drupal\book_clone\Controller; use Drupal\Core\Controller\ControllerBase; use Drupal\node\Entity\Node; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Class CloneNodesController. */ class CloneNodesController extends ControllerBase { /** * Clone nodes. */ public function cloneNodes() { $nids = [55,92,86]; $this->book_clone_clone_multiple_nodes($nids); $this->messenger()->addMessage($this->t('Nodes are being cloned.')); return $this->redirect('system.admin_content'); } function book_clone_clone_multiple_nodes(array $nids) { $operations = []; foreach ($nids as $nid) { $operations[] = [ [ $this->book_clone_clone_node($nid), [], ], ]; } $batch = [ 'title' => t('Cloning'), 'operations' => $operations, 'finished' => $this->book_clone_batch_finished(), ]; batch_set($batch); } function book_clone_clone_node($nid) { $node = Node::load($nid); if ($node) { $cloned_node = $node->createDuplicate(); $cloned_node->save(); } } function book_clone_batch_finished() { $message = t('Finished'); \Drupal::messenger()->addMessage($message); } } 

The function cloneNodes is called by going to a specific admin path via a routing file:

book_clone.clone_nodes: path: '/admin/content/clone' defaults: _controller: '\Drupal\book_clone\Controller\CloneNodesController::cloneNodes' _title: 'Clone Nodes' requirements: _permission: 'access content' 

Cloning works with this code but I don't see the batch page and progressbar. So I don't know if the batch is working and I want to show this page for my users to get proper feedback. First time using Batch so I think i'm missing something here. What am I doing wrong?

2 Answers 2

0

As you're in a controller you'll need to manually trigger the batch to run. Only in the form API will it auto trigger. Something like this should work:

$goto = '/'; $batch = batch_get(); if (!empty($batch)) { return batch_process($goto); } 

You need to do the check to make sure the batch isn't empty otherwise you'll get an error

0

You are calling the class methods when filling the array but you have to use a callback format so that they are called when the batch runs:

$batch = [ 'title' => $this->t('My batch'), 'operations' => [ [[$this, 'batchProcess'], [$nid]], ], 'finished' => [$this, 'batchFinished'], ]; batch_set($batch); 

These callbacks run in an instantiated object of your class. Most usage for the batch API is static, though. I think to avoid problems with caching of serialized objects. Then replace $this with static::class and make the methods static:

public static function batchProcess($nid) { public static function batchFinished($success, $results, $operations) { 

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.