InsertTrait.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace Drupal\Core\Database\Query;
  3. /**
  4. * Provides common functionality for INSERT and UPSERT queries.
  5. *
  6. * @ingroup database
  7. */
  8. trait InsertTrait {
  9. /**
  10. * The table on which to insert.
  11. *
  12. * @var string
  13. */
  14. protected $table;
  15. /**
  16. * An array of fields on which to insert.
  17. *
  18. * @var array
  19. */
  20. protected $insertFields = [];
  21. /**
  22. * An array of fields that should be set to their database-defined defaults.
  23. *
  24. * @var array
  25. */
  26. protected $defaultFields = [];
  27. /**
  28. * A nested array of values to insert.
  29. *
  30. * $insertValues is an array of arrays. Each sub-array is either an
  31. * associative array whose keys are field names and whose values are field
  32. * values to insert, or a non-associative array of values in the same order
  33. * as $insertFields.
  34. *
  35. * Whether multiple insert sets will be run in a single query or multiple
  36. * queries is left to individual drivers to implement in whatever manner is
  37. * most appropriate. The order of values in each sub-array must match the
  38. * order of fields in $insertFields.
  39. *
  40. * @var array
  41. */
  42. protected $insertValues = [];
  43. /**
  44. * Adds a set of field->value pairs to be inserted.
  45. *
  46. * This method may only be called once. Calling it a second time will be
  47. * ignored. To queue up multiple sets of values to be inserted at once,
  48. * use the values() method.
  49. *
  50. * @param array $fields
  51. * An array of fields on which to insert. This array may be indexed or
  52. * associative. If indexed, the array is taken to be the list of fields.
  53. * If associative, the keys of the array are taken to be the fields and
  54. * the values are taken to be corresponding values to insert. If a
  55. * $values argument is provided, $fields must be indexed.
  56. * @param array $values
  57. * (optional) An array of fields to insert into the database. The values
  58. * must be specified in the same order as the $fields array.
  59. *
  60. * @return $this
  61. * The called object.
  62. */
  63. public function fields(array $fields, array $values = []) {
  64. if (empty($this->insertFields)) {
  65. if (empty($values)) {
  66. if (!is_numeric(key($fields))) {
  67. $values = array_values($fields);
  68. $fields = array_keys($fields);
  69. }
  70. }
  71. $this->insertFields = $fields;
  72. if (!empty($values)) {
  73. $this->insertValues[] = $values;
  74. }
  75. }
  76. return $this;
  77. }
  78. /**
  79. * Adds another set of values to the query to be inserted.
  80. *
  81. * If $values is a numeric-keyed array, it will be assumed to be in the same
  82. * order as the original fields() call. If it is associative, it may be
  83. * in any order as long as the keys of the array match the names of the
  84. * fields.
  85. *
  86. * @param array $values
  87. * An array of values to add to the query.
  88. *
  89. * @return $this
  90. * The called object.
  91. */
  92. public function values(array $values) {
  93. if (is_numeric(key($values))) {
  94. $this->insertValues[] = $values;
  95. }
  96. elseif ($this->insertFields) {
  97. // Reorder the submitted values to match the fields array.
  98. foreach ($this->insertFields as $key) {
  99. $insert_values[$key] = $values[$key];
  100. }
  101. // For consistency, the values array is always numerically indexed.
  102. $this->insertValues[] = array_values($insert_values);
  103. }
  104. return $this;
  105. }
  106. /**
  107. * Specifies fields for which the database defaults should be used.
  108. *
  109. * If you want to force a given field to use the database-defined default,
  110. * not NULL or undefined, use this method to instruct the database to use
  111. * default values explicitly. In most cases this will not be necessary
  112. * unless you are inserting a row that is all default values, as you cannot
  113. * specify no values in an INSERT query.
  114. *
  115. * Specifying a field both in fields() and in useDefaults() is an error
  116. * and will not execute.
  117. *
  118. * @param array $fields
  119. * An array of values for which to use the default values
  120. * specified in the table definition.
  121. *
  122. * @return $this
  123. * The called object.
  124. */
  125. public function useDefaults(array $fields) {
  126. $this->defaultFields = $fields;
  127. return $this;
  128. }
  129. /**
  130. * Returns the query placeholders for values that will be inserted.
  131. *
  132. * @param array $nested_insert_values
  133. * A nested array of values to insert.
  134. * @param array $default_fields
  135. * An array of fields that should be set to their database-defined defaults.
  136. *
  137. * @return array
  138. * An array of insert placeholders.
  139. */
  140. protected function getInsertPlaceholderFragment(array $nested_insert_values, array $default_fields) {
  141. $max_placeholder = 0;
  142. $values = [];
  143. if ($nested_insert_values) {
  144. foreach ($nested_insert_values as $insert_values) {
  145. $placeholders = [];
  146. // Default fields aren't really placeholders, but this is the most convenient
  147. // way to handle them.
  148. $placeholders = array_pad($placeholders, count($default_fields), 'default');
  149. $new_placeholder = $max_placeholder + count($insert_values);
  150. for ($i = $max_placeholder; $i < $new_placeholder; ++$i) {
  151. $placeholders[] = ':db_insert_placeholder_' . $i;
  152. }
  153. $max_placeholder = $new_placeholder;
  154. $values[] = '(' . implode(', ', $placeholders) . ')';
  155. }
  156. }
  157. else {
  158. // If there are no values, then this is a default-only query. We still need to handle that.
  159. $placeholders = array_fill(0, count($default_fields), 'default');
  160. $values[] = '(' . implode(', ', $placeholders) . ')';
  161. }
  162. return $values;
  163. }
  164. /**
  165. * {@inheritdoc}
  166. */
  167. public function count() {
  168. return count($this->insertValues);
  169. }
  170. }