mediawiki-extensions-Gadgets/includes/GadgetDefinitionNamespaceRepo.php
Siddharth VP 1f7b9d90df Support JSON files in gadgets
The parsed content of JSON files in the gadget is made available from the
gadget's JS files via require(). That is, MediaWiki:Gadget-data.json (or
Gadget:data.json) is available as `require('./data.json')`. This is
supported for both MediaWikiGadgetsDefinitionRepo and
GadgetDefinitionNamespaceRepo. The JSON parsing is done server-side.

JSON can only be used in "package" gadgets - in which the JS files can
also be invoked via require().

Also added a test for GadgetResourceLoaderModule.

Bug: T198758
Depends-On: Ib4556d09c4d393269e32771aab00f59a5f630e1b
Depends-On: Id4589a597ccfc4266b3e63d10f75b146aa7a287a
Change-Id: I21acb46cdd244a39b5cc6963aa763f0113bd1e38
2021-12-27 17:33:21 +00:00

180 lines
4.1 KiB
PHP

<?php
use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\SlotRecord;
use Wikimedia\Rdbms\Database;
/**
* GadgetRepo implementation where each gadget has a page in
* the Gadget definition namespace, and scripts and styles are
* located in the Gadget namespace.
*/
class GadgetDefinitionNamespaceRepo extends GadgetRepo {
/**
* How long in seconds the list of gadget ids and
* individual gadgets should be cached for (1 day)
*/
private const CACHE_TTL = 86400;
/**
* @var string
*/
protected $titlePrefix = 'Gadget:';
/**
* @var WANObjectCache
*/
private $wanCache;
/**
* @var RevisionLookup
*/
private $revLookup;
public function __construct() {
$services = MediaWikiServices::getInstance();
$this->wanCache = $services->getMainWANObjectCache();
$this->revLookup = $services->getRevisionLookup();
}
/**
* Get a list of gadget ids from cache/database
*
* @return string[]
*/
public function getGadgetIds() {
$key = $this->getGadgetIdsKey();
$fname = __METHOD__;
return $this->wanCache->getWithSetCallback(
$key,
self::CACHE_TTL,
static function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) {
$dbr = wfGetDB( DB_REPLICA );
$setOpts += Database::getCacheSetOptions( $dbr );
return $dbr->selectFieldValues(
'page',
'page_title',
[ 'page_namespace' => NS_GADGET_DEFINITION ],
$fname
);
},
[
'checkKeys' => [ $key ],
'pcTTL' => WANObjectCache::TTL_PROC_SHORT,
'lockTSE' => 30
]
);
}
/**
* @inheritDoc
*/
public function handlePageUpdate( LinkTarget $target ) {
if ( $target->inNamespace( NS_GADGET_DEFINITION ) ) {
$this->purgeGadgetEntry( $target->getText() );
}
}
/**
* @inheritDoc
*/
public function handlePageCreation( LinkTarget $target ) {
if ( $target->inNamespace( NS_GADGET_DEFINITION ) ) {
$this->purgeGadgetIdsList();
}
}
/**
* @inheritDoc
*/
public function handlePageDeletion( LinkTarget $target ) {
if ( $target->inNamespace( NS_GADGET_DEFINITION ) ) {
$this->purgeGadgetIdsList();
$this->purgeGadgetEntry( $target->getText() );
}
}
/**
* Purge the list of gadget ids when a page is deleted or if a new page is created
*/
public function purgeGadgetIdsList() {
$this->wanCache->touchCheckKey( $this->getGadgetIdsKey() );
}
/**
* @param string $id
* @throws InvalidArgumentException
* @return Gadget
*/
public function getGadget( $id ) {
$key = $this->getGadgetCacheKey( $id );
$gadget = $this->wanCache->getWithSetCallback(
$key,
self::CACHE_TTL,
function ( $old, &$ttl, array &$setOpts ) use ( $id ) {
$setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
$title = Title::makeTitleSafe( NS_GADGET_DEFINITION, $id );
if ( !$title ) {
$ttl = WANObjectCache::TTL_UNCACHEABLE;
return null;
}
$revRecord = $this->revLookup->getRevisionByTitle( $title );
if ( !$revRecord ) {
$ttl = WANObjectCache::TTL_UNCACHEABLE;
return null;
}
$content = $revRecord->getContent( SlotRecord::MAIN );
if ( !$content instanceof GadgetDefinitionContent ) {
// Uhm...
$ttl = WANObjectCache::TTL_UNCACHEABLE;
return null;
}
return Gadget::newFromDefinitionContent( $id, $content );
},
[
'checkKeys' => [ $key ],
'pcTTL' => WANObjectCache::TTL_PROC_SHORT,
'lockTSE' => 30
]
);
if ( $gadget === null ) {
throw new InvalidArgumentException( "No gadget registered for '$id'" );
}
return $gadget;
}
/**
* Update the cache for a specific Gadget whenever it is updated
*
* @param string $id
*/
public function purgeGadgetEntry( $id ) {
$this->wanCache->touchCheckKey( $this->getGadgetCacheKey( $id ) );
}
/**
* @return string
*/
private function getGadgetIdsKey() {
return $this->wanCache->makeKey( 'gadgets', 'namespace', 'ids' );
}
/**
* @param string $id
* @return string
*/
private function getGadgetCacheKey( $id ) {
return $this->wanCache->makeKey(
'gadgets', 'object', md5( $id ), Gadget::GADGET_CLASS_VERSION );
}
}