Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
PendingChangesPager
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 9
930
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
110
 setLimit
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 formatRow
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultQuery
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getQueryInfo
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
156
 getIndexField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doBatchLookups
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getStartBody
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEndBody
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3use MediaWiki\MediaWikiServices;
4use MediaWiki\Pager\AlphabeticPager;
5
6/**
7 * Query to list out outdated reviewed pages
8 */
9class PendingChangesPager extends AlphabeticPager {
10    /** @var PendingChanges */
11    private $mForm;
12
13    /** @var string|null */
14    private $category;
15
16    /** @var int|int[] */
17    private $namespace;
18
19    /** @var int */
20    private $level;
21
22    /** @var int|null */
23    private $size;
24
25    /** @var bool */
26    private $watched;
27
28    /** @var bool */
29    private $stable;
30
31    // Don't get too expensive
32    private const PAGE_LIMIT = 100;
33
34    /**
35     * @param PendingChanges $form
36     * @param int|null $namespace
37     * @param int $level
38     * @param string $category
39     * @param int|null $size
40     * @param bool $watched
41     * @param bool $stable
42     */
43    public function __construct( $form, $namespace, $level = -1, $category = '',
44        $size = null, $watched = false, $stable = false
45    ) {
46        $this->mForm = $form;
47        # Must be a content page...
48        if ( $namespace !== null ) {
49            $namespace = (int)$namespace;
50        }
51        # Sanity check
52        if ( $namespace === null || !FlaggedRevs::isReviewNamespace( $namespace ) ) {
53            $namespace = FlaggedRevs::getReviewNamespaces();
54        }
55        $this->namespace = $namespace;
56        # Sanity check level: 0 = checked; 1 = quality; 2 = pristine
57        $this->level = ( $level >= 0 && $level <= 2 ) ? $level : -1;
58        $this->category = $category ? str_replace( ' ', '_', $category ) : null;
59        $this->size = ( $size !== null ) ? intval( $size ) : null;
60        $this->watched = (bool)$watched;
61        $this->stable = $stable && !FlaggedRevs::isStableShownByDefault()
62            && !FlaggedRevs::useOnlyIfProtected();
63
64        parent::__construct();
65        # Don't get too expensive
66        $this->mLimitsShown = [ 20, 50, 100 ];
67        $this->setLimit( $this->mLimit ); // apply max limit
68    }
69
70    /**
71     * @inheritDoc
72     */
73    public function setLimit( $limit ) {
74        $this->mLimit = min( $limit, self::PAGE_LIMIT );
75    }
76
77    /**
78     * @inheritDoc
79     */
80    public function formatRow( $row ) {
81        return $this->mForm->formatRow( $row );
82    }
83
84    /**
85     * @inheritDoc
86     */
87    public function getDefaultQuery() {
88        $query = parent::getDefaultQuery();
89        $query['category'] = $this->category;
90        return $query;
91    }
92
93    /**
94     * @inheritDoc
95     */
96    public function getQueryInfo() {
97        $tables = [ 'page', 'revision' ];
98        $fields = [ 'page_namespace', 'page_title', 'page_len', 'rev_len', 'page_latest' ];
99        $conds = [];
100        # Show outdated "stable" versions
101        if ( $this->level < 0 ) {
102            $tables[] = 'flaggedpages';
103            $fields['stable'] = 'fp_stable';
104            $fields['quality'] = 'fp_quality';
105            $fields['pending_since'] = 'fp_pending_since';
106            $conds[] = 'page_id = fp_page_id';
107            $conds[] = 'rev_id = fp_stable'; // PK
108            $conds[] = 'fp_pending_since IS NOT NULL';
109            # Filter by pages configured to be stable
110            if ( $this->stable ) {
111                $tables[] = 'flaggedpage_config';
112                $conds[] = 'fp_page_id = fpc_page_id';
113                $conds['fpc_override'] = 1;
114            }
115            # Filter by category
116            if ( $this->category != '' ) {
117                $tables[] = 'categorylinks';
118                $conds[] = 'cl_from = fp_page_id';
119                $conds['cl_to'] = $this->category;
120            }
121            $this->mIndexField = 'fp_pending_since';
122        # Show outdated version for a specific review level
123        } else {
124            $tables[] = 'flaggedpage_pending';
125            $fields['stable'] = 'fpp_rev_id';
126            $fields['quality'] = 'fpp_quality';
127            $fields['pending_since'] = 'fpp_pending_since';
128            $conds[] = 'page_id = fpp_page_id';
129            $conds[] = 'rev_id = fpp_rev_id'; // PK
130            $conds[] = 'fpp_pending_since IS NOT NULL';
131            # Filter by review level
132            $conds['fpp_quality'] = $this->level;
133            # Filter by pages configured to be stable
134            if ( $this->stable ) {
135                $tables[] = 'flaggedpage_config';
136                $conds[] = 'fpp_page_id = fpc_page_id';
137                $conds['fpc_override'] = 1;
138            }
139            # Filter by category
140            if ( $this->category != '' ) {
141                $tables[] = 'categorylinks';
142                $conds[] = 'cl_from = fpp_page_id';
143                $conds['cl_to'] = $this->category;
144            }
145            $this->mIndexField = 'fpp_pending_since';
146        }
147        $fields[] = $this->mIndexField; // Pager needs this
148        # Filter namespace
149        if ( $this->namespace !== null ) {
150            $conds['page_namespace'] = $this->namespace;
151        }
152        # Filter by watchlist
153        if ( $this->watched ) {
154            $uid = $this->getUser()->getId();
155            if ( $uid ) {
156                $tables[] = 'watchlist';
157                $conds['wl_user'] = $uid;
158                $conds[] = 'page_namespace = wl_namespace';
159                $conds[] = 'page_title = wl_title';
160            }
161        }
162        # Filter by bytes changed
163        if ( $this->size !== null && $this->size >= 0 ) {
164            # Note: ABS(x-y) is broken due to mysql unsigned int design.
165            $conds[] = 'GREATEST(page_len,rev_len)-LEAST(page_len,rev_len) <= ' .
166                intval( $this->size );
167        }
168        # Don't display pages with expired protection (T350527)
169        if ( FlaggedRevs::useOnlyIfProtected() ) {
170            $tables[] = 'flaggedpage_config';
171            $conds[] = 'fpc_page_id = fp_page_id';
172            $conds[] = $this->mDb->expr( 'fpc_expiry', '=', 'infinity' )
173                ->or( 'fpc_expiry', '>', $this->mDb->timestamp() );
174        }
175        return [
176            'tables'  => $tables,
177            'fields'  => $fields,
178            'conds'   => $conds
179        ];
180    }
181
182    /**
183     * @inheritDoc
184     */
185    public function getIndexField() {
186        return $this->mIndexField;
187    }
188
189    /**
190     * @inheritDoc
191     */
192    protected function doBatchLookups() {
193        $lb = MediaWikiServices::getInstance()->getLinkBatchFactory()->newLinkBatch();
194        foreach ( $this->mResult as $row ) {
195            $lb->add( $row->page_namespace, $row->page_title );
196        }
197        $lb->execute();
198    }
199
200    /**
201     * @return string HTML
202     */
203    protected function getStartBody() {
204        return '<ul>';
205    }
206
207    /**
208     * @return string HTML
209     */
210    protected function getEndBody() {
211        return '</ul>';
212    }
213}