BufferedStatement.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database\Statement;
  16. /**
  17. * A statement decorator that implements buffered results.
  18. *
  19. * This statement decorator will save fetched results in memory, allowing
  20. * the iterator to be rewound and reused.
  21. */
  22. class BufferedStatement extends StatementDecorator
  23. {
  24. /**
  25. * Records count
  26. *
  27. * @var int
  28. */
  29. protected $_count = 0;
  30. /**
  31. * Array of results
  32. *
  33. * @var array
  34. */
  35. protected $_records = [];
  36. /**
  37. * If true, all rows were fetched
  38. *
  39. * @var bool
  40. */
  41. protected $_allFetched = true;
  42. /**
  43. * Current record pointer
  44. *
  45. * @var int
  46. */
  47. protected $_counter = 0;
  48. /**
  49. * Constructor
  50. *
  51. * @param \Cake\Database\StatementInterface|null $statement Statement implementation such as PDOStatement
  52. * @param \Cake\Database\Driver|null $driver Driver instance
  53. */
  54. public function __construct($statement = null, $driver = null)
  55. {
  56. parent::__construct($statement, $driver);
  57. $this->_reset();
  58. }
  59. /**
  60. * Execute the statement and return the results.
  61. *
  62. * @param array|null $params list of values to be bound to query
  63. * @return bool true on success, false otherwise
  64. */
  65. public function execute($params = null)
  66. {
  67. $this->_reset();
  68. return parent::execute($params);
  69. }
  70. /**
  71. * {@inheritDoc}
  72. *
  73. * @param string $type The type to fetch.
  74. * @return array|false
  75. */
  76. public function fetch($type = parent::FETCH_TYPE_NUM)
  77. {
  78. if ($this->_allFetched) {
  79. $row = ($this->_counter < $this->_count) ? $this->_records[$this->_counter++] : false;
  80. $row = ($row && $type === static::FETCH_TYPE_NUM) ? array_values($row) : $row;
  81. return $row;
  82. }
  83. $record = parent::fetch($type);
  84. if ($record === false) {
  85. $this->_allFetched = true;
  86. $this->_counter = $this->_count + 1;
  87. $this->_statement->closeCursor();
  88. return false;
  89. }
  90. $this->_count++;
  91. return $this->_records[] = $record;
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function fetchAssoc()
  97. {
  98. return $this->fetch(static::FETCH_TYPE_ASSOC);
  99. }
  100. /**
  101. * {@inheritDoc}
  102. *
  103. * @param string $type The type to fetch.
  104. * @return array
  105. */
  106. public function fetchAll($type = parent::FETCH_TYPE_NUM)
  107. {
  108. if ($this->_allFetched) {
  109. return $this->_records;
  110. }
  111. $this->_records = parent::fetchAll($type);
  112. $this->_count = count($this->_records);
  113. $this->_allFetched = true;
  114. $this->_statement->closeCursor();
  115. return $this->_records;
  116. }
  117. /**
  118. * {@inheritDoc}
  119. */
  120. public function rowCount()
  121. {
  122. if (!$this->_allFetched) {
  123. $counter = $this->_counter;
  124. while ($this->fetch(static::FETCH_TYPE_ASSOC)) {
  125. }
  126. $this->_counter = $counter;
  127. }
  128. return $this->_count;
  129. }
  130. /**
  131. * Rewind the _counter property
  132. *
  133. * @return void
  134. */
  135. public function rewind()
  136. {
  137. $this->_counter = 0;
  138. }
  139. /**
  140. * Reset all properties
  141. *
  142. * @return void
  143. */
  144. protected function _reset()
  145. {
  146. $this->_count = $this->_counter = 0;
  147. $this->_records = [];
  148. $this->_allFetched = false;
  149. }
  150. }