MediaWiki REL1_40
ApiQueryExtLinksUsage.php
Go to the documentation of this file.
1<?php
2
29
34
39 public function __construct( ApiQuery $query, $moduleName ) {
40 parent::__construct( $query, $moduleName, 'eu' );
41 }
42
43 public function execute() {
44 $this->run();
45 }
46
47 public function getCacheMode( $params ) {
48 return 'public';
49 }
50
51 public function executeGenerator( $resultPageSet ) {
52 $this->run( $resultPageSet );
53 }
54
59 private function run( $resultPageSet = null ) {
60 $params = $this->extractRequestParams();
61 $db = $this->getDB();
62
63 $query = $params['query'];
64 $protocol = LinkFilter::getProtocolPrefix( $params['protocol'] );
65
66 $this->addTables( [ 'externallinks', 'page' ] );
67 $this->addJoinConds( [ 'page' => [ 'JOIN', 'page_id=el_from' ] ] );
68
69 $miser_ns = [];
70 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
71 $miser_ns = $params['namespace'] ?: [];
72 } else {
73 $this->addWhereFld( 'page_namespace', $params['namespace'] );
74 }
75
76 $orderBy = [];
77
78 if ( $query !== null && $query !== '' ) {
79 $protocol ??= 'http://';
80
81 // Normalize query to match the normalization applied for the externallinks table
82 $query = Parser::normalizeLinkUrl( $protocol . $query );
83
84 $conds = LinkFilter::getQueryConditions( $query, [
85 'protocol' => '',
86 'oneWildcard' => true,
87 'db' => $db
88 ] );
89 if ( !$conds ) {
90 $this->dieWithError( 'apierror-badquery' );
91 }
92 $this->addWhere( $conds );
93 if ( !isset( $conds['el_index_60'] ) ) {
94 $orderBy[] = 'el_index_60';
95 }
96 } else {
97 $orderBy[] = 'el_index_60';
98
99 if ( $protocol !== null ) {
100 $this->addWhere( 'el_index_60' . $db->buildLike( "$protocol", $db->anyString() ) );
101 } else {
102 // We're querying all protocols, filter out duplicate protocol-relative links
103 $this->addWhere( $db->makeList( [
104 'el_to NOT' . $db->buildLike( '//', $db->anyString() ),
105 'el_index_60 ' . $db->buildLike( 'http://', $db->anyString() ),
106 ], LIST_OR ) );
107 }
108 }
109
110 $orderBy[] = 'el_id';
111
112 $this->addOption( 'ORDER BY', $orderBy );
113 $this->addFields( $orderBy ); // Make sure
114
115 $prop = array_fill_keys( $params['prop'], true );
116 $fld_ids = isset( $prop['ids'] );
117 $fld_title = isset( $prop['title'] );
118 $fld_url = isset( $prop['url'] );
119
120 if ( $resultPageSet === null ) {
121 $this->addFields( [
122 'page_id',
123 'page_namespace',
124 'page_title'
125 ] );
126 $this->addFieldsIf( 'el_to', $fld_url );
127 } else {
128 $this->addFields( $resultPageSet->getPageTableFields() );
129 }
130
131 $limit = $params['limit'];
132 $this->addOption( 'LIMIT', $limit + 1 );
133
134 // T244254: Avoid MariaDB deciding to scan all of `page`.
135 $this->addOption( 'STRAIGHT_JOIN' );
136
137 if ( $params['continue'] !== null ) {
138 $cont = $this->parseContinueParamOrDie( $params['continue'],
139 array_fill( 0, count( $orderBy ), 'string' ) );
140 $conds = array_combine( $orderBy, array_map( 'rawurldecode', $cont ) );
141 $this->addWhere( $db->buildComparison( '>=', $conds ) );
142 }
143
144 $res = $this->select( __METHOD__ );
145
146 $result = $this->getResult();
147
148 if ( $resultPageSet === null ) {
149 $this->executeGenderCacheFromResultWrapper( $res, __METHOD__ );
150 }
151
152 $count = 0;
153 foreach ( $res as $row ) {
154 if ( ++$count > $limit ) {
155 // We've reached the one extra which shows that there are
156 // additional pages to be had. Stop here...
157 $this->setContinue( $orderBy, $row );
158 break;
159 }
160
161 if ( count( $miser_ns ) && !in_array( $row->page_namespace, $miser_ns ) ) {
162 continue;
163 }
164
165 if ( $resultPageSet === null ) {
166 $vals = [
167 ApiResult::META_TYPE => 'assoc',
168 ];
169 if ( $fld_ids ) {
170 $vals['pageid'] = (int)$row->page_id;
171 }
172 if ( $fld_title ) {
173 $title = Title::makeTitle( $row->page_namespace, $row->page_title );
175 }
176 if ( $fld_url ) {
177 $to = $row->el_to;
178 // expand protocol-relative urls
179 if ( $params['expandurl'] ) {
180 $to = wfExpandUrl( $to, PROTO_CANONICAL );
181 }
182 $vals['url'] = $to;
183 }
184 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals );
185 if ( !$fit ) {
186 $this->setContinue( $orderBy, $row );
187 break;
188 }
189 } else {
190 $resultPageSet->processDbRow( $row );
191 }
192 }
193
194 if ( $resultPageSet === null ) {
195 $result->addIndexedTagName( [ 'query', $this->getModuleName() ],
196 $this->getModulePrefix() );
197 }
198 }
199
200 private function setContinue( $orderBy, $row ) {
201 $fields = [];
202 foreach ( $orderBy as $field ) {
203 $fields[] = strtr( $row->$field, [ '%' => '%25', '|' => '%7C' ] );
204 }
205 $this->setContinueEnumParameter( 'continue', implode( '|', $fields ) );
206 }
207
208 public function getAllowedParams() {
209 $ret = [
210 'prop' => [
211 ParamValidator::PARAM_ISMULTI => true,
212 ParamValidator::PARAM_DEFAULT => 'ids|title|url',
213 ParamValidator::PARAM_TYPE => [
214 'ids',
215 'title',
216 'url'
217 ],
219 ],
220 'continue' => [
221 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
222 ],
223 'protocol' => [
224 ParamValidator::PARAM_TYPE => LinkFilter::prepareProtocols(),
225 ParamValidator::PARAM_DEFAULT => '',
226 ],
227 'query' => null,
228 'namespace' => [
229 ParamValidator::PARAM_ISMULTI => true,
230 ParamValidator::PARAM_TYPE => 'namespace'
231 ],
232 'limit' => [
233 ParamValidator::PARAM_DEFAULT => 10,
234 ParamValidator::PARAM_TYPE => 'limit',
235 IntegerDef::PARAM_MIN => 1,
236 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
237 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
238 ],
239 'expandurl' => false,
240 ];
241
242 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
243 $ret['namespace'][ApiBase::PARAM_HELP_MSG_APPEND] = [
244 'api-help-param-limited-in-miser-mode',
245 ];
246 }
247
248 return $ret;
249 }
250
251 protected function getExamplesMessages() {
252 return [
253 'action=query&list=exturlusage&euquery=www.mediawiki.org'
254 => 'apihelp-query+exturlusage-example-simple',
255 ];
256 }
257
258 public function getHelpUrls() {
259 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Exturlusage';
260 }
261}
const PROTO_CANONICAL
Definition Defines.php:199
const LIST_OR
Definition Defines.php:46
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1460
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:514
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition ApiBase.php:173
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1649
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:204
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:229
getResult()
Get the result object.
Definition ApiBase.php:637
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:773
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:166
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:231
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:506
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
addFields( $value)
Add a set of fields to select to the internal array.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
getDB()
Get the Query database connection (read-only)
executeGenderCacheFromResultWrapper(IResultWrapper $res, $fname=__METHOD__, $fieldPrefix='page')
Preprocess the result set to fill the GenderCache with the necessary information before using self::a...
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addFieldsIf( $value, $condition)
Same as addFields(), but add the fields only if a condition is met.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
addWhere( $value)
Add a set of WHERE clauses to the internal array.
executeGenerator( $resultPageSet)
Execute this module as a generator.
getExamplesMessages()
Returns usage examples for this module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getHelpUrls()
Return links to more detailed help pages about the module.
getCacheMode( $params)
Get the cache mode for the data generated by this module.
__construct(ApiQuery $query, $moduleName)
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
This is the main query class.
Definition ApiQuery.php:42
const META_TYPE
Key for the 'type' metadata item.
A class containing constants representing the names of configuration variables.
Represents a title within MediaWiki.
Definition Title.php:82
static normalizeLinkUrl( $url)
Replace unusual escape codes in a URL with their equivalent characters.
Definition Parser.php:2302
Service for formatting and validating API parameters.
Type definition for integer types.