ApiQueryRandom   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
dl 0
loc 182
rs 9.8
c 0
b 0
f 0
wmc 31
lcom 1
cbo 8

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A execute() 0 3 1
A executeGenerator() 0 3 1
D runQuery() 0 64 14
C run() 0 47 10
A getCacheMode() 0 3 1
B getAllowedParams() 0 26 1
A getExamplesMessages() 0 8 1
A getHelpUrls() 0 3 1
1
<?php
2
3
/**
4
 *
5
 *
6
 * Created on Monday, January 28, 2008
7
 *
8
 * Copyright © 2008 Brent Garber
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License along
21
 * with this program; if not, write to the Free Software Foundation, Inc.,
22
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
 * http://www.gnu.org/copyleft/gpl.html
24
 *
25
 * @file
26
 */
27
28
/**
29
 * Query module to get list of random pages
30
 *
31
 * @ingroup API
32
 */
33
class ApiQueryRandom extends ApiQueryGeneratorBase {
34
	public function __construct( ApiQuery $query, $moduleName ) {
35
		parent::__construct( $query, $moduleName, 'rn' );
36
	}
37
38
	public function execute() {
39
		$this->run();
40
	}
41
42
	public function executeGenerator( $resultPageSet ) {
43
		$this->run( $resultPageSet );
44
	}
45
46
	/**
47
	 * Actually perform the query and add pages to the result.
48
	 * @param ApiPageSet|null $resultPageSet
49
	 * @param int $limit Number of pages to fetch
50
	 * @param string|null $start Starting page_random
51
	 * @param int|null $startId Starting page_id
52
	 * @param string|null $end Ending page_random
53
	 * @return array (int, string|null) Number of pages left to query and continuation string
54
	 */
55
	protected function runQuery( $resultPageSet, $limit, $start, $startId, $end ) {
56
		$params = $this->extractRequestParams();
57
58
		$this->resetQueryParams();
59
		$this->addTables( 'page' );
60
		$this->addFields( [ 'page_id', 'page_random' ] );
61
		if ( is_null( $resultPageSet ) ) {
62
			$this->addFields( [ 'page_title', 'page_namespace' ] );
63
		} else {
64
			$this->addFields( $resultPageSet->getPageTableFields() );
65
		}
66
		$this->addWhereFld( 'page_namespace', $params['namespace'] );
67
		if ( $params['redirect'] || $params['filterredir'] === 'redirects' ) {
68
			$this->addWhereFld( 'page_is_redirect', 1 );
69
		} elseif ( $params['filterredir'] === 'nonredirects' ) {
70
			$this->addWhereFld( 'page_is_redirect', 0 );
71
		} elseif ( is_null( $resultPageSet ) ) {
72
			$this->addFields( [ 'page_is_redirect' ] );
73
		}
74
		$this->addOption( 'LIMIT', $limit + 1 );
75
76
		if ( $start !== null ) {
77
			$start = $this->getDB()->addQuotes( $start );
78
			if ( $startId !== null ) {
79
				$startId = (int)$startId;
80
				$this->addWhere( "page_random = $start AND page_id >= $startId OR page_random > $start" );
81
			} else {
82
				$this->addWhere( "page_random >= $start" );
83
			}
84
		}
85
		if ( $end !== null ) {
86
			$this->addWhere( 'page_random < ' . $this->getDB()->addQuotes( $end ) );
87
		}
88
		$this->addOption( 'ORDER BY', [ 'page_random', 'page_id' ] );
89
90
		$result = $this->getResult();
91
		$path = [ 'query', $this->getModuleName() ];
92
93
		$res = $this->select( __METHOD__ );
94
		$count = 0;
95
		foreach ( $res as $row ) {
96
			if ( $count++ >= $limit ) {
97
				return [ 0, "{$row->page_random}|{$row->page_id}" ];
98
			}
99
			if ( is_null( $resultPageSet ) ) {
100
				$title = Title::makeTitle( $row->page_namespace, $row->page_title );
101
				$page = [
102
					'id' => (int)$row->page_id,
103
				];
104
				ApiQueryBase::addTitleInfo( $page, $title );
105
				if ( isset( $row->page_is_redirect ) ) {
106
					$page['redirect'] = (bool)$row->page_is_redirect;
107
				}
108
				$fit = $result->addValue( $path, null, $page );
109
				if ( !$fit ) {
110
					return [ 0, "{$row->page_random}|{$row->page_id}" ];
111
				}
112
			} else {
113
				$resultPageSet->processDbRow( $row );
0 ignored issues
show
Bug introduced by
It seems like $row defined by $row on line 95 can be null; however, ApiPageSet::processDbRow() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
114
			}
115
		}
116
117
		return [ $limit - $count, null ];
118
	}
119
120
	/**
121
	 * @param ApiPageSet|null $resultPageSet
122
	 */
123
	public function run( $resultPageSet = null ) {
124
		$params = $this->extractRequestParams();
125
126
		// Since 'filterredir" will always be set in $params, we have to dig
127
		// into the WebRequest to see if it was actually passed.
128
		$request = $this->getMain()->getRequest();
129
		if ( $request->getCheck( $this->encodeParamName( 'filterredir' ) ) ) {
130
			$this->requireMaxOneParameter( $params, 'filterredir', 'redirect' );
131
		}
132
133
		if ( isset( $params['continue'] ) ) {
134
			$cont = explode( '|', $params['continue'] );
135
			$this->dieContinueUsageIf( count( $cont ) != 4 );
136
			$rand = $cont[0];
137
			$start = $cont[1];
138
			$startId = (int)$cont[2];
139
			$end = $cont[3] ? $rand : null;
140
			$this->dieContinueUsageIf( !preg_match( '/^0\.\d+$/', $rand ) );
141
			$this->dieContinueUsageIf( !preg_match( '/^0\.\d+$/', $start ) );
142
			$this->dieContinueUsageIf( $cont[2] !== (string)$startId );
143
			$this->dieContinueUsageIf( $cont[3] !== '0' && $cont[3] !== '1' );
144
		} else {
145
			$rand = wfRandom();
146
			$start = $rand;
147
			$startId = null;
148
			$end = null;
149
		}
150
151
		list( $left, $continue ) =
152
			$this->runQuery( $resultPageSet, $params['limit'], $start, $startId, $end );
153
		if ( $end === null && $continue === null ) {
154
			// Wrap around. We do this even if $left === 0 for continuation
155
			// (saving a DB query in this rare case probably isn't worth the
156
			// added code complexity it would require).
157
			$end = $rand;
158
			list( $left, $continue ) = $this->runQuery( $resultPageSet, $left, null, null, $end );
0 ignored issues
show
Unused Code introduced by
The assignment to $left is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
159
		}
160
161
		if ( $continue !== null ) {
162
			$endFlag = $end === null ? 0 : 1;
163
			$this->setContinueEnumParameter( 'continue', "$rand|$continue|$endFlag" );
164
		}
165
166
		if ( is_null( $resultPageSet ) ) {
167
			$this->getResult()->addIndexedTagName( [ 'query', $this->getModuleName() ], 'page' );
168
		}
169
	}
170
171
	public function getCacheMode( $params ) {
172
		return 'public';
173
	}
174
175
	public function getAllowedParams() {
176
		return [
177
			'namespace' => [
178
				ApiBase::PARAM_TYPE => 'namespace',
179
				ApiBase::PARAM_ISMULTI => true
180
			],
181
			'filterredir' => [
182
				ApiBase::PARAM_TYPE => [ 'all', 'redirects', 'nonredirects' ],
183
				ApiBase::PARAM_DFLT => 'nonredirects', // for BC
184
			],
185
			'redirect' => [
186
				ApiBase::PARAM_DEPRECATED => true,
187
				ApiBase::PARAM_DFLT => false,
188
			],
189
			'limit' => [
190
				ApiBase::PARAM_TYPE => 'limit',
191
				ApiBase::PARAM_DFLT => 1,
192
				ApiBase::PARAM_MIN => 1,
193
				ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
194
				ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
195
			],
196
			'continue' => [
197
				ApiBase::PARAM_HELP_MSG => 'api-help-param-continue'
198
			],
199
		];
200
	}
201
202
	protected function getExamplesMessages() {
203
		return [
204
			'action=query&list=random&rnnamespace=0&rnlimit=2'
205
				=> 'apihelp-query+random-example-simple',
206
			'action=query&generator=random&grnnamespace=0&grnlimit=2&prop=info'
207
				=> 'apihelp-query+random-example-generator',
208
		];
209
	}
210
211
	public function getHelpUrls() {
212
		return 'https://www.mediawiki.org/wiki/API:Random';
213
	}
214
}
215