private $mPendingRedirectIDs = array();
private $mConvertedTitles = array();
private $mGoodRevIDs = array();
+ private $mLiveRevIDs = array();
+ private $mDeletedRevIDs = array();
private $mMissingRevIDs = array();
+ private $mGeneratorData = array(); // [ns][dbkey] => data array
private $mFakePageId = -1;
private $mCacheMode = 'public';
private $mRequestedPageFields = array();
if ( !$isDryRun ) {
$generator->executeGenerator( $this );
- wfRunHooks( 'APIQueryGeneratorAfterExecute', array( &$generator, &$this ) );
+ Hooks::run( 'APIQueryGeneratorAfterExecute', array( &$generator, &$this ) );
} else {
// Prevent warnings from being reported on these parameters
$main = $this->getMain();
$pageFlds['page_is_redirect'] = null;
}
+ if ( $this->getConfig()->get( 'ContentHandlerUseDB' ) ) {
+ $pageFlds['page_content_model'] = null;
+ }
+
// only store non-default fields
$this->mRequestedPageFields = array_diff_key( $this->mRequestedPageFields, $pageFlds );
if ( $titleTo->hasFragment() ) {
$r['tofragment'] = $titleTo->getFragment();
}
+ if ( $titleTo->isExternal() ) {
+ $r['tointerwiki'] = $titleTo->getInterwiki();
+ }
$values[] = $r;
}
if ( !empty( $values ) && $result ) {
}
/**
- * Get the list of revision IDs (requested with the revids= parameter)
+ * Get the list of valid revision IDs (requested with the revids= parameter)
* @return array Array of revID (int) => pageID (int)
*/
public function getRevisionIDs() {
return $this->mGoodRevIDs;
}
+ /**
+ * Get the list of non-deleted revision IDs (requested with the revids= parameter)
+ * @return array Array of revID (int) => pageID (int)
+ */
+ public function getLiveRevisionIDs() {
+ return $this->mLiveRevIDs;
+ }
+
+ /**
+ * Get the list of revision IDs that were associated with deleted titles.
+ * @return array Array of revID (int) => pageID (int)
+ */
+ public function getDeletedRevisionIDs() {
+ return $this->mDeletedRevIDs;
+ }
+
/**
* Revision IDs that were not found in the database
* @return array Array of revision IDs
$revid = intval( $row->rev_id );
$pageid = intval( $row->rev_page );
$this->mGoodRevIDs[$revid] = $pageid;
+ $this->mLiveRevIDs[$revid] = $pageid;
$pageids[$pageid] = '';
unset( $remaining[$revid] );
}
// Populate all the page information
$this->initFromPageIds( array_keys( $pageids ) );
+
+ // If the user can see deleted revisions, pull out the corresponding
+ // titles from the archive table and include them too. We ignore
+ // ar_page_id because deleted revisions are tied by title, not page_id.
+ if ( !empty( $this->mMissingRevIDs ) && $this->getUser()->isAllowed( 'deletedhistory' ) ) {
+ $remaining = array_flip( $this->mMissingRevIDs );
+ $tables = array( 'archive' );
+ $fields = array( 'ar_rev_id', 'ar_namespace', 'ar_title' );
+ $where = array( 'ar_rev_id' => $this->mMissingRevIDs );
+
+ $this->profileDBIn();
+ $res = $db->select( $tables, $fields, $where, __METHOD__ );
+ $titles = array();
+ foreach ( $res as $row ) {
+ $revid = intval( $row->ar_rev_id );
+ $titles[$revid] = Title::makeTitle( $row->ar_namespace, $row->ar_title );
+ unset( $remaining[$revid] );
+ }
+ $this->profileDBOut();
+
+ $this->initFromTitles( $titles );
+
+ foreach ( $titles as $revid => $title ) {
+ $ns = $title->getNamespace();
+ $dbkey = $title->getDBkey();
+
+ // Handle converted titles
+ if ( !isset( $this->mAllPages[$ns][$dbkey] ) &&
+ isset( $this->mConvertedTitles[$title->getPrefixedText()] )
+ ) {
+ $title = Title::newFromText( $this->mConvertedTitles[$title->getPrefixedText()] );
+ $ns = $title->getNamespace();
+ $dbkey = $title->getDBkey();
+ }
+
+ if ( isset( $this->mAllPages[$ns][$dbkey] ) ) {
+ $this->mGoodRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
+ $this->mDeletedRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
+ } else {
+ $remaining[$revid] = true;
+ }
+ }
+
+ $this->mMissingRevIDs = array_keys( $remaining );
+ }
}
/**
$row->rd_interwiki
);
unset( $this->mPendingRedirectIDs[$rdfrom] );
- if ( !$to->isExternal() && !isset( $this->mAllPages[$row->rd_namespace][$row->rd_title] ) ) {
+ if ( $to->isExternal() ) {
+ $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
+ } elseif ( !isset( $this->mAllPages[$row->rd_namespace][$row->rd_title] ) ) {
$lb->add( $row->rd_namespace, $row->rd_title );
}
$this->mRedirectTitles[$from] = $to;
return $linkBatch;
}
+ /**
+ * Set data for a title.
+ *
+ * This data may be extracted into an ApiResult using
+ * self::populateGeneratorData. This should generally be limited to
+ * data that is likely to be particularly useful to end users rather than
+ * just being a dump of everything returned in non-generator mode.
+ *
+ * Redirects here will *not* be followed, even if 'redirects' was
+ * specified, since in the case of multiple redirects we can't know which
+ * source's data to use on the target.
+ *
+ * @param Title $title
+ * @param array $data
+ */
+ public function setGeneratorData( Title $title, array $data ) {
+ $ns = $title->getNamespace();
+ $dbkey = $title->getDBkey();
+ $this->mGeneratorData[$ns][$dbkey] = $data;
+ }
+
+ /**
+ * Populate the generator data for all titles in the result
+ *
+ * The page data may be inserted into an ApiResult object or into an
+ * associative array. The $path parameter specifies the path within the
+ * ApiResult or array to find the "pages" node.
+ *
+ * The "pages" node itself must be an associative array mapping the page ID
+ * or fake page ID values returned by this pageset (see
+ * self::getAllTitlesByNamespace() and self::getSpecialTitles()) to
+ * associative arrays of page data. Each of those subarrays will have the
+ * data from self::setGeneratorData() merged in.
+ *
+ * Data that was set by self::setGeneratorData() for pages not in the
+ * "pages" node will be ignored.
+ *
+ * @param ApiResult|array &$result
+ * @param array $path
+ * @return bool Whether the data fit
+ */
+ public function populateGeneratorData( &$result, array $path = array() ) {
+ if ( $result instanceof ApiResult ) {
+ $data = $result->getData();
+ } else {
+ $data = &$result;
+ }
+ foreach ( $path as $key ) {
+ if ( !isset( $data[$key] ) ) {
+ // Path isn't in $result, so nothing to add, so everything
+ // "fits"
+ return true;
+ }
+ $data = &$data[$key];
+ }
+ foreach ( $this->mGeneratorData as $ns => $dbkeys ) {
+ if ( $ns === -1 ) {
+ $pages = array();
+ foreach ( $this->mSpecialTitles as $id => $title ) {
+ $pages[$title->getDBkey()] = $id;
+ }
+ } else {
+ if ( !isset( $this->mAllPages[$ns] ) ) {
+ // No known titles in the whole namespace. Skip it.
+ continue;
+ }
+ $pages = $this->mAllPages[$ns];
+ }
+ foreach ( $dbkeys as $dbkey => $genData ) {
+ if ( !isset( $pages[$dbkey] ) ) {
+ // Unknown title. Forget it.
+ continue;
+ }
+ $pageId = $pages[$dbkey];
+ if ( !isset( $data[$pageId] ) ) {
+ // $pageId didn't make it into the result. Ignore it.
+ continue;
+ }
+
+ if ( $result instanceof ApiResult ) {
+ $path2 = array_merge( $path, array( $pageId ) );
+ foreach ( $genData as $key => $value ) {
+ if ( !$result->addValue( $path2, $key, $value ) ) {
+ return false;
+ }
+ }
+ } else {
+ $data[$pageId] = array_merge( $data[$pageId], $genData );
+ }
+ }
+ }
+ return true;
+ }
+
/**
* Get the database connection (read-only)
* @return DatabaseBase
ApiBase::PARAM_DFLT => false,
ApiBase::PARAM_HELP_MSG => array(
'api-pageset-param-converttitles',
- $this->getLanguage()->commaList( LanguageConverter::$languagesWithVariants ),
+ new DeferredStringifier(
+ function ( IContextSource $context ) {
+ return $context->getLanguage()
+ ->commaList( LanguageConverter::$languagesWithVariants );
+ },
+ $this
+ )
),
),
);
if ( !$this->mAllowGenerator ) {
unset( $result['generator'] );
} elseif ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
- $result['generator'][ApiBase::PARAM_TYPE] = $this->getGenerators();
- foreach ( $result['generator'][ApiBase::PARAM_TYPE] as $g ) {
+ foreach ( $this->getGenerators() as $g ) {
$result['generator'][ApiBase::PARAM_TYPE][] = $g;
$result['generator'][ApiBase::PARAM_VALUE_LINKS][$g] = "Special:ApiHelp/query+$g";
}