Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 37 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
AbstractIterator | |
0.00% |
0 / 37 |
|
0.00% |
0 / 11 |
306 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
query | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
setPage | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
setNamespace | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
setFrom | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
setTo | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
current | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
key | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
rewind | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
valid | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
next | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
transform | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace Flow\Search\Iterators; |
4 | |
5 | use Flow\Container; |
6 | use Flow\Data\ManagerGroup; |
7 | use Flow\DbFactory; |
8 | use Flow\Model\AbstractRevision; |
9 | use Flow\Model\UUID; |
10 | use Iterator; |
11 | use MediaWiki\WikiMap\WikiMap; |
12 | use ReturnTypeWillChange; |
13 | use stdClass; |
14 | use Wikimedia\Rdbms\IReadableDatabase; |
15 | use Wikimedia\Rdbms\IResultWrapper; |
16 | |
17 | abstract class AbstractIterator implements Iterator { |
18 | /** |
19 | * @var IReadableDatabase |
20 | */ |
21 | protected $dbr; |
22 | |
23 | /** |
24 | * @var array |
25 | */ |
26 | protected $conditions = []; |
27 | |
28 | /** |
29 | * @var IResultWrapper|null |
30 | */ |
31 | protected $results; |
32 | |
33 | /** |
34 | * Depending on where we are in the iteration, this can be null (object |
35 | * constructed but not yet being iterated over), AbstractRevision (being |
36 | * iterated) or false (end of iteration, no more revisions) |
37 | * |
38 | * @var AbstractRevision|null|false |
39 | */ |
40 | protected $current; |
41 | |
42 | /** |
43 | * Depending on where we are in the iteration, this can be integer (object |
44 | * being iterated over) or null (iteration not yet started, or completed) |
45 | * |
46 | * @var int|null |
47 | */ |
48 | protected $key; |
49 | |
50 | /** |
51 | * @param DbFactory $dbFactory |
52 | */ |
53 | public function __construct( DbFactory $dbFactory ) { |
54 | $this->dbr = $dbFactory->getDB( DB_REPLICA ); |
55 | $this->conditions = [ 'workflow_wiki' => WikiMap::getCurrentWikiId() ]; |
56 | } |
57 | |
58 | /** |
59 | * @return bool|IResultWrapper |
60 | */ |
61 | abstract protected function query(); |
62 | |
63 | /** |
64 | * @param array|int|null $pageId |
65 | */ |
66 | public function setPage( $pageId = null ) { |
67 | $this->results = null; |
68 | |
69 | unset( $this->conditions['workflow_page_id'] ); |
70 | if ( $pageId !== null ) { |
71 | $this->conditions['workflow_page_id'] = $pageId; |
72 | } |
73 | } |
74 | |
75 | /** |
76 | * @param int|null $namespace |
77 | */ |
78 | public function setNamespace( $namespace = null ) { |
79 | $this->results = null; |
80 | |
81 | unset( $this->conditions['workflow_namespace'] ); |
82 | if ( $namespace !== null ) { |
83 | $this->conditions['workflow_namespace'] = $namespace; |
84 | } |
85 | } |
86 | |
87 | /** |
88 | * Define where to start iterating (inclusive) |
89 | * |
90 | * @param UUID|null $revId |
91 | */ |
92 | public function setFrom( ?UUID $revId = null ) { |
93 | $this->results = null; |
94 | |
95 | unset( $this->conditions[0] ); |
96 | if ( $revId !== null ) { |
97 | $this->conditions[0] = $this->dbr->expr( 'rev_id', '>=', $revId->getBinary() ); |
98 | } |
99 | } |
100 | |
101 | /** |
102 | * Define where to stop iterating (exclusive) |
103 | * |
104 | * @param UUID|null $revId |
105 | */ |
106 | public function setTo( ?UUID $revId = null ) { |
107 | $this->results = null; |
108 | |
109 | unset( $this->conditions[1] ); |
110 | if ( $revId !== null ) { |
111 | $this->conditions[1] = $this->dbr->expr( 'rev_id', '<', $revId->getBinary() ); |
112 | } |
113 | } |
114 | |
115 | /** |
116 | * @return AbstractRevision|null The most recently fetched revision object |
117 | */ |
118 | #[ReturnTypeWillChange] |
119 | public function current() { |
120 | return $this->current; |
121 | } |
122 | |
123 | /** |
124 | * @return int 0-indexed count of the page number fetched |
125 | */ |
126 | #[\ReturnTypeWillChange] |
127 | public function key() { |
128 | return $this->key; |
129 | } |
130 | |
131 | /** |
132 | * Reset the iterator to the beginning of the table. |
133 | */ |
134 | public function rewind(): void { |
135 | $this->results = null; |
136 | // self::next() will turn this into 0 |
137 | $this->key = -1; |
138 | $this->current = null; |
139 | $this->next(); |
140 | } |
141 | |
142 | /** |
143 | * @return bool True when the iterator is in a valid state |
144 | */ |
145 | public function valid(): bool { |
146 | return (bool)$this->current; |
147 | } |
148 | |
149 | /** |
150 | * Fetch the next set of rows from the database. |
151 | */ |
152 | public function next(): void { |
153 | if ( $this->results === null ) { |
154 | $this->results = $this->query(); |
155 | } |
156 | |
157 | $current = $this->results->fetchObject(); |
158 | if ( $current !== false ) { |
159 | $this->current = $this->transform( $current ); |
160 | $this->key++; |
161 | } else { |
162 | // end of iteration reached |
163 | $this->current = false; |
164 | $this->key = null; |
165 | } |
166 | } |
167 | |
168 | /** |
169 | * Transforms the DB row into a revision object. |
170 | * |
171 | * $row will be one of the results of static::query(). In this method, $row |
172 | * is expected to have at least properties `rev_id` & `rev_type`, which will |
173 | * be used to fetch this specific row's data from storage. |
174 | * |
175 | * This will need to do some DB/cache requests. Ideally, those would be |
176 | * bundled instead of being done on a per-row record. These iterators |
177 | * are only meant to be run in maintenance scripts, however, so it |
178 | * doesn't really matter that much ;) |
179 | * |
180 | * @param stdClass $row |
181 | * @return AbstractRevision |
182 | */ |
183 | protected function transform( stdClass $row ) { |
184 | $uuid = UUID::create( $row->rev_id ); |
185 | |
186 | /** @var ManagerGroup $storage */ |
187 | $storage = Container::get( 'storage' ); |
188 | |
189 | // prevent memory from being filled up |
190 | $storage->clear(); |
191 | |
192 | return $storage->getStorage( $row->rev_type )->get( $uuid ); |
193 | } |
194 | } |