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