Transaction.php 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. namespace Drupal\Core\Database;
  3. /**
  4. * A wrapper class for creating and managing database transactions.
  5. *
  6. * Not all databases or database configurations support transactions. For
  7. * example, MySQL MyISAM tables do not. It is also easy to begin a transaction
  8. * and then forget to commit it, which can lead to connection errors when
  9. * another transaction is started.
  10. *
  11. * This class acts as a wrapper for transactions. To begin a transaction,
  12. * simply instantiate it. When the object goes out of scope and is destroyed
  13. * it will automatically commit. It also will check to see if the specified
  14. * connection supports transactions. If not, it will simply skip any transaction
  15. * commands, allowing user-space code to proceed normally. The only difference
  16. * is that rollbacks won't actually do anything.
  17. *
  18. * In the vast majority of cases, you should not instantiate this class
  19. * directly. Instead, call ->startTransaction(), from the appropriate connection
  20. * object.
  21. */
  22. class Transaction {
  23. /**
  24. * The connection object for this transaction.
  25. *
  26. * @var \Drupal\Core\Database\Connection
  27. */
  28. protected $connection;
  29. /**
  30. * A boolean value to indicate whether this transaction has been rolled back.
  31. *
  32. * @var bool
  33. */
  34. protected $rolledBack = FALSE;
  35. /**
  36. * The name of the transaction.
  37. *
  38. * This is used to label the transaction savepoint. It will be overridden to
  39. * 'drupal_transaction' if there is no transaction depth.
  40. */
  41. protected $name;
  42. public function __construct(Connection $connection, $name = NULL) {
  43. $this->connection = $connection;
  44. // If there is no transaction depth, then no transaction has started. Name
  45. // the transaction 'drupal_transaction'.
  46. if (!$depth = $connection->transactionDepth()) {
  47. $this->name = 'drupal_transaction';
  48. }
  49. // Within transactions, savepoints are used. Each savepoint requires a
  50. // name. So if no name is present we need to create one.
  51. elseif (!$name) {
  52. $this->name = 'savepoint_' . $depth;
  53. }
  54. else {
  55. $this->name = $name;
  56. }
  57. $this->connection->pushTransaction($this->name);
  58. }
  59. public function __destruct() {
  60. // If we rolled back then the transaction would have already been popped.
  61. if (!$this->rolledBack) {
  62. $this->connection->popTransaction($this->name);
  63. }
  64. }
  65. /**
  66. * Retrieves the name of the transaction or savepoint.
  67. */
  68. public function name() {
  69. return $this->name;
  70. }
  71. /**
  72. * Rolls back the current transaction.
  73. *
  74. * This is just a wrapper method to rollback whatever transaction stack we are
  75. * currently in, which is managed by the connection object itself. Note that
  76. * logging (preferable with watchdog_exception()) needs to happen after a
  77. * transaction has been rolled back or the log messages will be rolled back
  78. * too.
  79. *
  80. * @see \Drupal\Core\Database\Connection::rollBack()
  81. * @see watchdog_exception()
  82. */
  83. public function rollBack() {
  84. $this->rolledBack = TRUE;
  85. $this->connection->rollBack($this->name);
  86. }
  87. }