Merge "API: Migrate Title::userCan() calls to PermissionManager"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / resultwrapper / ResultWrapper.php
1 <?php
2
3 namespace Wikimedia\Rdbms;
4
5 use stdClass;
6 use RuntimeException;
7
8 /**
9 * Result wrapper for grabbing data queried from an IDatabase object
10 *
11 * Note that using the Iterator methods in combination with the non-Iterator
12 * DB result iteration functions may cause rows to be skipped or repeated.
13 *
14 * By default, this will use the iteration methods of the IDatabase handle if provided.
15 * Subclasses can override methods to make it solely work on the result resource instead.
16 * If no database is provided, and the subclass does not override the DB iteration methods,
17 * then a RuntimeException will be thrown when iteration is attempted.
18 *
19 * The result resource field should not be accessed from non-Database related classes.
20 * It is database class specific and is stored here to associate iterators with queries.
21 *
22 * @ingroup Database
23 */
24 class ResultWrapper implements IResultWrapper {
25 /** @var resource|array|null Optional underlying result handle for subclass usage */
26 public $result;
27
28 /** @var IDatabase|null */
29 protected $db;
30
31 /** @var int */
32 protected $pos = 0;
33 /** @var stdClass|bool|null */
34 protected $currentRow;
35
36 /**
37 * Create a row iterator from a result resource and an optional Database object
38 *
39 * Only Database-related classes should construct ResultWrapper. Other code may
40 * use the FakeResultWrapper subclass for convenience or compatibility shims, however.
41 *
42 * @param IDatabase|null $db Optional database handle
43 * @param ResultWrapper|array|resource $result Optional underlying result handle
44 */
45 public function __construct( IDatabase $db = null, $result ) {
46 $this->db = $db;
47 if ( $result instanceof ResultWrapper ) {
48 $this->result = $result->result;
49 } else {
50 $this->result = $result;
51 }
52 }
53
54 public function numRows() {
55 return $this->getDB()->numRows( $this );
56 }
57
58 public function fetchObject() {
59 return $this->getDB()->fetchObject( $this );
60 }
61
62 public function fetchRow() {
63 return $this->getDB()->fetchRow( $this );
64 }
65
66 public function seek( $pos ) {
67 $this->getDB()->dataSeek( $this, $pos );
68 $this->pos = $pos;
69 }
70
71 public function free() {
72 $this->db = null;
73 $this->result = null;
74 }
75
76 function rewind() {
77 if ( $this->numRows() ) {
78 $this->getDB()->dataSeek( $this, 0 );
79 }
80 $this->pos = 0;
81 $this->currentRow = null;
82 }
83
84 function current() {
85 if ( $this->currentRow === null ) {
86 $this->currentRow = $this->fetchObject();
87 }
88
89 return $this->currentRow;
90 }
91
92 function key() {
93 return $this->pos;
94 }
95
96 function next() {
97 $this->pos++;
98 $this->currentRow = $this->fetchObject();
99
100 return $this->currentRow;
101 }
102
103 function valid() {
104 return $this->current() !== false;
105 }
106
107 /**
108 * @return IDatabase
109 * @throws RuntimeException
110 */
111 private function getDB() {
112 if ( !$this->db ) {
113 throw new RuntimeException( static::class . ' needs a DB handle for iteration.' );
114 }
115
116 return $this->db;
117 }
118 }
119
120 /**
121 * @deprecated since 1.29
122 */
123 class_alias( ResultWrapper::class, 'ResultWrapper' );