Solving bulk operations in Drupal VBO module

Konstantin Glushak
Universal Language
Published in
4 min readJul 22, 2016

--

How to overcome the limitations of the VBO module in Drupal 8, and find a bug in core.

At this point it is a well-known fact, that Drupal 8 accepted the core of the VBO module , though with only a subset of its Drupal 7 functionality. But what if the missing parts are almost vital for your project? Today we will talk on how to bring those features back. Namely we will talk about “batch processing” and multi-step forms, that allow you to get additional data from the user.

In our case, as Smartling is a global fluency platform, and our main task is to move original and translated content back-and-forth over the network, we need to make this process as reliable as possible, thus avoid time limits of PHP. That’s why we strongly need “batch processing”, and also an additional step form for selecting locales for user convenience.

VBO action

We start this process by implementing a simple action for VBO. We need to describe it for the Drupal 8 discovery mechanism first, then implement the action itself. Please note that in the annotation for the action we declare the route for the confirm form (confirm_form_route_name = “smartling.send_multiple_confirm”). This is the place where all the batch handling will take place. The only mission for the action class itself is to collect the IDs that we selected in the list view and store them in temp storage to pass them to the confirmation form (unfortunately we didn’t find a better option to pass this data to the form).

/smartling/config/install/system.action.smartling_translate_node_action.yml

modules/smartling/src/Plugin/Action/SmartlingBaseTranslationAction.php

Confirmation form:

The second step is to implement the confirmation form itself and add a route for it. Here you will be able to ask for some additional info from the users and invoke the batch process for each selected entity on the form submit.

modules/smartling/smartling.routing.yml

modules/smartling/src/Form/SendMultipleConfirmForm.php

This file is pretty big, so I will show only the 2 main methods of the form here. The first builds the form, by extracting our IDs from the temp storage, and loading entities with the provided IDs. It also retrieves the set of languages enabled in the system, so that a user can choose which locales to submit content for .

The second method creates batch-specific object based on the data retrieved from the submit step and gives away the control over the execution flow back to Drupal by calling a “batch_set” function. You can see its source here:

http://cgit.drupalcode.org/smartling/tree/src/Form/SendMultipleConfirmForm.php?h=8.x-1.x#n231

After you implement these 2 methods you will be able to process any request in batch, while still getting some additional configs/parameters from the user.

The Drupal 8 core bug

It is also interesting to mention, that while working on this functionality we found the Drupal 8 core bug: https://www.drupal.org/node/2701829 that says “Recoverable fatal error: Argument 1 passed to twig_init() must be an instance of Drupal\Core\Extension\Extension, array given in \drupal8.loc\www\core\themes\engines\twig\twig.engine on line 34”.

The idea behind it is that if you want to have a batch process with VBO, but without the confirmation step, for now you will get the fatal error. To demonstrate this behavior you can either download the patch from here https://www.drupal.org/node/2701829#comment-11097957, and then select a new custom action on the nodes list view. Or you can download a new test module from here: https://www.drupal.org/node/2701829#comment-11166585

So here is what is happening under the hood: when you try to invoke the the batch process from the VBO action, at some point your theme object will be deserialized from cache (in \Drupal\Core\Cache\DatabaseBackend::getMultiple). At that point all the links to the other object will be initialized. And the problem is that in normal state, $item->baseThemes[‘stable’]->extension is an object, but in our situation it is an empty array. And so when this empty array is passed to twig_init(Extension $theme) it doesn’t pass the type checking and causes a fatal error.

The issue is still open, so everyone is welcome to participate. As a workaround for now we used our second-step form, with a list of all the entities and an option for the user to continue with the operation or not.This approach allowed us to overcome the mentioned bug and enables the user to undo any accidental clicks.

Instead of the conclusion:

That’s mostly it. Now you should be able to use VBO, just as you used it before, and wait until this functionality emerges in some contrib module and the bug is fixed.

--

--