From 7c49c10d802445aa775a43144158ce867ebb9274 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Mon, 15 Aug 2016 14:27:40 -0400 Subject: [PATCH] API: Add a 'known' property when missing-but-known titles are output For example file pages from foreign repos, MediaWiki-namespace messages that haven't been locally customized, and titles manipulated with the 'TitleIsAlwaysKnown' hook. This allows clients to be able to display such titles as bluelinks rather than redlinks. This also has ApiPageSet populate LinkCache to make later checks of ->exists() and ->isKnown() more efficient. Bug: T141963 Change-Id: Idbdfd2896c0ce9425ededd7cb4b60eda89ba7ef5 --- RELEASE-NOTES-1.28 | 2 + includes/api/ApiImageRotate.php | 35 +++------------ includes/api/ApiPageSet.php | 45 +++++++++++++++----- includes/api/ApiParse.php | 10 +++++ includes/api/ApiQuery.php | 13 +++--- includes/api/ApiSetNotificationTimestamp.php | 3 ++ 6 files changed, 61 insertions(+), 47 deletions(-) diff --git a/RELEASE-NOTES-1.28 b/RELEASE-NOTES-1.28 index 8a25a05122..b9278d058d 100644 --- a/RELEASE-NOTES-1.28 +++ b/RELEASE-NOTES-1.28 @@ -119,6 +119,8 @@ production. module without listing them all explicitly. * (T146770) It is now possible to assert that the current user is a specific named user, using the 'assertuser' parameter. +* (T141963) Added a 'known' property when missing-but-known titles (e.g. from + the 'TitleIsAlwaysKnown' hook) are output in various modules. === Action API internal changes in 1.28 === * Added a new hook, 'ApiMakeParserOptions', to allow extensions to better diff --git a/includes/api/ApiImageRotate.php b/includes/api/ApiImageRotate.php index 966bcbf6b6..37cb80a9fc 100644 --- a/includes/api/ApiImageRotate.php +++ b/includes/api/ApiImageRotate.php @@ -24,30 +24,6 @@ class ApiImageRotate extends ApiBase { private $mPageSet = null; - /** - * Add all items from $values into the result - * @param array $result Output - * @param array $values Values to add - * @param string $flag The name of the boolean flag to mark this element - * @param string $name If given, name of the value - */ - private static function addValues( array &$result, $values, $flag = null, $name = null ) { - foreach ( $values as $val ) { - if ( $val instanceof Title ) { - $v = []; - ApiQueryBase::addTitleInfo( $v, $val ); - } elseif ( $name !== null ) { - $v = [ $name => $val ]; - } else { - $v = $val; - } - if ( $flag !== null ) { - $v[$flag] = true; - } - $result[] = $v; - } - } - public function execute() { $this->useTransactionalTimeLimit(); @@ -62,11 +38,9 @@ class ApiImageRotate extends ApiBase { $result = []; - self::addValues( $result, $pageSet->getInvalidTitlesAndReasons(), 'invalid' ); - self::addValues( $result, $pageSet->getSpecialTitles(), 'special', 'title' ); - self::addValues( $result, $pageSet->getMissingPageIDs(), 'missing', 'pageid' ); - self::addValues( $result, $pageSet->getMissingRevisionIDs(), 'missing', 'revid' ); - self::addValues( $result, $pageSet->getInterwikiTitlesAsResult() ); + $result = $pageSet->getInvalidTitlesAndRevisions( [ + 'invalidTitles', 'special', 'missingIds', 'missingRevIds', 'interwikiTitles', + ] ); foreach ( $pageSet->getTitles() as $title ) { $r = []; @@ -74,6 +48,9 @@ class ApiImageRotate extends ApiBase { ApiQueryBase::addTitleInfo( $r, $title ); if ( !$title->exists() ) { $r['missing'] = true; + if ( $title->isKnown() ) { + $r['known'] = true; + } } $file = wfFindFile( $title, [ 'latest' => true ] ); diff --git a/includes/api/ApiPageSet.php b/includes/api/ApiPageSet.php index 34c17c1ef3..46c57b86b4 100644 --- a/includes/api/ApiPageSet.php +++ b/includes/api/ApiPageSet.php @@ -86,10 +86,10 @@ class ApiPageSet extends ApiBase { * Add all items from $values into the result * @param array $result Output * @param array $values Values to add - * @param string $flag The name of the boolean flag to mark this element + * @param string[] $flags The names of boolean flags to mark this element * @param string $name If given, name of the value */ - private static function addValues( array &$result, $values, $flag = null, $name = null ) { + private static function addValues( array &$result, $values, $flags = [], $name = null ) { foreach ( $values as $val ) { if ( $val instanceof Title ) { $v = []; @@ -99,7 +99,7 @@ class ApiPageSet extends ApiBase { } else { $v = $val; } - if ( $flag !== null ) { + foreach ( $flags as $flag ) { $v[$flag] = true; } $result[] = $v; @@ -309,8 +309,9 @@ class ApiPageSet extends ApiBase { $pageFlds['page_lang'] = null; } - // only store non-default fields - $this->mRequestedPageFields = array_diff_key( $this->mRequestedPageFields, $pageFlds ); + foreach ( LinkCache::getSelectFields() as $field ) { + $pageFlds[$field] = null; + } $pageFlds = array_merge( $pageFlds, $this->mRequestedPageFields ); @@ -600,19 +601,39 @@ class ApiPageSet extends ApiBase { ) { $result = []; if ( in_array( 'invalidTitles', $invalidChecks ) ) { - self::addValues( $result, $this->getInvalidTitlesAndReasons(), 'invalid' ); + self::addValues( $result, $this->getInvalidTitlesAndReasons(), [ 'invalid' ] ); } if ( in_array( 'special', $invalidChecks ) ) { - self::addValues( $result, $this->getSpecialTitles(), 'special', 'title' ); + $known = []; + $unknown = []; + foreach ( $this->getSpecialTitles() as $title ) { + if ( $title->isKnown() ) { + $known[] = $title; + } else { + $unknown[] = $title; + } + } + self::addValues( $result, $unknown, [ 'special', 'missing' ] ); + self::addValues( $result, $known, [ 'special' ] ); } if ( in_array( 'missingIds', $invalidChecks ) ) { - self::addValues( $result, $this->getMissingPageIDs(), 'missing', 'pageid' ); + self::addValues( $result, $this->getMissingPageIDs(), [ 'missing' ], 'pageid' ); } if ( in_array( 'missingRevIds', $invalidChecks ) ) { - self::addValues( $result, $this->getMissingRevisionIDs(), 'missing', 'revid' ); + self::addValues( $result, $this->getMissingRevisionIDs(), [ 'missing' ], 'revid' ); } if ( in_array( 'missingTitles', $invalidChecks ) ) { - self::addValues( $result, $this->getMissingTitles(), 'missing' ); + $known = []; + $unknown = []; + foreach ( $this->getMissingTitles() as $title ) { + if ( $title->isKnown() ) { + $known[] = $title; + } else { + $unknown[] = $title; + } + } + self::addValues( $result, $unknown, [ 'missing' ] ); + self::addValues( $result, $known, [ 'missing', 'known' ] ); } if ( in_array( 'interwikiTitles', $invalidChecks ) ) { self::addValues( $result, $this->getInterwikiTitlesAsResult() ); @@ -734,6 +755,8 @@ class ApiPageSet extends ApiBase { // Store Title object in various data structures $title = Title::newFromRow( $row ); + LinkCache::singleton()->addGoodLinkObjFromRow( $title, $row ); + $pageId = intval( $row->page_id ); $this->mAllPages[$row->page_namespace][$row->page_title] = $pageId; $this->mTitles[] = $title; @@ -863,9 +886,11 @@ class ApiPageSet extends ApiBase { // Any items left in the $remaining list are added as missing if ( $processTitles ) { // The remaining titles in $remaining are non-existent pages + $linkCache = LinkCache::singleton(); foreach ( $remaining as $ns => $dbkeys ) { foreach ( array_keys( $dbkeys ) as $dbkey ) { $title = Title::makeTitle( $ns, $dbkey ); + $linkCache->addBadLinkObj( $title ); $this->mAllPages[$ns][$dbkey] = $this->mFakePageId; $this->mMissingPages[$ns][$dbkey] = $this->mFakePageId; $this->mGoodAndMissingPages[$ns][$dbkey] = $this->mFakePageId; diff --git a/includes/api/ApiParse.php b/includes/api/ApiParse.php index 83b5d93e61..0cad5dee9c 100644 --- a/includes/api/ApiParse.php +++ b/includes/api/ApiParse.php @@ -641,6 +641,8 @@ class ApiParse extends ApiBase { $hiddencats[$row->page_title] = isset( $row->pp_propname ); } + $linkCache = LinkCache::singleton(); + foreach ( $links as $link => $sortkey ) { $entry = []; $entry['sortkey'] = $sortkey; @@ -648,6 +650,14 @@ class ApiParse extends ApiBase { ApiResult::setContentValue( $entry, 'category', (string)$link ); if ( !isset( $hiddencats[$link] ) ) { $entry['missing'] = true; + + // We already know the link doesn't exist in the database, so + // tell LinkCache that before calling $title->isKnown(). + $title = Title::makeTitle( NS_CATEGORY, $link ); + $linkCache->addBadLinkObj( $title ); + if ( $title->isKnown() ) { + $entry['known'] = true; + } } elseif ( $hiddencats[$link] ) { $entry['hidden'] = true; } diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php index 2f532097ee..16bd725e3c 100644 --- a/includes/api/ApiQuery.php +++ b/includes/api/ApiQuery.php @@ -362,6 +362,9 @@ class ApiQuery extends ApiBase { $vals = []; ApiQueryBase::addTitleInfo( $vals, $title ); $vals['missing'] = true; + if ( $title->isKnown() ) { + $vals['known'] = true; + } $pages[$fakeId] = $vals; } // Report any invalid titles @@ -372,7 +375,7 @@ class ApiQuery extends ApiBase { foreach ( $pageSet->getMissingPageIDs() as $pageid ) { $pages[$pageid] = [ 'pageid' => $pageid, - 'missing' => true + 'missing' => true, ]; } // Report special pages @@ -381,13 +384,7 @@ class ApiQuery extends ApiBase { $vals = []; ApiQueryBase::addTitleInfo( $vals, $title ); $vals['special'] = true; - if ( $title->isSpecialPage() && - !SpecialPageFactory::exists( $title->getDBkey() ) - ) { - $vals['missing'] = true; - } elseif ( $title->getNamespace() == NS_MEDIA && - !wfFindFile( $title ) - ) { + if ( !$title->isKnown() ) { $vals['missing'] = true; } $pages[$fakeId] = $vals; diff --git a/includes/api/ApiSetNotificationTimestamp.php b/includes/api/ApiSetNotificationTimestamp.php index f3356821ef..3412f38ed3 100644 --- a/includes/api/ApiSetNotificationTimestamp.php +++ b/includes/api/ApiSetNotificationTimestamp.php @@ -158,6 +158,9 @@ class ApiSetNotificationTimestamp extends ApiBase { ]; if ( !$title->exists() ) { $r['missing'] = true; + if ( $title->isKnown() ) { + $r['known'] = true; + } } if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] ) ) { $r['notificationtimestamp'] = ''; -- 2.20.1