mediawiki-extensions-Cite/CiteHooks.php
cenarium 70e14ebaeb Store references in page_props and cache
This stores references in page_props during links update in
compressed JSON form. If the size is too big, it's broken up
in several parts to fit, which is very unlikely to occur more
than once.

When the data is retrieved from the db, it's always cached. If
set in config, it's also saved in the cache on parse. If not,
the cache is invalidated when references are modified.

Uses cases include : section preview to also show refs defined
elsewhere on the page (T124840) and MobileFrontend (T123328).
For the later, this still needs API support (T123290).

There's a soft dependency on the core change
I0c73b3d181f32502da75687857ae9aeff731f559.

Bug: T125329
Change-Id: I7b106254b8f264f93b0f0c9cfa89f65adeeea4f0
2016-02-10 14:47:02 +01:00

149 lines
4.7 KiB
PHP

<?php
/**
* Cite extension hooks
*
* @file
* @ingroup Extensions
* @copyright 2011-2016 Cite VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see MIT-LICENSE.txt
*/
class CiteHooks {
/**
* Convert the content model of a message that is actually JSON to JSON. This
* only affects validation and UI when saving and editing, not loading the
* content.
*
* @param Title $title
* @param string $model
* @return bool
*/
public static function onContentHandlerDefaultModelFor( Title $title, &$model ) {
if (
$title->inNamespace( NS_MEDIAWIKI ) &&
$title->getText() == 'Visualeditor-cite-tool-definition.json'
) {
$model = CONTENT_MODEL_JSON;
}
return true;
}
/**
* Conditionally register the unit testing module for the ext.cite.visualEditor module
* only if that module is loaded
*
* @param array $testModules The array of registered test modules
* @param ResourceLoader $resourceLoader The reference to the resource loader
* @return true
*/
public static function onResourceLoaderTestModules(
array &$testModules,
ResourceLoader &$resourceLoader
) {
$resourceModules = $resourceLoader->getConfig()->get( 'ResourceModules' );
if (
isset( $resourceModules[ 'ext.cite.visualEditor' ] ) ||
$resourceLoader->isModuleRegistered( 'ext.cite.visualEditor' )
) {
$testModules['qunit']['ext.cite.visualEditor.test'] = array(
'scripts' => array(
'modules/ve-cite/tests/ve.dm.citeExample.js',
'modules/ve-cite/tests/ve.dm.Converter.test.js',
'modules/ve-cite/tests/ve.dm.InternalList.test.js',
'modules/ve-cite/tests/ve.dm.Transaction.test.js',
),
'dependencies' => array(
'ext.cite.visualEditor',
'ext.visualEditor.test'
),
'localBasePath' => __DIR__,
'remoteExtPath' => 'Cite',
);
}
return true;
}
/**
* Callback for LinksUpdateConstructed hook
* If $wgCiteCacheRawReferencesOnParse is set to true, caches the raw references
* in array form
*
* @param LinksUpdate $linksUpdate
*/
public static function onLinksUpdateConstructed( LinksUpdate &$linksUpdate ) {
global $wgCiteStoreReferencesData, $wgCiteCacheRawReferencesOnParse;
if ( !$wgCiteStoreReferencesData || !$wgCiteCacheRawReferencesOnParse ) {
return;
}
$refs = $linksUpdate->getParserOutput()->getExtensionData( Cite::EXT_DATA_KEY );
if ( $refs !== null ) {
$cache = ObjectCache::getMainWANInstance();
$articleID = $linksUpdate->getTitle()->getArticleID();
$key = $cache->makeKey( Cite::EXT_DATA_KEY, $articleID );
$cache->set( $key, $refs, Cite::CACHE_DURATION_ONPARSE );
}
}
/**
* Callback for LinksUpdate hook
* Post-output processing of references property, for proper db storage
* Deferred to avoid performance overhead when outputting the page
*
* @param LinksUpdate $linksUpdate
*/
public static function onLinksUpdate( LinksUpdate &$linksUpdate ) {
global $wgCiteStoreReferencesData;
if ( !$wgCiteStoreReferencesData ) {
return;
}
$refs = $linksUpdate->getParserOutput()->getExtensionData( Cite::EXT_DATA_KEY );
if ( $refs !== null ) {
// JSON encode
$ppValue = FormatJson::encode( $refs, false, FormatJson::ALL_OK );
// GZIP encode references data at maximum compression
$ppValue = gzencode( $ppValue, 9 );
// split the string in smaller parts that can fit into a db blob
$ppValues = str_split( $ppValue, Cite::MAX_STORAGE_LENGTH );
foreach ( $ppValues as $num => $ppValue ) {
$key = 'references-' . intval( $num + 1 );
$linksUpdate->mProperties[$key] = $ppValue;
}
$linksUpdate->getParserOutput()->setExtensionData( Cite::EXT_DATA_KEY, null );
}
}
/**
* Callback for LinksUpdateComplete hook
* If $wgCiteCacheRawReferencesOnParse is set to false, purges the cache
* when references are modified
*
* @param LinksUpdate $linksUpdate
*/
public static function onLinksUpdateComplete( LinksUpdate &$linksUpdate ) {
global $wgCiteStoreReferencesData, $wgCiteCacheRawReferencesOnParse;
if ( !$wgCiteStoreReferencesData || $wgCiteCacheRawReferencesOnParse ) {
return;
}
// if we can, avoid clearing the cache when references were not changed
if ( method_exists( $linksUpdate, 'getAddedProperties' )
&& method_exists( $linksUpdate, 'getRemovedProperties' )
) {
$addedProps = $linksUpdate->getAddedProperties();
$removedProps = $linksUpdate->getRemovedProperties();
if ( !isset( $addedProps['references-1'] )
&& !isset( $removedProps['references-1'] )
) {
return;
}
}
$cache = ObjectCache::getMainWANInstance();
$articleID = $linksUpdate->getTitle()->getArticleID();
$key = $cache->makeKey( Cite::EXT_DATA_KEY, $articleID );
// delete with reduced hold off period (LinksUpdate uses a master connection)
$cache->delete( $key, WANObjectCache::MAX_COMMIT_DELAY );
}
}