1

I'm working on a custom Drupal 8 module. In a form submit function, I need to create several entities of different types. I am worried about what will happen if something goes wrong in the middle of the operation, as it will be difficult to clean up the mess.

So my question is: is there any kind of transactional mechanism for entities, similar to SQL transactions, so that I could conveniently rollback in case of an error?

If not, what strategy would you suggest?

1
  • No there's no such mechanism - transactions are proxied straight through to the DBMS that supports them, and in the case of an entity being persisted the queries for each individual entity are wrapped in a transaction. To the best of my knowledge Drupal has nothing that would help you with this either
    – Clive
    Sep 16, 2015 at 11:05

2 Answers 2

2

You can wrap all the entity save calls in a further transaction with Connection::startTransaction for a given database connection. Inject the database service into the form using FormBase::create

Catch using DatabaseExceptionWrapper and rollback :-). This is similar to Drupal 7 behavior as well.

It would be best to provide a unique name for the transaction as the transaction stack is fairly basic.

3
  • Oh good, that sounds just like what I had in mind. Is it safe to use DB transactions though? Could it interfere with caches, config storage etc?
    – Hendrik
    Sep 16, 2015 at 20:13
  • 1
    Note that theoretically, entities can be saved in a different place, e.g. MongoDB or an external system through API calls. For custom development, you probably know that this isn't the case and using database transactions is fine. For generic code, you should be aware that your entities might not end up in the database and a transaction will be meaningless. To a lesser extend, the same is true for cache backends and other pluggable systems. If you use redis for caching, then you can't revert changes in there automatically.
    – Berdir
    Sep 17, 2015 at 18:10
  • Berdir is correct. Although pdo mongodb does throw PDOException it does not look like the current driver catches or wraps the exception. Thank you for clarification.
    – mradcliffe
    Sep 22, 2015 at 3:27
0

it is a solution:

$database = \Drupal::database();
$transaction = $database->startTransaction();
$id_branch = null;
try {
  if(empty($id_branch)) {
      throw new \Exception('Empty: Branch Entity id.');
  }
  $Branch = Entities::load($id_branch);
  $branch_address = $Branch->getAddress();

  for ($i = 0; $i < 8000; $i++) {
    $values = array(
      'entity' => $id_branch,
      'name' => 'Store ' . $i,
      'address' => $branch_address,
    );
    $Store = Store::create($values);
    $Store->save();
  }

}
catch (\Exception $e) {
  $transaction->rollback();
  watchdog_exception($e->getMessage(), $e);
  throw new \Exception(  $e->getMessage(), $e->getCode(), $e->getPrevious());
}

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.