DatabaseStorage.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. namespace Drupal\Core\KeyValueStore;
  3. use Drupal\Component\Serialization\SerializationInterface;
  4. use Drupal\Core\Database\Query\Merge;
  5. use Drupal\Core\Database\Connection;
  6. use Drupal\Core\DependencyInjection\DependencySerializationTrait;
  7. /**
  8. * Defines a default key/value store implementation.
  9. *
  10. * This is Drupal's default key/value store implementation. It uses the database
  11. * to store key/value data.
  12. */
  13. class DatabaseStorage extends StorageBase {
  14. use DependencySerializationTrait;
  15. /**
  16. * The serialization class to use.
  17. *
  18. * @var \Drupal\Component\Serialization\SerializationInterface
  19. */
  20. protected $serializer;
  21. /**
  22. * The database connection.
  23. *
  24. * @var \Drupal\Core\Database\Connection
  25. */
  26. protected $connection;
  27. /**
  28. * The name of the SQL table to use.
  29. *
  30. * @var string
  31. */
  32. protected $table;
  33. /**
  34. * Overrides Drupal\Core\KeyValueStore\StorageBase::__construct().
  35. *
  36. * @param string $collection
  37. * The name of the collection holding key and value pairs.
  38. * @param \Drupal\Component\Serialization\SerializationInterface $serializer
  39. * The serialization class to use.
  40. * @param \Drupal\Core\Database\Connection $connection
  41. * The database connection to use.
  42. * @param string $table
  43. * The name of the SQL table to use, defaults to key_value.
  44. */
  45. public function __construct($collection, SerializationInterface $serializer, Connection $connection, $table = 'key_value') {
  46. parent::__construct($collection);
  47. $this->serializer = $serializer;
  48. $this->connection = $connection;
  49. $this->table = $table;
  50. }
  51. /**
  52. * {@inheritdoc}
  53. */
  54. public function has($key) {
  55. return (bool) $this->connection->query('SELECT 1 FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name = :key', [
  56. ':collection' => $this->collection,
  57. ':key' => $key,
  58. ])->fetchField();
  59. }
  60. /**
  61. * {@inheritdoc}
  62. */
  63. public function getMultiple(array $keys) {
  64. $values = [];
  65. try {
  66. $result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN ( :keys[] ) AND collection = :collection', [':keys[]' => $keys, ':collection' => $this->collection])->fetchAllAssoc('name');
  67. foreach ($keys as $key) {
  68. if (isset($result[$key])) {
  69. $values[$key] = $this->serializer->decode($result[$key]->value);
  70. }
  71. }
  72. }
  73. catch (\Exception $e) {
  74. // @todo: Perhaps if the database is never going to be available,
  75. // key/value requests should return FALSE in order to allow exception
  76. // handling to occur but for now, keep it an array, always.
  77. }
  78. return $values;
  79. }
  80. /**
  81. * {@inheritdoc}
  82. */
  83. public function getAll() {
  84. $result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection', [':collection' => $this->collection]);
  85. $values = [];
  86. foreach ($result as $item) {
  87. if ($item) {
  88. $values[$item->name] = $this->serializer->decode($item->value);
  89. }
  90. }
  91. return $values;
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function set($key, $value) {
  97. $this->connection->merge($this->table)
  98. ->keys([
  99. 'name' => $key,
  100. 'collection' => $this->collection,
  101. ])
  102. ->fields(['value' => $this->serializer->encode($value)])
  103. ->execute();
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function setIfNotExists($key, $value) {
  109. $result = $this->connection->merge($this->table)
  110. ->insertFields([
  111. 'collection' => $this->collection,
  112. 'name' => $key,
  113. 'value' => $this->serializer->encode($value),
  114. ])
  115. ->condition('collection', $this->collection)
  116. ->condition('name', $key)
  117. ->execute();
  118. return $result == Merge::STATUS_INSERT;
  119. }
  120. /**
  121. * {@inheritdoc}
  122. */
  123. public function rename($key, $new_key) {
  124. $this->connection->update($this->table)
  125. ->fields(['name' => $new_key])
  126. ->condition('collection', $this->collection)
  127. ->condition('name', $key)
  128. ->execute();
  129. }
  130. /**
  131. * {@inheritdoc}
  132. */
  133. public function deleteMultiple(array $keys) {
  134. // Delete in chunks when a large array is passed.
  135. while ($keys) {
  136. $this->connection->delete($this->table)
  137. ->condition('name', array_splice($keys, 0, 1000), 'IN')
  138. ->condition('collection', $this->collection)
  139. ->execute();
  140. }
  141. }
  142. /**
  143. * {@inheritdoc}
  144. */
  145. public function deleteAll() {
  146. $this->connection->delete($this->table)
  147. ->condition('collection', $this->collection)
  148. ->execute();
  149. }
  150. }