Completed
Push — master ( 951284...b5c57e )
by
unknown
06:36 queued 11s
created

client/includes/Api/ApiPropsEntityUsage.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Wikibase\Client\Api;
4
5
use ApiBase;
6
use ApiQuery;
7
use ApiQueryBase;
8
use ApiResult;
9
use Wikibase\Client\RepoLinker;
10
use Wikibase\Client\Usage\EntityUsage;
11
use Wikibase\Client\WikibaseClient;
12
use Wikimedia\Rdbms\IResultWrapper;
13
14
/**
15
 * API module to get the usage of entities.
16
 *
17
 * @license GPL-2.0-or-later
18
 * @author Amir Sarabadani < [email protected] >
19
 */
20
class ApiPropsEntityUsage extends ApiQueryBase {
21
22
	/**
23
	 * @var RepoLinker
24
	 */
25
	private $repoLinker = null;
26
27
	/**
28
	 * @param ApiQuery $query
29
	 * @param string $moduleName
30
	 * @param RepoLinker $repoLinker
31
	 */
32
	public function __construct( ApiQuery $query, $moduleName, RepoLinker $repoLinker ) {
33
		parent::__construct( $query, $moduleName, 'wbeu' );
34
35
		$this->repoLinker = $repoLinker;
36
	}
37
38
	public static function factory( ApiQuery $apiQuery, string $moduleName ): self {
39
		return new self(
40
			$apiQuery,
41
			$moduleName,
42
			WikibaseClient::getDefaultInstance()->newRepoLinker()
43
		);
44
	}
45
46
	public function execute() {
47
		$params = $this->extractRequestParams();
48
		$res = $this->doQuery( $params );
49
		if ( !$res ) {
50
			return;
51
		}
52
53
		$prop = array_flip( (array)$params['prop'] );
54
		$this->formatResult( $res, $params['limit'], $prop );
55
	}
56
57
	/**
58
	 * @param IResultWrapper $res
59
	 * @param int $limit
60
	 * @param array $prop
61
	 */
62
	private function formatResult( IResultWrapper $res, $limit, array $prop ) {
63
		$currentPageId = null;
64
		$entry = [];
65
		$count = 0;
66
67
		foreach ( $res as $row ) {
68
			if ( ++$count > $limit ) {
69
				// We've reached the one extra which shows that
70
				// there are additional pages to be had. Stop here...
71
				$this->setContinueFromRow( $row );
72
				break;
73
			}
74
75
			if ( isset( $currentPageId ) && $row->eu_page_id !== $currentPageId ) {
76
				// Flush out everything we built
77
				$fit = $this->addPageSubItems( $currentPageId, $entry );
78
				if ( !$fit ) {
79
					$this->setContinueFromRow( $row );
80
					break;
81
				}
82
				$entry = [];
83
			}
84
			$currentPageId = $row->eu_page_id;
85
			if ( array_key_exists( $row->eu_entity_id, $entry ) ) {
86
				$entry[$row->eu_entity_id]['aspects'][] = $row->eu_aspect;
87
			} else {
88
				$entry[$row->eu_entity_id] = [ 'aspects' => [ $row->eu_aspect ] ];
89
				if ( isset( $prop['url'] ) ) {
90
					$entry[$row->eu_entity_id]['url'] = $this->repoLinker->getPageUrl(
91
						'Special:EntityPage/' . $row->eu_entity_id );
92
				}
93
				ApiResult::setIndexedTagName(
94
					$entry[$row->eu_entity_id]['aspects'], 'aspect'
95
				);
96
				ApiResult::setArrayType( $entry, 'kvp', 'id' );
97
			}
98
99
		}
100
101
		if ( $entry ) { // Sanity
0 ignored issues
show
Bug Best Practice introduced by
The expression $entry of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
102
			// Flush out remaining ones
103
			$this->addPageSubItems( $currentPageId, $entry );
104
		}
105
	}
106
107
	/**
108
	 * @param object $row
109
	 */
110
	private function setContinueFromRow( $row ) {
111
		$this->setContinueEnumParameter(
112
			'continue',
113
			"{$row->eu_page_id}|{$row->eu_entity_id}|{$row->eu_aspect}"
114
		);
115
	}
116
117
	/**
118
	 * @see ApiQueryBase::getCacheMode
119
	 *
120
	 * @param array $params
121
	 *
122
	 * @return string
123
	 */
124
	public function getCacheMode( $params ) {
125
		return 'public';
126
	}
127
128
	/**
129
	 * @param array $params
130
	 *
131
	 * @return IResultWrapper|null
132
	 */
133
	public function doQuery( array $params ) {
134
		$pages = $this->getPageSet()->getGoodTitles();
135
		if ( !$pages ) {
136
			return null;
137
		}
138
139
		$this->addFields( [
140
			'eu_page_id',
141
			'eu_entity_id',
142
			'eu_aspect'
143
		] );
144
145
		$this->addTables( 'wbc_entity_usage' );
146
		$this->addWhereFld( 'eu_page_id', array_keys( $pages ) );
147
148
		if ( isset( $params['entities'] ) ) {
149
			$this->addWhereFld( 'eu_entity_id', $params['entities'] );
150
		}
151
152
		if ( $params['continue'] !== null ) {
153
			$db = $this->getDB();
154
			list( $pageContinueSql, $entityContinueSql, $aspectContinueSql ) = explode( '|', $params['continue'], 3 );
155
			$pageContinue = (int)$pageContinueSql;
156
			$entityContinue = $db->addQuotes( $entityContinueSql );
157
			$aspectContinue = $db->addQuotes( $aspectContinueSql );
158
			// Filtering out results that have been shown already and
159
			// starting the query from where it ended.
160
			$this->addWhere(
161
				"eu_page_id > $pageContinue OR " .
162
				"(eu_page_id = $pageContinue AND " .
163
				"(eu_entity_id > $entityContinue OR " .
164
				"(eu_entity_id = $entityContinue AND " .
165
				"eu_aspect >= $aspectContinue)))"
166
			);
167
		}
168
169
		$orderBy = [ 'eu_page_id' , 'eu_entity_id' ];
170
		if ( isset( $params['aspect'] ) ) {
171
			$this->addWhereFld( 'eu_aspect', $params['aspect'] );
172
		} else {
173
			$orderBy[] = 'eu_aspect';
174
		}
175
		$this->addOption( 'ORDER BY', $orderBy );
176
177
		$this->addOption( 'LIMIT', $params['limit'] + 1 );
178
		$res = $this->select( __METHOD__ );
179
		return $res;
180
	}
181
182
	public function getAllowedParams() {
183
		return [
184
			'prop' => [
185
				ApiBase::PARAM_ISMULTI => true,
186
				ApiBase::PARAM_TYPE => [
187
					'url',
188
				],
189
				ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
190
			],
191
			'aspect' => [
192
				ApiBase::PARAM_ISMULTI => true,
193
				ApiBase::PARAM_TYPE => [
194
					EntityUsage::SITELINK_USAGE,
195
					EntityUsage::LABEL_USAGE,
196
					EntityUsage::DESCRIPTION_USAGE,
197
					EntityUsage::TITLE_USAGE,
198
					EntityUsage::STATEMENT_USAGE,
199
					EntityUsage::ALL_USAGE,
200
					EntityUsage::OTHER_USAGE,
201
				]
202
			],
203
			'entities' => [
204
				ApiBase::PARAM_ISMULTI => true,
205
			],
206
			'limit' => [
207
				ApiBase::PARAM_DFLT => 10,
208
				ApiBase::PARAM_TYPE => 'limit',
209
				ApiBase::PARAM_MIN => 1,
210
				ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
211
				ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
212
			],
213
			'continue' => [
214
				ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
215
			],
216
		];
217
	}
218
219
	protected function getExamplesMessages() {
220
		return [
221
			'action=query&prop=wbentityusage&titles=Main%20Page'
222
				=> 'apihelp-query+wbentityusage-example-simple',
223
		];
224
	}
225
226
	public function getHelpUrls() {
227
		return 'https://www.mediawiki.org/wiki/Special:MyLanguage/Wikibase/API#wbentityusage';
228
	}
229
230
}
231