X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fresourceloader%2FResourceLoaderWikiModule.php;h=3deeb84481f19db173408a0c73a4ff627d7adf6e;hb=69ae945e8d39972a07bea89ddb64bc0189b43ac2;hp=5580306a134e12144c1f203880e685c8ef9c36ba;hpb=4a975b8099ee11b15421d03be02206935a8422f1;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/resourceloader/ResourceLoaderWikiModule.php b/includes/resourceloader/ResourceLoaderWikiModule.php index 5580306a13..3deeb84481 100644 --- a/includes/resourceloader/ResourceLoaderWikiModule.php +++ b/includes/resourceloader/ResourceLoaderWikiModule.php @@ -26,7 +26,8 @@ * Abstraction for ResourceLoader modules which pull from wiki pages * * This can only be used for wiki pages in the MediaWiki and User namespaces, - * because of its dependence on the functionality of Title::isCssJsSubpage. + * because of its dependence on the functionality of Title::isCssJsSubpage + * and Title::isCssOrJsPage(). * * This module supports being used as a placeholder for a module on a remote wiki. * To do so, getDB() must be overloaded to return a foreign database object that @@ -143,7 +144,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { } /** - * @param string $title + * @param string $titleText * @return null|string */ protected function getContent( $titleText ) { @@ -296,16 +297,20 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { sort( $pageNames ); $key = implode( '|', $pageNames ); if ( !isset( $this->titleInfo[$key] ) ) { - $this->titleInfo[$key] = self::fetchTitleInfo( $dbr, $pageNames, __METHOD__ ); + $this->titleInfo[$key] = static::fetchTitleInfo( $dbr, $pageNames, __METHOD__ ); } return $this->titleInfo[$key]; } - private static function fetchTitleInfo( IDatabase $db, array $pages, $fname = __METHOD__ ) { + protected static function fetchTitleInfo( IDatabase $db, array $pages, $fname = __METHOD__ ) { $titleInfo = []; $batch = new LinkBatch; foreach ( $pages as $titleText ) { - $batch->addObj( Title::newFromText( $titleText ) ); + $title = Title::newFromText( $titleText ); + if ( $title ) { + // Page name may be invalid if user-provided (e.g. gadgets) + $batch->addObj( $title ); + } } if ( !$batch->isEmpty() ) { $res = $db->select( 'page', @@ -332,7 +337,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { * @since 1.28 * @param ResourceLoaderContext $context * @param IDatabase $db - * @param string[] $modules + * @param string[] $moduleNames */ public static function preloadTitleInfo( ResourceLoaderContext $context, IDatabase $db, array $moduleNames @@ -341,6 +346,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { // getDB() can be overridden to point to a foreign database. // For now, only preload local. In the future, we could preload by wikiID. $allPages = []; + /** @var ResourceLoaderWikiModule[] $wikiModules */ $wikiModules = []; foreach ( $moduleNames as $name ) { $module = $rl->getModule( $name ); @@ -353,16 +359,79 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { } } } - $allInfo = self::fetchTitleInfo( $db, array_keys( $allPages ), __METHOD__ ); - foreach ( $wikiModules as $module ) { - $pages = $module->getPages( $context ); - $info = array_intersect_key( $allInfo, $pages ); + + $pageNames = array_keys( $allPages ); + sort( $pageNames ); + $hash = sha1( implode( '|', $pageNames ) ); + + // Avoid Zend bug where "static::" does not apply LSB in the closure + $func = [ static::class, 'fetchTitleInfo' ]; + $fname = __METHOD__; + + $cache = ObjectCache::getMainWANInstance(); + $allInfo = $cache->getWithSetCallback( + $cache->makeGlobalKey( 'resourceloader', 'titleinfo', $db->getWikiID(), $hash ), + $cache::TTL_HOUR, + function ( $curVal, &$ttl, array &$setOpts ) use ( $func, $pageNames, $db, $fname ) { + $setOpts += Database::getCacheSetOptions( $db ); + + return call_user_func( $func, $db, $pageNames, $fname ); + }, + [ 'checkKeys' => [ $cache->makeGlobalKey( 'resourceloader', 'titleinfo', $db->getWikiID() ) ] ] + ); + + foreach ( $wikiModules as $wikiModule ) { + $pages = $wikiModule->getPages( $context ); + // Before we intersect, map the names to canonical form (T145673). + $intersect = []; + foreach ( $pages as $page => $unused ) { + $title = Title::newFromText( $page ); + if ( $title ) { + $intersect[ $title->getPrefixedText() ] = 1; + } else { + // Page name may be invalid if user-provided (e.g. gadgets) + $rl->getLogger()->info( + 'Invalid wiki page title "{title}" in ' . __METHOD__, + [ 'title' => $page ] + ); + } + } + $info = array_intersect_key( $allInfo, $intersect ); $pageNames = array_keys( $pages ); sort( $pageNames ); $key = implode( '|', $pageNames ); - $module->setTitleInfo( $key, $info ); + $wikiModule->setTitleInfo( $key, $info ); + } + } + + /** + * Clear the preloadTitleInfo() cache for all wiki modules on this wiki on + * page change if it was a JS or CSS page + * + * @param Title $title + * @param Revision|null $old Prior page revision + * @param Revision|null $new New page revision + * @param string $wikiId + * @since 1.28 + */ + public static function invalidateModuleCache( + Title $title, Revision $old = null, Revision $new = null, $wikiId + ) { + static $formats = [ CONTENT_FORMAT_CSS, CONTENT_FORMAT_JAVASCRIPT ]; + + if ( $old && in_array( $old->getContentFormat(), $formats ) ) { + $purge = true; + } elseif ( $new && in_array( $new->getContentFormat(), $formats ) ) { + $purge = true; + } else { + $purge = ( $title->isCssOrJsPage() || $title->isCssJsSubpage() ); + } + + if ( $purge ) { + $cache = ObjectCache::getMainWANInstance(); + $key = $cache->makeGlobalKey( 'resourceloader', 'titleinfo', $wikiId ); + $cache->touchCheckKey( $key ); } - return $allInfo; } /**