MediaWiki  master
ApiQueryLinks.php
Go to the documentation of this file.
1 <?php
29 
30  private const LINKS = 'links';
31  private const TEMPLATES = 'templates';
32 
34 
35  public function __construct( ApiQuery $query, $moduleName ) {
36  switch ( $moduleName ) {
37  case self::LINKS:
38  $this->table = 'pagelinks';
39  $this->prefix = 'pl';
40  $this->titlesParam = 'titles';
41  $this->helpUrl = 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Links';
42  break;
43  case self::TEMPLATES:
44  $this->table = 'templatelinks';
45  $this->prefix = 'tl';
46  $this->titlesParam = 'templates';
47  $this->helpUrl = 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Templates';
48  break;
49  default:
50  ApiBase::dieDebug( __METHOD__, 'Unknown module name' );
51  }
52 
53  parent::__construct( $query, $moduleName, $this->prefix );
54  }
55 
56  public function execute() {
57  $this->run();
58  }
59 
60  public function getCacheMode( $params ) {
61  return 'public';
62  }
63 
64  public function executeGenerator( $resultPageSet ) {
65  $this->run( $resultPageSet );
66  }
67 
71  private function run( $resultPageSet = null ) {
72  if ( $this->getPageSet()->getGoodTitleCount() == 0 ) {
73  return; // nothing to do
74  }
75 
76  $params = $this->extractRequestParams();
77 
78  $this->addFields( [
79  'pl_from' => $this->prefix . '_from',
80  'pl_namespace' => $this->prefix . '_namespace',
81  'pl_title' => $this->prefix . '_title'
82  ] );
83 
84  $this->addTables( $this->table );
85  $this->addWhereFld( $this->prefix . '_from', array_keys( $this->getPageSet()->getGoodTitles() ) );
86 
87  $multiNS = true;
88  $multiTitle = true;
89  if ( $params[$this->titlesParam] ) {
90  // Filter the titles in PHP so our ORDER BY bug avoidance below works right.
91  $filterNS = $params['namespace'] ? array_flip( $params['namespace'] ) : false;
92 
93  $lb = new LinkBatch;
94  foreach ( $params[$this->titlesParam] as $t ) {
96  if ( !$title ) {
97  $this->addWarning( [ 'apiwarn-invalidtitle', wfEscapeWikiText( $t ) ] );
98  } elseif ( !$filterNS || isset( $filterNS[$title->getNamespace()] ) ) {
99  $lb->addObj( $title );
100  }
101  }
102  $cond = $lb->constructSet( $this->prefix, $this->getDB() );
103  if ( $cond ) {
104  $this->addWhere( $cond );
105  $multiNS = count( $lb->data ) !== 1;
106  $multiTitle = count( array_merge( ...$lb->data ) ) !== 1;
107  } else {
108  // No titles so no results
109  return;
110  }
111  } elseif ( $params['namespace'] ) {
112  $this->addWhereFld( $this->prefix . '_namespace', $params['namespace'] );
113  $multiNS = $params['namespace'] === null || count( $params['namespace'] ) !== 1;
114  }
115 
116  if ( $params['continue'] !== null ) {
117  $cont = explode( '|', $params['continue'] );
118  $this->dieContinueUsageIf( count( $cont ) != 3 );
119  $op = $params['dir'] == 'descending' ? '<' : '>';
120  $plfrom = (int)$cont[0];
121  $plns = (int)$cont[1];
122  $pltitle = $this->getDB()->addQuotes( $cont[2] );
123  $this->addWhere(
124  "{$this->prefix}_from $op $plfrom OR " .
125  "({$this->prefix}_from = $plfrom AND " .
126  "({$this->prefix}_namespace $op $plns OR " .
127  "({$this->prefix}_namespace = $plns AND " .
128  "{$this->prefix}_title $op= $pltitle)))"
129  );
130  }
131 
132  $sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
133  // Here's some MySQL craziness going on: if you use WHERE foo='bar'
134  // and later ORDER BY foo MySQL doesn't notice the ORDER BY is pointless
135  // but instead goes and filesorts, because the index for foo was used
136  // already. To work around this, we drop constant fields in the WHERE
137  // clause from the ORDER BY clause
138  $order = [];
139  if ( count( $this->getPageSet()->getGoodTitles() ) != 1 ) {
140  $order[] = $this->prefix . '_from' . $sort;
141  }
142  if ( $multiNS ) {
143  $order[] = $this->prefix . '_namespace' . $sort;
144  }
145  if ( $multiTitle ) {
146  $order[] = $this->prefix . '_title' . $sort;
147  }
148  if ( $order ) {
149  $this->addOption( 'ORDER BY', $order );
150  }
151  $this->addOption( 'LIMIT', $params['limit'] + 1 );
152 
153  $res = $this->select( __METHOD__ );
154 
155  if ( $resultPageSet === null ) {
156  $this->executeGenderCacheFromResultWrapper( $res, __METHOD__, 'pl' );
157 
158  $count = 0;
159  foreach ( $res as $row ) {
160  if ( ++$count > $params['limit'] ) {
161  // We've reached the one extra which shows that
162  // there are additional pages to be had. Stop here...
163  $this->setContinueEnumParameter( 'continue',
164  "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}" );
165  break;
166  }
167  $vals = [];
168  ApiQueryBase::addTitleInfo( $vals, Title::makeTitle( $row->pl_namespace, $row->pl_title ) );
169  $fit = $this->addPageSubItem( $row->pl_from, $vals );
170  if ( !$fit ) {
171  $this->setContinueEnumParameter( 'continue',
172  "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}" );
173  break;
174  }
175  }
176  } else {
177  $titles = [];
178  $count = 0;
179  foreach ( $res as $row ) {
180  if ( ++$count > $params['limit'] ) {
181  // We've reached the one extra which shows that
182  // there are additional pages to be had. Stop here...
183  $this->setContinueEnumParameter( 'continue',
184  "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}" );
185  break;
186  }
187  $titles[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
188  }
189  $resultPageSet->populateFromTitles( $titles );
190  }
191  }
192 
193  public function getAllowedParams() {
194  return [
195  'namespace' => [
196  ApiBase::PARAM_TYPE => 'namespace',
197  ApiBase::PARAM_ISMULTI => true,
199  ],
200  'limit' => [
201  ApiBase::PARAM_DFLT => 10,
202  ApiBase::PARAM_TYPE => 'limit',
203  ApiBase::PARAM_MIN => 1,
206  ],
207  'continue' => [
208  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
209  ],
210  $this->titlesParam => [
211  ApiBase::PARAM_ISMULTI => true,
212  ],
213  'dir' => [
214  ApiBase::PARAM_DFLT => 'ascending',
216  'ascending',
217  'descending'
218  ]
219  ],
220  ];
221  }
222 
223  protected function getExamplesMessages() {
224  $name = $this->getModuleName();
225  $path = $this->getModulePath();
226 
227  return [
228  "action=query&prop={$name}&titles=Main%20Page"
229  => "apihelp-{$path}-example-simple",
230  "action=query&generator={$name}&titles=Main%20Page&prop=info"
231  => "apihelp-{$path}-example-generator",
232  "action=query&prop={$name}&titles=Main%20Page&{$this->prefix}namespace=2|10"
233  => "apihelp-{$path}-example-namespaces",
234  ];
235  }
236 
237  public function getHelpUrls() {
238  return $this->helpUrl;
239  }
240 }
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:329
ApiQueryBase\addFields
addFields( $value)
Add a set of fields to select to the internal array.
Definition: ApiQueryBase.php:215
ApiQuery
This is the main query class.
Definition: ApiQuery.php:37
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1301
LinkBatch
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:35
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:107
ApiBase\PARAM_TYPE
const PARAM_TYPE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:71
ApiQueryBase\addOption
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
Definition: ApiQueryBase.php:381
$res
$res
Definition: testCompression.php:57
ApiQueryGeneratorBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
Definition: ApiQueryGeneratorBase.php:83
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:58
ApiBase\PARAM_MIN
const PARAM_MIN
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:74
ApiQueryBase\executeGenderCacheFromResultWrapper
executeGenderCacheFromResultWrapper(IResultWrapper $res, $fname=__METHOD__, $fieldPrefix='page')
Preprocess the result set to fill the GenderCache with the necessary information before using self::a...
Definition: ApiQueryBase.php:630
ApiQueryGeneratorBase\getPageSet
getPageSet()
Get the PageSet object to work on.
Definition: ApiQueryGeneratorBase.php:57
ApiBase\getModulePath
getModulePath()
Get the path to this module.
Definition: ApiBase.php:509
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:165
ApiQueryBase\getDB
getDB()
Get the Query database connection (read-only) Stable to override.
Definition: ApiQueryBase.php:119
ApiBase\PARAM_MAX
const PARAM_MAX
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:72
ApiQueryBase\addTables
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
Definition: ApiQueryBase.php:185
ApiQueryBase\select
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
Definition: ApiQueryBase.php:402
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:717
$title
$title
Definition: testCompression.php:38
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:592
ApiBase\PARAM_EXTRA_NAMESPACES
const PARAM_EXTRA_NAMESPACES
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:81
NS_MEDIA
const NS_MEDIA
Definition: Defines.php:57
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1562
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1487
ApiQueryBase\addWhereFld
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
Definition: ApiQueryBase.php:285
ApiQueryGeneratorBase
Stable to extend.
Definition: ApiQueryGeneratorBase.php:28
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:167
$path
$path
Definition: NoLocalSettings.php:25
ApiBase\PARAM_DFLT
const PARAM_DFLT
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:69
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:444
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:70
ApiBase\PARAM_MAX2
const PARAM_MAX2
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:73
ApiQueryBase\addWhere
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Definition: ApiQueryBase.php:248
$t
$t
Definition: testCompression.php:74
ApiQueryBase\addPageSubItem
addPageSubItem( $pageId, $item, $elemname=null)
Same as addPageSubItems(), but one element of $data at a time.
Definition: ApiQueryBase.php:498
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1574
ApiQueryBase\addTitleInfo
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
Definition: ApiQueryBase.php:470