Merge "Add CollationFa"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / resultwrapper / ResultWrapper.php
1 <?php
2 /**
3 * Result wrapper for grabbing data queried from an IDatabase object
4 *
5 * Note that using the Iterator methods in combination with the non-Iterator
6 * DB result iteration functions may cause rows to be skipped or repeated.
7 *
8 * By default, this will use the iteration methods of the IDatabase handle if provided.
9 * Subclasses can override methods to make it solely work on the result resource instead.
10 * If no database is provided, and the subclass does not override the DB iteration methods,
11 * then a RuntimeException will be thrown when iteration is attempted.
12 *
13 * The result resource field should not be accessed from non-Database related classes.
14 * It is database class specific and is stored here to associate iterators with queries.
15 *
16 * @ingroup Database
17 */
18 class ResultWrapper implements Iterator {
19 /** @var resource|array|null Optional underlying result handle for subclass usage */
20 public $result;
21
22 /** @var IDatabase|null */
23 protected $db;
24
25 /** @var int */
26 protected $pos = 0;
27 /** @var stdClass|null */
28 protected $currentRow = null;
29
30 /**
31 * Create a row iterator from a result resource and an optional Database object
32 *
33 * Only Database-related classes should construct ResultWrapper. Other code may
34 * use the FakeResultWrapper subclass for convenience or compatibility shims, however.
35 *
36 * @param IDatabase|null $db Optional database handle
37 * @param ResultWrapper|array|resource $result Optional underlying result handle
38 */
39 public function __construct( IDatabase $db = null, $result ) {
40 $this->db = $db;
41 if ( $result instanceof ResultWrapper ) {
42 $this->result = $result->result;
43 } else {
44 $this->result = $result;
45 }
46 }
47
48 /**
49 * Get the number of rows in a result object
50 *
51 * @return int
52 */
53 public function numRows() {
54 return $this->getDB()->numRows( $this );
55 }
56
57 /**
58 * Fetch the next row from the given result object, in object form. Fields can be retrieved with
59 * $row->fieldname, with fields acting like member variables. If no more rows are available,
60 * false is returned.
61 *
62 * @return stdClass|bool
63 * @throws DBUnexpectedError Thrown if the database returns an error
64 */
65 public function fetchObject() {
66 return $this->getDB()->fetchObject( $this );
67 }
68
69 /**
70 * Fetch the next row from the given result object, in associative array form. Fields are
71 * retrieved with $row['fieldname']. If no more rows are available, false is returned.
72 *
73 * @return array|bool
74 * @throws DBUnexpectedError Thrown if the database returns an error
75 */
76 public function fetchRow() {
77 return $this->getDB()->fetchRow( $this );
78 }
79
80 /**
81 * Change the position of the cursor in a result object.
82 * See mysql_data_seek()
83 *
84 * @param int $row
85 */
86 public function seek( $row ) {
87 $this->getDB()->dataSeek( $this, $row );
88 }
89
90 /**
91 * Free a result object
92 *
93 * This either saves memory in PHP (buffered queries) or on the server (unbuffered queries).
94 * In general, queries are not large enough in result sets for this to be worth calling.
95 */
96 public function free() {
97 if ( $this->db ) {
98 $this->db->freeResult( $this );
99 $this->db = null;
100 }
101 $this->result = null;
102 }
103
104 /**
105 * @return IDatabase
106 * @throws RuntimeException
107 */
108 private function getDB() {
109 if ( !$this->db ) {
110 throw new RuntimeException( get_class( $this ) . ' needs a DB handle for iteration.' );
111 }
112
113 return $this->db;
114 }
115
116 function rewind() {
117 if ( $this->numRows() ) {
118 $this->getDB()->dataSeek( $this, 0 );
119 }
120 $this->pos = 0;
121 $this->currentRow = null;
122 }
123
124 /**
125 * @return stdClass|array|bool
126 */
127 function current() {
128 if ( is_null( $this->currentRow ) ) {
129 $this->next();
130 }
131
132 return $this->currentRow;
133 }
134
135 /**
136 * @return int
137 */
138 function key() {
139 return $this->pos;
140 }
141
142 /**
143 * @return stdClass
144 */
145 function next() {
146 $this->pos++;
147 $this->currentRow = $this->fetchObject();
148
149 return $this->currentRow;
150 }
151
152 function valid() {
153 return $this->current() !== false;
154 }
155 }