1

On a Drupal 7 site, I am using the Batch API to perform operations on many entities, one at a time. During a typical operation, the D7 site uses Guzzle to make a POST call to a Drupal 8 site. The D7 Batch callback looks like this:

function example_operation($foo, &$context) {

  // Login to Drupal 8.
  // ...

  // Make POST call to Drupal 8.
  // ...

  // Logout from Drupal 8.
  // ...

}

The D7 client uses a Guzzle client and cookie jar to authenticate with the D8 server (REST+cookies), with no issues. Great!

Now imagine running this on 100K+ entities, that's an awful lot of logging in and out unnecessarily, wasting a whole bunch of time and resources. So I figure, let's login once on the first operation, retain that session for each operation, then logout when finished. Sounds reasonable.

I thought I'd use D7 Batch API's $context['results'] array to hang onto the cookie jar and D8 rest tokens, that way each operation would have access to them, no problem, or so I thought. Take a look at this attempt in the D7 Batch callbacks:

function example_operation($foo, &$context) {

  $jar = NULL;
  $csrfToken = NULL;

  // Login to Drupal 8 (first time only)
  if (!isset($context['results']['jar'])) {

    // Login to Drupal 8.
    // ...

    // Set aside cookie jar and tokens.
    $context['results']['jar'] = $jar;
    $context['results']['csrf_token'] = $csrfToken;
    $context['results']['logout_token'] = $logoutToken;

  }
  else {

    // We've already logged in, grab the cookie jar and token.
    $jar = $context['results']['jar'];
    $csrfToken = $context['results']['csrf_token'];

  }

  // Make POST call to Drupal 8 (using cookie jar and token).
  // ...

}

function example_finished($success, $results, $operations) {

  // Pull out cookie jar and tokens.
  $jar = $results['jar'];
  $csrfToken = $results['csrf_token'];
  $logoutToken = $results['logout_token'];

  // Logout from Drupal 8 (using cookie jar and tokens)
  // ...

}

This approach works fine on the first operation only. Then on the second operation, the tokens are available in $context['results'] as expected, but the cookie jar always comes through as a __PHP_Incomplete_Class Object, and then if I try using it with the Guzzle client a cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface is thrown.

How do you retain a Guzzle session between batch operations in Drupal 7?

  • Perhaps $context['results'] cannot contain "complex" class/objects like a Guzzle cookie jar
  • I tried using the cookies request option when instantiating the Guzzle client, but that breaks any authenticated POST calls (including the first operation)
  • Maybe the way D7's batch http requests work, it starts confusing the client/cookies/etc

1 Answer 1

1

Between two batch runs, the data is saved in the database serialized. Before the second batch run, the data is taken from the database and unserialized. __PHP_Incomplete_Class Object tell us that, at the moment the data is unserializes, no GuzzleHttp\Cookie\CookieJarInterface class is available, and objects of that class cannot be unserialized.

To retain a Guzzle session between batch runs, you can save the data as array.

$context['results']['jar'] = $jar->toArray();

To get back the data, you can then use the following code.

$jar = CookieJar::fromArray($context['results']['jar'], 'domain.com');

If you save an object in $context, as in your case now, it would be available through all iterations at one batch run, but at the next run, an error is thrown.
If you still prefer to keep objects during iterations instead of arrays, to avoid errors you should check if $context['results']['jar'] is an instance of GuzzleHttp\Cookie\CookieJarInterface.

1
  • This answer (w/ toArray() and fromArray()) allowed me to get the cookie jar back, thank you. When I use the cookie jar in later requests (after the 1st round in the batch) the response from D8 is always a 403, suggesting the client/session/cookie is still confused. Dang! Commented Jul 25, 2020 at 19:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.