Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractIterator
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 9
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 query
n/a
0 / 0
n/a
0 / 0
0
 setPage
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setNamespace
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 current
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 rewind
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 valid
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 next
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 transform
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Flow\Search\Iterators;
4
5use Flow\Container;
6use Flow\Data\ManagerGroup;
7use Flow\DbFactory;
8use Flow\Model\AbstractRevision;
9use Flow\Model\UUID;
10use Iterator;
11use MediaWiki\WikiMap\WikiMap;
12use ReturnTypeWillChange;
13use stdClass;
14use Wikimedia\Rdbms\IReadableDatabase;
15use Wikimedia\Rdbms\IResultWrapper;
16
17abstract 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    public function __construct( DbFactory $dbFactory ) {
51        $this->dbr = $dbFactory->getDB( DB_REPLICA );
52        $this->conditions = [ 'workflow_wiki' => WikiMap::getCurrentWikiId() ];
53    }
54
55    /**
56     * @return bool|IResultWrapper
57     */
58    abstract protected function query();
59
60    /**
61     * @param array|int|null $pageId
62     */
63    public function setPage( $pageId = null ) {
64        $this->results = null;
65
66        unset( $this->conditions['workflow_page_id'] );
67        if ( $pageId !== null ) {
68            $this->conditions['workflow_page_id'] = $pageId;
69        }
70    }
71
72    /**
73     * @param int|null $namespace
74     */
75    public function setNamespace( $namespace = null ) {
76        $this->results = null;
77
78        unset( $this->conditions['workflow_namespace'] );
79        if ( $namespace !== null ) {
80            $this->conditions['workflow_namespace'] = $namespace;
81        }
82    }
83
84    /**
85     * @return AbstractRevision|null The most recently fetched revision object
86     */
87    #[ReturnTypeWillChange]
88    public function current() {
89        return $this->current;
90    }
91
92    /**
93     * @return int 0-indexed count of the page number fetched
94     */
95    #[\ReturnTypeWillChange]
96    public function key() {
97        return $this->key;
98    }
99
100    /**
101     * Reset the iterator to the beginning of the table.
102     */
103    public function rewind(): void {
104        $this->results = null;
105        // self::next() will turn this into 0
106        $this->key = -1;
107        $this->current = null;
108        $this->next();
109    }
110
111    /**
112     * @return bool True when the iterator is in a valid state
113     */
114    public function valid(): bool {
115        return (bool)$this->current;
116    }
117
118    /**
119     * Fetch the next set of rows from the database.
120     */
121    public function next(): void {
122        if ( $this->results === null ) {
123            $this->results = $this->query();
124        }
125
126        $current = $this->results->fetchObject();
127        if ( $current !== false ) {
128            $this->current = $this->transform( $current );
129            $this->key++;
130        } else {
131            // end of iteration reached
132            $this->current = false;
133            $this->key = null;
134        }
135    }
136
137    /**
138     * Transforms the DB row into a revision object.
139     *
140     * $row will be one of the results of static::query(). In this method, $row
141     * is expected to have at least properties `rev_id` & `rev_type`, which will
142     * be used to fetch this specific row's data from storage.
143     *
144     * This will need to do some DB/cache requests. Ideally, those would be
145     * bundled instead of being done on a per-row record. These iterators
146     * are only meant to be run in maintenance scripts, however, so it
147     * doesn't really matter that much ;)
148     *
149     * @param stdClass $row
150     * @return AbstractRevision
151     */
152    protected function transform( stdClass $row ) {
153        $uuid = UUID::create( $row->rev_id );
154
155        /** @var ManagerGroup $storage */
156        $storage = Container::get( 'storage' );
157
158        // prevent memory from being filled up
159        $storage->clear();
160
161        return $storage->getStorage( $row->rev_type )->get( $uuid );
162    }
163}