Transaction.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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. * @var string
  42. */
  43. protected $name;
  44. public function __construct(Connection $connection, $name = NULL) {
  45. $this->connection = $connection;
  46. // If there is no transaction depth, then no transaction has started. Name
  47. // the transaction 'drupal_transaction'.
  48. if (!$depth = $connection->transactionDepth()) {
  49. $this->name = 'drupal_transaction';
  50. }
  51. // Within transactions, savepoints are used. Each savepoint requires a
  52. // name. So if no name is present we need to create one.
  53. elseif (!$name) {
  54. $this->name = 'savepoint_' . $depth;
  55. }
  56. else {
  57. $this->name = $name;
  58. }
  59. $this->connection->pushTransaction($this->name);
  60. }
  61. public function __destruct() {
  62. // If we rolled back then the transaction would have already been popped.
  63. if (!$this->rolledBack) {
  64. $this->connection->popTransaction($this->name);
  65. }
  66. }
  67. /**
  68. * Retrieves the name of the transaction or savepoint.
  69. */
  70. public function name() {
  71. return $this->name;
  72. }
  73. /**
  74. * Rolls back the current transaction.
  75. *
  76. * This is just a wrapper method to rollback whatever transaction stack we are
  77. * currently in, which is managed by the connection object itself. Note that
  78. * logging (preferable with watchdog_exception()) needs to happen after a
  79. * transaction has been rolled back or the log messages will be rolled back
  80. * too.
  81. *
  82. * @see \Drupal\Core\Database\Connection::rollBack()
  83. * @see watchdog_exception()
  84. */
  85. public function rollBack() {
  86. $this->rolledBack = TRUE;
  87. $this->connection->rollBack($this->name);
  88. }
  89. }