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