00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 if (!defined('MEDIAWIKI')) {
00027
00028 require_once ('ApiQueryBase.php');
00029 }
00030
00044 class ApiPageSet extends ApiQueryBase {
00045
00046 private $mAllPages;
00047 private $mTitles, $mGoodTitles, $mMissingTitles, $mInvalidTitles;
00048 private $mMissingPageIDs, $mRedirectTitles;
00049 private $mNormalizedTitles, $mInterwikiTitles;
00050 private $mResolveRedirects, $mPendingRedirectIDs;
00051 private $mGoodRevIDs, $mMissingRevIDs;
00052 private $mFakePageId;
00053
00054 private $mRequestedPageFields;
00055
00061 public function __construct($query, $resolveRedirects = false) {
00062 parent :: __construct($query, 'query');
00063
00064 $this->mAllPages = array ();
00065 $this->mTitles = array();
00066 $this->mGoodTitles = array ();
00067 $this->mMissingTitles = array ();
00068 $this->mInvalidTitles = array ();
00069 $this->mMissingPageIDs = array ();
00070 $this->mRedirectTitles = array ();
00071 $this->mNormalizedTitles = array ();
00072 $this->mInterwikiTitles = array ();
00073 $this->mGoodRevIDs = array();
00074 $this->mMissingRevIDs = array();
00075
00076 $this->mRequestedPageFields = array ();
00077 $this->mResolveRedirects = $resolveRedirects;
00078 if($resolveRedirects)
00079 $this->mPendingRedirectIDs = array();
00080
00081 $this->mFakePageId = -1;
00082 }
00083
00088 public function isResolvingRedirects() {
00089 return $this->mResolveRedirects;
00090 }
00091
00097 public function requestField($fieldName) {
00098 $this->mRequestedPageFields[$fieldName] = null;
00099 }
00100
00107 public function getCustomField($fieldName) {
00108 return $this->mRequestedPageFields[$fieldName];
00109 }
00110
00117 public function getPageTableFields() {
00118
00119
00120 $pageFlds = array (
00121 'page_namespace' => null,
00122 'page_title' => null,
00123 'page_id' => null,
00124 );
00125
00126 if ($this->mResolveRedirects)
00127 $pageFlds['page_is_redirect'] = null;
00128
00129
00130 $this->mRequestedPageFields = array_diff_key($this->mRequestedPageFields, $pageFlds);
00131
00132 $pageFlds = array_merge($pageFlds, $this->mRequestedPageFields);
00133 return array_keys($pageFlds);
00134 }
00135
00142 public function getAllTitlesByNamespace() {
00143 return $this->mAllPages;
00144 }
00145
00150 public function getTitles() {
00151 return $this->mTitles;
00152 }
00153
00158 public function getTitleCount() {
00159 return count($this->mTitles);
00160 }
00161
00166 public function getGoodTitles() {
00167 return $this->mGoodTitles;
00168 }
00169
00174 public function getGoodTitleCount() {
00175 return count($this->mGoodTitles);
00176 }
00177
00183 public function getMissingTitles() {
00184 return $this->mMissingTitles;
00185 }
00186
00192 public function getInvalidTitles() {
00193 return $this->mInvalidTitles;
00194 }
00195
00200 public function getMissingPageIDs() {
00201 return $this->mMissingPageIDs;
00202 }
00203
00209 public function getRedirectTitles() {
00210 return $this->mRedirectTitles;
00211 }
00212
00218 public function getNormalizedTitles() {
00219 return $this->mNormalizedTitles;
00220 }
00221
00227 public function getInterwikiTitles() {
00228 return $this->mInterwikiTitles;
00229 }
00230
00235 public function getRevisionIDs() {
00236 return $this->mGoodRevIDs;
00237 }
00238
00243 public function getMissingRevisionIDs() {
00244 return $this->mMissingRevIDs;
00245 }
00246
00251 public function getRevisionCount() {
00252 return count($this->getRevisionIDs());
00253 }
00254
00258 public function execute() {
00259 $this->profileIn();
00260 $params = $this->extractRequestParams();
00261
00262
00263 $dataSource = null;
00264 if (isset ($params['titles']))
00265 $dataSource = 'titles';
00266 if (isset ($params['pageids'])) {
00267 if (isset ($dataSource))
00268 $this->dieUsage("Cannot use 'pageids' at the same time as '$dataSource'", 'multisource');
00269 $dataSource = 'pageids';
00270 }
00271 if (isset ($params['revids'])) {
00272 if (isset ($dataSource))
00273 $this->dieUsage("Cannot use 'revids' at the same time as '$dataSource'", 'multisource');
00274 $dataSource = 'revids';
00275 }
00276
00277 switch ($dataSource) {
00278 case 'titles' :
00279 $this->initFromTitles($params['titles']);
00280 break;
00281 case 'pageids' :
00282 $this->initFromPageIds($params['pageids']);
00283 break;
00284 case 'revids' :
00285 if($this->mResolveRedirects)
00286 $this->setWarning('Redirect resolution cannot be used together with the revids= parameter. '.
00287 'Any redirects the revids= point to have not been resolved.');
00288 $this->mResolveRedirects = false;
00289 $this->initFromRevIDs($params['revids']);
00290 break;
00291 default :
00292
00293 break;
00294 }
00295 $this->profileOut();
00296 }
00297
00302 public function populateFromTitles($titles) {
00303 $this->profileIn();
00304 $this->initFromTitles($titles);
00305 $this->profileOut();
00306 }
00307
00312 public function populateFromPageIDs($pageIDs) {
00313 $this->profileIn();
00314 $this->initFromPageIds($pageIDs);
00315 $this->profileOut();
00316 }
00317
00323 public function populateFromQueryResult($db, $queryResult) {
00324 $this->profileIn();
00325 $this->initFromQueryResult($db, $queryResult);
00326 $this->profileOut();
00327 }
00328
00333 public function populateFromRevisionIDs($revIDs) {
00334 $this->profileIn();
00335 $this->initFromRevIDs($revIDs);
00336 $this->profileOut();
00337 }
00338
00343 public function processDbRow($row) {
00344
00345
00346 $title = Title :: makeTitle($row->page_namespace, $row->page_title);
00347
00348 $pageId = intval($row->page_id);
00349 $this->mAllPages[$row->page_namespace][$row->page_title] = $pageId;
00350 $this->mTitles[] = $title;
00351
00352 if ($this->mResolveRedirects && $row->page_is_redirect == '1') {
00353 $this->mPendingRedirectIDs[$pageId] = $title;
00354 } else {
00355 $this->mGoodTitles[$pageId] = $title;
00356 }
00357
00358 foreach ($this->mRequestedPageFields as $fieldName => & $fieldValues)
00359 $fieldValues[$pageId] = $row-> $fieldName;
00360 }
00361
00365 public function finishPageSetGeneration() {
00366 $this->profileIn();
00367 $this->resolvePendingRedirects();
00368 $this->profileOut();
00369 }
00370
00387 private function initFromTitles($titles) {
00388
00389
00390 $linkBatch = $this->processTitlesArray($titles);
00391 if($linkBatch->isEmpty())
00392 return;
00393
00394 $db = $this->getDB();
00395 $set = $linkBatch->constructSet('page', $db);
00396
00397
00398 $this->profileDBIn();
00399 $res = $db->select('page', $this->getPageTableFields(), $set,
00400 __METHOD__);
00401 $this->profileDBOut();
00402
00403
00404 $this->initFromQueryResult($db, $res, $linkBatch->data, true);
00405
00406
00407 $this->resolvePendingRedirects();
00408 }
00409
00414 private function initFromPageIds($pageids) {
00415 if(!count($pageids))
00416 return;
00417
00418 $pageids = array_map('intval', $pageids);
00419 $set = array (
00420 'page_id' => $pageids
00421 );
00422 $db = $this->getDB();
00423
00424
00425 $this->profileDBIn();
00426 $res = $db->select('page', $this->getPageTableFields(), $set,
00427 __METHOD__);
00428 $this->profileDBOut();
00429
00430 $remaining = array_flip($pageids);
00431 $this->initFromQueryResult($db, $res, $remaining, false);
00432
00433
00434 $this->resolvePendingRedirects();
00435 }
00436
00448 private function initFromQueryResult($db, $res, &$remaining = null, $processTitles = null) {
00449 if (!is_null($remaining) && is_null($processTitles))
00450 ApiBase :: dieDebug(__METHOD__, 'Missing $processTitles parameter when $remaining is provided');
00451
00452 while ($row = $db->fetchObject($res)) {
00453
00454 $pageId = intval($row->page_id);
00455
00456
00457 if (isset($remaining)) {
00458 if ($processTitles)
00459 unset ($remaining[$row->page_namespace][$row->page_title]);
00460 else
00461 unset ($remaining[$pageId]);
00462 }
00463
00464
00465 $this->processDbRow($row);
00466 }
00467 $db->freeResult($res);
00468
00469 if(isset($remaining)) {
00470
00471 if($processTitles) {
00472
00473 foreach ($remaining as $ns => $dbkeys) {
00474 foreach ( $dbkeys as $dbkey => $unused ) {
00475 $title = Title :: makeTitle($ns, $dbkey);
00476 $this->mAllPages[$ns][$dbkey] = $this->mFakePageId;
00477 $this->mMissingTitles[$this->mFakePageId] = $title;
00478 $this->mFakePageId--;
00479 $this->mTitles[] = $title;
00480 }
00481 }
00482 }
00483 else
00484 {
00485
00486 if(!$this->mMissingPageIDs)
00487 $this->mMissingPageIDs = array_keys($remaining);
00488 else
00489 $this->mMissingPageIDs = array_merge($this->mMissingPageIDs, array_keys($remaining));
00490 }
00491 }
00492 }
00493
00499 private function initFromRevIDs($revids) {
00500
00501 if(!count($revids))
00502 return;
00503
00504 $revids = array_map('intval', $revids);
00505 $db = $this->getDB();
00506 $pageids = array();
00507 $remaining = array_flip($revids);
00508
00509 $tables = array('revision', 'page');
00510 $fields = array('rev_id', 'rev_page');
00511 $where = array('rev_id' => $revids, 'rev_page = page_id');
00512
00513
00514 $this->profileDBIn();
00515 $res = $db->select($tables, $fields, $where, __METHOD__);
00516 while ($row = $db->fetchObject($res)) {
00517 $revid = intval($row->rev_id);
00518 $pageid = intval($row->rev_page);
00519 $this->mGoodRevIDs[$revid] = $pageid;
00520 $pageids[$pageid] = '';
00521 unset($remaining[$revid]);
00522 }
00523 $db->freeResult($res);
00524 $this->profileDBOut();
00525
00526 $this->mMissingRevIDs = array_keys($remaining);
00527
00528
00529 $this->initFromPageIds(array_keys($pageids));
00530 }
00531
00537 private function resolvePendingRedirects() {
00538
00539 if($this->mResolveRedirects) {
00540 $db = $this->getDB();
00541 $pageFlds = $this->getPageTableFields();
00542
00543
00544
00545 while ($this->mPendingRedirectIDs) {
00546
00547
00548
00549 $linkBatch = $this->getRedirectTargets();
00550
00551 if ($linkBatch->isEmpty())
00552 break;
00553
00554 $set = $linkBatch->constructSet('page', $db);
00555 if($set === false)
00556 break;
00557
00558
00559 $this->profileDBIn();
00560 $res = $db->select('page', $pageFlds, $set, __METHOD__);
00561 $this->profileDBOut();
00562
00563
00564 $this->initFromQueryResult($db, $res, $linkBatch->data, true);
00565 }
00566 }
00567 }
00568
00576 private function getRedirectTargets() {
00577 $lb = new LinkBatch();
00578 $db = $this->getDB();
00579
00580 $this->profileDBIn();
00581 $res = $db->select('redirect', array(
00582 'rd_from',
00583 'rd_namespace',
00584 'rd_title'
00585 ), array('rd_from' => array_keys($this->mPendingRedirectIDs)),
00586 __METHOD__
00587 );
00588 $this->profileDBOut();
00589
00590 while($row = $db->fetchObject($res))
00591 {
00592 $rdfrom = intval($row->rd_from);
00593 $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
00594 $to = Title::makeTitle($row->rd_namespace, $row->rd_title)->getPrefixedText();
00595 unset($this->mPendingRedirectIDs[$rdfrom]);
00596 if(!isset($this->mAllPages[$row->rd_namespace][$row->rd_title]))
00597 $lb->add($row->rd_namespace, $row->rd_title);
00598 $this->mRedirectTitles[$from] = $to;
00599 }
00600 $db->freeResult($res);
00601 if($this->mPendingRedirectIDs)
00602 {
00603 # We found pages that aren't in the redirect table
00604 # Add them
00605 foreach($this->mPendingRedirectIDs as $id => $title)
00606 {
00607 $article = new Article($title);
00608 $rt = $article->insertRedirect();
00609 if(!$rt)
00610 # What the hell. Let's just ignore this
00611 continue;
00612 $lb->addObj($rt);
00613 $this->mRedirectTitles[$title->getPrefixedText()] = $rt->getPrefixedText();
00614 unset($this->mPendingRedirectIDs[$id]);
00615 }
00616 }
00617 return $lb;
00618 }
00619
00629 private function processTitlesArray($titles) {
00630
00631 $linkBatch = new LinkBatch();
00632
00633 foreach ($titles as $title) {
00634
00635 $titleObj = is_string($title) ? Title :: newFromText($title) : $title;
00636 if (!$titleObj)
00637 {
00638 # Handle invalid titles gracefully
00639 $this->mAllpages[0][$title] = $this->mFakePageId;
00640 $this->mInvalidTitles[$this->mFakePageId] = $title;
00641 $this->mFakePageId--;
00642 continue;
00643 }
00644 $iw = $titleObj->getInterwiki();
00645 if (strval($iw) !== '') {
00646
00647 $this->mInterwikiTitles[$titleObj->getPrefixedText()] = $iw;
00648 } else {
00649
00650
00651 if ($titleObj->getNamespace() < 0)
00652 $this->setWarning("No support for special pages has been implemented");
00653 else
00654 $linkBatch->addObj($titleObj);
00655 }
00656
00657
00658
00659
00660
00661
00662 if (is_string($title) && $title !== $titleObj->getPrefixedText()) {
00663 $this->mNormalizedTitles[$title] = $titleObj->getPrefixedText();
00664 }
00665 }
00666
00667 return $linkBatch;
00668 }
00669
00670 protected function getAllowedParams() {
00671 return array (
00672 'titles' => array (
00673 ApiBase :: PARAM_ISMULTI => true
00674 ),
00675 'pageids' => array (
00676 ApiBase :: PARAM_TYPE => 'integer',
00677 ApiBase :: PARAM_ISMULTI => true
00678 ),
00679 'revids' => array (
00680 ApiBase :: PARAM_TYPE => 'integer',
00681 ApiBase :: PARAM_ISMULTI => true
00682 )
00683 );
00684 }
00685
00686 protected function getParamDescription() {
00687 return array (
00688 'titles' => 'A list of titles to work on',
00689 'pageids' => 'A list of page IDs to work on',
00690 'revids' => 'A list of revision IDs to work on'
00691 );
00692 }
00693
00694 public function getVersion() {
00695 return __CLASS__ . ': $Id: ApiPageSet.php 47424 2009-02-18 05:29:11Z werdna $';
00696 }
00697 }