=== Action API changes in 1.27 ===
* Added list=allrevisions.
* generator=recentchanges now has the option to generate revids.
+* ApiPageSet::setRedirectMergePolicy() was added. This allows generator
+ modules to define how generator data for a redirect source gets merged
+ into the redirect destination.
=== Action API internal changes in 1.27 ===
private $mRequestedPageFields = array();
/** @var int */
private $mDefaultNamespace = NS_MAIN;
+ /** @var callable|null */
+ private $mRedirectMergePolicy;
/**
* Add all items from $values into the result
$this->mGeneratorData[$ns][$dbkey] = $data;
}
+ /**
+ * Controls how generator data about a redirect source is merged into
+ * the generator data for the redirect target. When not set no data
+ * is merged. Note that if multiple titles redirect to the same target
+ * the order of operations is undefined.
+ *
+ * Example to include generated data from redirect in target, prefering
+ * the data generated for the destination when there is a collision:
+ * @code
+ * $pageSet->setRedirectMergePolicy( function( array $current, array $new ) {
+ * return $current + $new;
+ * } );
+ * @endcode
+ *
+ * @param callable|null $callable Recieves two array arguments, first the
+ * generator data for the redirect target and second the generator data
+ * for the redirect source. Returns the resulting generator data to use
+ * for the redirect target.
+ */
+ public function setRedirectMergePolicy( $callable ) {
+ $this->mRedirectMergePolicy = $callable;
+ }
+
/**
* Populate the generator data for all titles in the result
*
}
}
}
+
+ // Merge data generated about redirect titles into the redirect destination
+ if ( $this->mRedirectMergePolicy ) {
+ foreach ( $this->mResolvedRedirectTitles as $titleFrom ) {
+ $dest = $titleFrom;
+ while ( isset( $this->mRedirectTitles[$dest->getPrefixedText()] ) ) {
+ $dest = $this->mRedirectTitles[$dest->getPrefixedText()];
+ }
+ $fromNs = $titleFrom->getNamespace();
+ $fromDBkey = $titleFrom->getDBkey();
+ $toPageId = $dest->getArticleID();
+ if ( isset( $data[$toPageId] ) &&
+ isset( $this->mGeneratorData[$fromNs][$fromDBkey] )
+ ) {
+ // It is necesary to set both $data and add to $result, if an ApiResult,
+ // to ensure multiple redirects to the same destination are all merged.
+ $data[$toPageId] = call_user_func(
+ $this->mRedirectMergePolicy,
+ $data[$toPageId],
+ $this->mGeneratorData[$fromNs][$fromDBkey]
+ );
+ if ( $result instanceof ApiResult ) {
+ if ( !$result->addValue( $path, $toPageId, $data[$toPageId], ApiResult::OVERRIDE ) ) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
return true;
}
$searcher = new TitlePrefixSearch;
$titles = $searcher->searchWithVariants( $search, $limit + 1, $namespaces, $offset );
if ( $resultPageSet ) {
+ $resultPageSet->setRedirectMergePolicy( function( array $current, array $new ) {
+ if ( !isset( $current['index'] ) || $new['index'] < $current['index'] ) {
+ $current['index'] = $new['index'];
+ }
+ return $current;
+ } );
if ( count( $titles ) > $limit ) {
$this->setContinueEnumParameter( 'offset', $offset + $params['limit'] );
array_pop( $titles );
), 'p' );
}
} else {
+ $resultPageSet->setRedirectMergePolicy( function ( $current, $new ) {
+ if ( !isset( $current['index'] ) || $new['index'] < $current['index'] ) {
+ $current['index'] = $new['index'];
+ }
+ return $current;
+ } );
$resultPageSet->populateFromTitles( $titles );
$offset = $params['offset'] + 1;
foreach ( $titles as $index => $title ) {
--- /dev/null
+<?php
+
+/**
+ * @group API
+ * @group medium
+ * @group Database
+ */
+class ApiPageSetTest extends ApiTestCase {
+ public static function provideRedirectMergePolicy() {
+ return array(
+ 'By default nothing is merged' => array(
+ null,
+ array()
+ ),
+
+ 'A simple merge policy adds the redirect data in' => array(
+ function( $current, $new ) {
+ if ( !isset( $current['index'] ) || $new['index'] < $current['index'] ) {
+ $current['index'] = $new['index'];
+ }
+ return $current;
+ },
+ array( 'index' => 1 ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRedirectMergePolicy
+ */
+ public function testRedirectMergePolicyWithArrayResult( $mergePolicy, $expect ) {
+ list( $target, $pageSet ) = $this->createPageSetWithRedirect();
+ $pageSet->setRedirectMergePolicy( $mergePolicy );
+ $result = array(
+ $target->getArticleID() => array()
+ );
+ $pageSet->populateGeneratorData( $result );
+ $this->assertEquals( $expect, $result[$target->getArticleID()] );
+ }
+
+ /**
+ * @dataProvider provideRedirectMergePolicy
+ */
+ public function testRedirectMergePolicyWithApiResult( $mergePolicy, $expect ) {
+ list( $target, $pageSet ) = $this->createPageSetWithRedirect();
+ $pageSet->setRedirectMergePolicy( $mergePolicy );
+ $result = new ApiResult( false );
+ $result->addValue( null, 'pages', array(
+ $target->getArticleID() => array()
+ ) );
+ $pageSet->populateGeneratorData( $result, array( 'pages' ) );
+ $this->assertEquals(
+ $expect,
+ $result->getResultData( array( 'pages', $target->getArticleID() ) )
+ );
+ }
+
+ protected function createPageSetWithRedirect() {
+ $target = Title::makeTitle( NS_MAIN, 'UTRedirectTarget' );
+ $sourceA = Title::makeTitle( NS_MAIN, 'UTRedirectSourceA' );
+ $sourceB = Title::makeTitle( NS_MAIN, 'UTRedirectSourceB' );
+ self::editPage( 'UTRedirectTarget', 'api page set test' );
+ self::editPage( 'UTRedirectSourceA', '#REDIRECT [[UTRedirectTarget]]' );
+ self::editPage( 'UTRedirectSourceB', '#REDIRECT [[UTRedirectTarget]]' );
+
+ $request = new FauxRequest( array( 'redirects' => 1 ) );
+ $context = new RequestContext();
+ $context->setRequest( $request );
+ $main = new ApiMain( $context );
+ $pageSet = new ApiPageSet( $main );
+
+ $pageSet->setGeneratorData( $sourceA, array( 'index' => 1 ) );
+ $pageSet->setGeneratorData( $sourceB, array( 'index' => 3 ) );
+ $pageSet->populateFromTitles( array( $sourceA, $sourceB ) );
+
+ return array( $target, $pageSet );
+ }
+}