mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Math
synced 2024-09-23 10:21:31 +00:00
Remove explicit DB access
* Uses BagOfStuff caching instead of custom-made DB cache * By configuring the BagOfStuff cache in a way that it writes to the database no performance implications are expected * For WMF-use this should have no effect since restbase is used to cache stuff * Replaces Ib2c216f54e6817ee2c3be0355ba72bd4769ba6ea Bug: T349442 Change-Id: I1ce8ad9cf4c1a9ae71f447e4e067b39ee2601640
This commit is contained in:
parent
7f8a359a84
commit
9236575a1a
|
@ -38,7 +38,8 @@ return [
|
||||||
),
|
),
|
||||||
Math::getMathConfig( $services ),
|
Math::getMathConfig( $services ),
|
||||||
$services->getUserOptionsLookup(),
|
$services->getUserOptionsLookup(),
|
||||||
LoggerFactory::getInstance( 'Math' )
|
LoggerFactory::getInstance( 'Math' ),
|
||||||
|
$services->getMainWANObjectCache()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'Math.WikibaseConnector' => static function ( MediaWikiServices $services ): MathWikibaseConnector {
|
'Math.WikibaseConnector' => static function ( MediaWikiServices $services ): MathWikibaseConnector {
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "mathlatexml",
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "math_inputhash",
|
|
||||||
"type": "binary",
|
|
||||||
"options": {
|
|
||||||
"notnull": true,
|
|
||||||
"length": 16,
|
|
||||||
"fixed": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_inputtex",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": true,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_tex",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_mathml",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 16777215
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_svg",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_style",
|
|
||||||
"type": "mwtinyint",
|
|
||||||
"options": {
|
|
||||||
"notnull": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"indexes": [],
|
|
||||||
"pk": [
|
|
||||||
"math_inputhash"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,74 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "mathoid",
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "math_inputhash",
|
|
||||||
"type": "binary",
|
|
||||||
"options": {
|
|
||||||
"notnull": true,
|
|
||||||
"length": 16,
|
|
||||||
"fixed": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_input",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": true,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_tex",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_mathml",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_svg",
|
|
||||||
"type": "text",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 65535
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_style",
|
|
||||||
"type": "mwtinyint",
|
|
||||||
"options": {
|
|
||||||
"notnull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_input_type",
|
|
||||||
"type": "mwtinyint",
|
|
||||||
"options": {
|
|
||||||
"notnull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "math_png",
|
|
||||||
"type": "blob",
|
|
||||||
"options": {
|
|
||||||
"notnull": false,
|
|
||||||
"length": 16777215
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"indexes": [],
|
|
||||||
"pk": [
|
|
||||||
"math_inputhash"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,13 +0,0 @@
|
||||||
-- This file is automatically generated using maintenance/generateSchemaSql.php.
|
|
||||||
-- Source: Math/sql/mathlatexml.json
|
|
||||||
-- Do not modify this file directly.
|
|
||||||
-- See https://www.mediawiki.org/wiki/Manual:Schema_changes
|
|
||||||
CREATE TABLE /*_*/mathlatexml (
|
|
||||||
math_inputhash VARBINARY(16) NOT NULL,
|
|
||||||
math_inputtex TEXT NOT NULL,
|
|
||||||
math_tex TEXT DEFAULT NULL,
|
|
||||||
math_mathml MEDIUMTEXT DEFAULT NULL,
|
|
||||||
math_svg TEXT DEFAULT NULL,
|
|
||||||
math_style TINYINT DEFAULT NULL,
|
|
||||||
PRIMARY KEY(math_inputhash)
|
|
||||||
) /*$wgDBTableOptions*/;
|
|
|
@ -1,15 +0,0 @@
|
||||||
-- This file is automatically generated using maintenance/generateSchemaSql.php.
|
|
||||||
-- Source: Math/sql/mathoid.json
|
|
||||||
-- Do not modify this file directly.
|
|
||||||
-- See https://www.mediawiki.org/wiki/Manual:Schema_changes
|
|
||||||
CREATE TABLE /*_*/mathoid (
|
|
||||||
math_inputhash VARBINARY(16) NOT NULL,
|
|
||||||
math_input TEXT NOT NULL,
|
|
||||||
math_tex TEXT DEFAULT NULL,
|
|
||||||
math_mathml TEXT DEFAULT NULL,
|
|
||||||
math_svg TEXT DEFAULT NULL,
|
|
||||||
math_style TINYINT DEFAULT NULL,
|
|
||||||
math_input_type TINYINT DEFAULT NULL,
|
|
||||||
math_png MEDIUMBLOB DEFAULT NULL,
|
|
||||||
PRIMARY KEY(math_inputhash)
|
|
||||||
) /*$wgDBTableOptions*/;
|
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE /*_*/mathoid ADD math_png mediumblob;
|
|
|
@ -1,13 +0,0 @@
|
||||||
-- This file is automatically generated using maintenance/generateSchemaSql.php.
|
|
||||||
-- Source: Math/sql/mathlatexml.json
|
|
||||||
-- Do not modify this file directly.
|
|
||||||
-- See https://www.mediawiki.org/wiki/Manual:Schema_changes
|
|
||||||
CREATE TABLE mathlatexml (
|
|
||||||
math_inputhash TEXT NOT NULL,
|
|
||||||
math_inputtex TEXT NOT NULL,
|
|
||||||
math_tex TEXT DEFAULT NULL,
|
|
||||||
math_mathml TEXT DEFAULT NULL,
|
|
||||||
math_svg TEXT DEFAULT NULL,
|
|
||||||
math_style SMALLINT DEFAULT NULL,
|
|
||||||
PRIMARY KEY(math_inputhash)
|
|
||||||
);
|
|
|
@ -1,15 +0,0 @@
|
||||||
-- This file is automatically generated using maintenance/generateSchemaSql.php.
|
|
||||||
-- Source: Math/sql/mathoid.json
|
|
||||||
-- Do not modify this file directly.
|
|
||||||
-- See https://www.mediawiki.org/wiki/Manual:Schema_changes
|
|
||||||
CREATE TABLE mathoid (
|
|
||||||
math_inputhash TEXT NOT NULL,
|
|
||||||
math_input TEXT NOT NULL,
|
|
||||||
math_tex TEXT DEFAULT NULL,
|
|
||||||
math_mathml TEXT DEFAULT NULL,
|
|
||||||
math_svg TEXT DEFAULT NULL,
|
|
||||||
math_style SMALLINT DEFAULT NULL,
|
|
||||||
math_input_type SMALLINT DEFAULT NULL,
|
|
||||||
math_png TEXT DEFAULT NULL,
|
|
||||||
PRIMARY KEY(math_inputhash)
|
|
||||||
);
|
|
|
@ -1,13 +0,0 @@
|
||||||
-- This file is automatically generated using maintenance/generateSchemaSql.php.
|
|
||||||
-- Source: Math/sql/mathlatexml.json
|
|
||||||
-- Do not modify this file directly.
|
|
||||||
-- See https://www.mediawiki.org/wiki/Manual:Schema_changes
|
|
||||||
CREATE TABLE /*_*/mathlatexml (
|
|
||||||
math_inputhash BLOB NOT NULL,
|
|
||||||
math_inputtex CLOB NOT NULL,
|
|
||||||
math_tex CLOB DEFAULT NULL,
|
|
||||||
math_mathml CLOB DEFAULT NULL,
|
|
||||||
math_svg CLOB DEFAULT NULL,
|
|
||||||
math_style SMALLINT DEFAULT NULL,
|
|
||||||
PRIMARY KEY(math_inputhash)
|
|
||||||
);
|
|
|
@ -1,15 +0,0 @@
|
||||||
-- This file is automatically generated using maintenance/generateSchemaSql.php.
|
|
||||||
-- Source: Math/sql/mathoid.json
|
|
||||||
-- Do not modify this file directly.
|
|
||||||
-- See https://www.mediawiki.org/wiki/Manual:Schema_changes
|
|
||||||
CREATE TABLE /*_*/mathoid (
|
|
||||||
math_inputhash BLOB NOT NULL,
|
|
||||||
math_input CLOB NOT NULL,
|
|
||||||
math_tex CLOB DEFAULT NULL,
|
|
||||||
math_mathml CLOB DEFAULT NULL,
|
|
||||||
math_svg CLOB DEFAULT NULL,
|
|
||||||
math_style SMALLINT DEFAULT NULL,
|
|
||||||
math_input_type SMALLINT DEFAULT NULL,
|
|
||||||
math_png BLOB DEFAULT NULL,
|
|
||||||
PRIMARY KEY(math_inputhash)
|
|
||||||
);
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace MediaWiki\Extension\Math\HookHandlers;
|
namespace MediaWiki\Extension\Math\HookHandlers;
|
||||||
|
|
||||||
use DatabaseUpdater;
|
use DatabaseUpdater;
|
||||||
use LogicException;
|
|
||||||
use MediaWiki\Installer\Hook\LoadExtensionSchemaUpdatesHook;
|
use MediaWiki\Installer\Hook\LoadExtensionSchemaUpdatesHook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,22 +18,11 @@ class SchemaHooksHandler implements LoadExtensionSchemaUpdatesHook {
|
||||||
public function onLoadExtensionSchemaUpdates( $updater ) {
|
public function onLoadExtensionSchemaUpdates( $updater ) {
|
||||||
$type = $updater->getDB()->getType();
|
$type = $updater->getDB()->getType();
|
||||||
if ( !in_array( $type, [ 'mysql', 'sqlite', 'postgres' ], true ) ) {
|
if ( !in_array( $type, [ 'mysql', 'sqlite', 'postgres' ], true ) ) {
|
||||||
throw new LogicException( "Math extension does not currently support $type database." );
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( [ 'mathoid', 'mathlatexml' ] as $mode ) {
|
foreach ( [ 'mathoid', 'mathlatexml' ] as $mode ) {
|
||||||
$updater->addExtensionTable(
|
$updater->dropExtensionTable( $mode );
|
||||||
$mode,
|
|
||||||
__DIR__ . "/../../sql/$type/$mode.sql"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $type === 'mysql' ) {
|
|
||||||
$updater->addExtensionField(
|
|
||||||
'mathoid',
|
|
||||||
'math_png',
|
|
||||||
__DIR__ . '/../../sql/' . $type . '/patch-mathoid.add_png.sql'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ class MathLaTeXML extends MathMathML {
|
||||||
/** @var string settings for LaTeXML daemon */
|
/** @var string settings for LaTeXML daemon */
|
||||||
private $LaTeXMLSettings = '';
|
private $LaTeXMLSettings = '';
|
||||||
|
|
||||||
public function __construct( $tex = '', $params = [] ) {
|
public function __construct( $tex = '', $params = [], $cache = null ) {
|
||||||
global $wgMathLaTeXMLUrl;
|
global $wgMathLaTeXMLUrl;
|
||||||
parent::__construct( $tex, $params );
|
parent::__construct( $tex, $params, $cache );
|
||||||
$this->host = $wgMathLaTeXMLUrl;
|
$this->host = $wgMathLaTeXMLUrl;
|
||||||
$this->setMode( MathConfig::MODE_LATEXML );
|
$this->setMode( MathConfig::MODE_LATEXML );
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,9 @@ class MathMathML extends MathRenderer {
|
||||||
/** @var string|null */
|
/** @var string|null */
|
||||||
private $mathoidStyle;
|
private $mathoidStyle;
|
||||||
|
|
||||||
public function __construct( string $tex = '', array $params = [] ) {
|
public function __construct( string $tex = '', array $params = [], $cache = null ) {
|
||||||
global $wgMathMathMLUrl;
|
global $wgMathMathMLUrl;
|
||||||
parent::__construct( $tex, $params );
|
parent::__construct( $tex, $params, $cache );
|
||||||
$this->setMode( MathConfig::MODE_MATHML );
|
$this->setMode( MathConfig::MODE_MATHML );
|
||||||
$this->host = $wgMathMathMLUrl;
|
$this->host = $wgMathMathMLUrl;
|
||||||
if ( isset( $params['type'] ) ) {
|
if ( isset( $params['type'] ) ) {
|
||||||
|
@ -354,7 +354,7 @@ class MathMathML extends MathRenderer {
|
||||||
return $this->svgPath;
|
return $this->svgPath;
|
||||||
}
|
}
|
||||||
return SpecialPage::getTitleFor( 'MathShowImage' )->getLocalURL( [
|
return SpecialPage::getTitleFor( 'MathShowImage' )->getLocalURL( [
|
||||||
'hash' => $this->getMd5(),
|
'hash' => $this->getInputHash(),
|
||||||
'mode' => $this->getMode(),
|
'mode' => $this->getMode(),
|
||||||
'noRender' => $noRender
|
'noRender' => $noRender
|
||||||
]
|
]
|
||||||
|
@ -493,7 +493,7 @@ class MathMathML extends MathRenderer {
|
||||||
|
|
||||||
protected function dbOutArray() {
|
protected function dbOutArray() {
|
||||||
$out = parent::dbOutArray();
|
$out = parent::dbOutArray();
|
||||||
if ( $this->getMathTableName() == 'mathoid' ) {
|
if ( $this->getMathTableName() === 'mathoid' ) {
|
||||||
$out['math_input'] = $out['math_inputtex'];
|
$out['math_input'] = $out['math_inputtex'];
|
||||||
unset( $out['math_inputtex'] );
|
unset( $out['math_inputtex'] );
|
||||||
}
|
}
|
||||||
|
@ -502,20 +502,20 @@ class MathMathML extends MathRenderer {
|
||||||
|
|
||||||
protected function dbInArray() {
|
protected function dbInArray() {
|
||||||
$out = parent::dbInArray();
|
$out = parent::dbInArray();
|
||||||
if ( $this->getMathTableName() == 'mathoid' ) {
|
if ( $this->getMathTableName() === 'mathoid' ) {
|
||||||
$out = array_diff( $out, [ 'math_inputtex' ] );
|
$out = array_diff( $out, [ 'math_inputtex' ] );
|
||||||
$out[] = 'math_input';
|
$out[] = 'math_input';
|
||||||
}
|
}
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function initializeFromDatabaseRow( $rpage ) {
|
public function initializeFromCache( $rpage ) {
|
||||||
// mathoid allows different input formats
|
// mathoid allows different input formats
|
||||||
// therefore the column name math_inputtex was changed to math_input
|
// therefore the column name math_inputtex was changed to math_input
|
||||||
if ( $this->getMathTableName() == 'mathoid' && !empty( $rpage->math_input ) ) {
|
if ( $this->getMathTableName() === 'mathoid' && isset( $rpage['math_input'] ) ) {
|
||||||
$this->userInputTex = $rpage->math_input;
|
$this->userInputTex = $rpage['math_input'];
|
||||||
}
|
}
|
||||||
parent::initializeFromDatabaseRow( $rpage );
|
parent::initializeFromCache( $rpage );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -48,7 +48,7 @@ class MathMathMLCli extends MathMathML {
|
||||||
*/
|
*/
|
||||||
private function initializeFromCliResponse( $res ) {
|
private function initializeFromCliResponse( $res ) {
|
||||||
global $wgMathoidCli;
|
global $wgMathoidCli;
|
||||||
if ( !property_exists( $res, $this->getMd5() ) ) {
|
if ( !property_exists( $res, $this->getInputHash() ) ) {
|
||||||
$this->lastError =
|
$this->lastError =
|
||||||
$this->getError( 'math_mathoid_error', 'cli',
|
$this->getError( 'math_mathoid_error', 'cli',
|
||||||
var_export( get_object_vars( $res ), true ) );
|
var_export( get_object_vars( $res ), true ) );
|
||||||
|
@ -58,7 +58,7 @@ class MathMathMLCli extends MathMathML {
|
||||||
$this->lastError = $this->getError( 'math_empty_tex' );
|
$this->lastError = $this->getError( 'math_empty_tex' );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$response = $res->{$this->getMd5()};
|
$response = $res->{$this->getInputHash()};
|
||||||
if ( !$response->success ) {
|
if ( !$response->success ) {
|
||||||
$this->lastError = $this->renderError( $response );
|
$this->lastError = $this->renderError( $response );
|
||||||
return false;
|
return false;
|
||||||
|
@ -103,7 +103,7 @@ class MathMathMLCli extends MathMathML {
|
||||||
'query' => [
|
'query' => [
|
||||||
'q' => $this->getTex(),
|
'q' => $this->getTex(),
|
||||||
'type' => $this->getInputType(),
|
'type' => $this->getInputType(),
|
||||||
'hash' => $this->getMd5(),
|
'hash' => $this->getInputHash(),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ use StatusValue;
|
||||||
class MathNativeMML extends MathMathML {
|
class MathNativeMML extends MathMathML {
|
||||||
private LocalChecker $checker;
|
private LocalChecker $checker;
|
||||||
|
|
||||||
public function __construct( $tex = '', $params = [] ) {
|
public function __construct( $tex = '', $params = [], $cache = null ) {
|
||||||
parent::__construct( $tex, $params );
|
parent::__construct( $tex, $params, $cache );
|
||||||
$this->setMode( MathConfig::MODE_NATIVE_MML );
|
$this->setMode( MathConfig::MODE_NATIVE_MML );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class MathNativeMML extends MathMathML {
|
||||||
return $this->getMathml();
|
return $this->getMathml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readFromDatabase() {
|
public function readFromCache(): bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
namespace MediaWiki\Extension\Math;
|
namespace MediaWiki\Extension\Math;
|
||||||
|
|
||||||
use MediaWiki\Deferred\DeferredUpdates;
|
|
||||||
use MediaWiki\Extension\Math\InputCheck\BaseChecker;
|
use MediaWiki\Extension\Math\InputCheck\BaseChecker;
|
||||||
use MediaWiki\Logger\LoggerFactory;
|
use MediaWiki\Logger\LoggerFactory;
|
||||||
use MediaWiki\MediaWikiServices;
|
use MediaWiki\MediaWikiServices;
|
||||||
|
@ -20,14 +19,14 @@ use Message;
|
||||||
use Parser;
|
use Parser;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use RequestContext;
|
use RequestContext;
|
||||||
use stdClass;
|
|
||||||
use StringUtils;
|
use StringUtils;
|
||||||
|
use WANObjectCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class with static methods for rendering the <math> tags using
|
* Abstract base class with static methods for rendering the <math> tags using
|
||||||
* different technologies. These static methods create a new instance of the
|
* different technologies. These static methods create a new instance of the
|
||||||
* extending classes and render the math tags based on the mode setting of the user.
|
* extending classes and render the math tags based on the mode setting of the user.
|
||||||
* Furthermore this class handles the caching of the rendered output.
|
* Furthermore, this class handles the caching of the rendered output.
|
||||||
*
|
*
|
||||||
* @author Tomasz Wegrzanowski
|
* @author Tomasz Wegrzanowski
|
||||||
* @author Brion Vibber
|
* @author Brion Vibber
|
||||||
|
@ -58,13 +57,11 @@ abstract class MathRenderer {
|
||||||
/** @var bool has the mathematical content changed */
|
/** @var bool has the mathematical content changed */
|
||||||
protected $changed = false;
|
protected $changed = false;
|
||||||
/** @var bool is there a database entry for the mathematical content */
|
/** @var bool is there a database entry for the mathematical content */
|
||||||
protected $storedInDatabase = null;
|
protected $storedInCache = null;
|
||||||
/** @var bool is there a request to purge the existing mathematical content */
|
/** @var bool is there a request to purge the existing mathematical content */
|
||||||
protected $purge = false;
|
protected $purge = false;
|
||||||
/** @var string with last occurred error */
|
/** @var string with last occurred error */
|
||||||
protected $lastError = '';
|
protected $lastError = '';
|
||||||
/** @var string md5 value from userInputTex */
|
|
||||||
protected $md5 = '';
|
|
||||||
/** @var string binary packed inputhash */
|
/** @var string binary packed inputhash */
|
||||||
protected $inputHash = '';
|
protected $inputHash = '';
|
||||||
/** @var string rendering mode */
|
/** @var string rendering mode */
|
||||||
|
@ -78,13 +75,17 @@ abstract class MathRenderer {
|
||||||
/** @var LoggerInterface */
|
/** @var LoggerInterface */
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
|
private WANObjectCache $cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a base MathRenderer
|
* Constructs a base MathRenderer
|
||||||
*
|
*
|
||||||
* @param string $tex (optional) LaTeX markup
|
* @param string $tex (optional) LaTeX markup
|
||||||
* @param array $params (optional) HTML attributes
|
* @param array $params (optional) HTML attributes
|
||||||
|
* @param WANObjectCache|null $cache (optional)
|
||||||
*/
|
*/
|
||||||
public function __construct( $tex = '', $params = [] ) {
|
public function __construct( string $tex = '', $params = [], $cache = null ) {
|
||||||
|
$this->cache = $cache ?? MediaWikiServices::getInstance()->getMainWANObjectCache();
|
||||||
$this->params = $params;
|
$this->params = $params;
|
||||||
if ( isset( $params['id'] ) ) {
|
if ( isset( $params['id'] ) ) {
|
||||||
$this->id = $params['id'];
|
$this->id = $params['id'];
|
||||||
|
@ -119,18 +120,6 @@ abstract class MathRenderer {
|
||||||
$this->logger = LoggerFactory::getInstance( 'Math' );
|
$this->logger = LoggerFactory::getInstance( 'Math' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $md5
|
|
||||||
* @return self the MathRenderer generated from md5
|
|
||||||
*/
|
|
||||||
public static function newFromMd5( $md5 ) {
|
|
||||||
// @phan-suppress-next-line PhanTypeInstantiateAbstractStatic
|
|
||||||
$instance = new static();
|
|
||||||
$instance->setMd5( $md5 );
|
|
||||||
$instance->readFromDatabase();
|
|
||||||
return $instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static factory method for getting a renderer based on mode
|
* Static factory method for getting a renderer based on mode
|
||||||
*
|
*
|
||||||
|
@ -181,64 +170,31 @@ abstract class MathRenderer {
|
||||||
*
|
*
|
||||||
* @return string hash
|
* @return string hash
|
||||||
*/
|
*/
|
||||||
public function getMd5() {
|
public function getInputHash(): string {
|
||||||
if ( !$this->md5 ) {
|
|
||||||
$this->md5 = md5( $this->userInputTex );
|
|
||||||
}
|
|
||||||
return $this->md5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the input hash (if user input tex is not available)
|
|
||||||
* @param string $md5
|
|
||||||
*/
|
|
||||||
public function setMd5( $md5 ) {
|
|
||||||
$this->md5 = $md5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return hash of input
|
|
||||||
*
|
|
||||||
* @return string hash
|
|
||||||
*/
|
|
||||||
public function getInputHash() {
|
|
||||||
// TODO: What happens if $tex is empty?
|
|
||||||
if ( !$this->inputHash ) {
|
if ( !$this->inputHash ) {
|
||||||
$dbr = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->getReplicaDatabase();
|
$this->inputHash = hash( 'md5', // xxh128 might be better when dropping php 7 support
|
||||||
return $dbr->encodeBlob( pack( "H32", $this->getMd5() ) ); # Binary packed, not hex
|
$this->mode .
|
||||||
|
$this->userInputTex .
|
||||||
|
implode( $this->params )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return $this->inputHash;
|
return $this->inputHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode binary packed hash from the database to md5 of input_tex
|
|
||||||
* @param string $hash (binary)
|
|
||||||
* @return string md5
|
|
||||||
*/
|
|
||||||
private static function dbHash2md5( $hash ) {
|
|
||||||
$dbr = wfGetDB( DB_REPLICA );
|
|
||||||
$xhash = unpack( 'H32md5', $dbr->decodeBlob( $hash ) . " " );
|
|
||||||
return $xhash['md5'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads rendering data from database
|
* Reads rendering data from database
|
||||||
*
|
*
|
||||||
* @return bool true if read successfully, false otherwise
|
* @return bool true if read successfully, false otherwise
|
||||||
*/
|
*/
|
||||||
public function readFromDatabase() {
|
public function readFromCache(): bool {
|
||||||
$dbr = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->getReplicaDatabase();
|
$rpage = $this->cache->get( $this->getCacheKey() );
|
||||||
$rpage = $dbr->selectRow( $this->getMathTableName(),
|
|
||||||
$this->dbInArray(),
|
|
||||||
[ 'math_inputhash' => $this->getInputHash() ],
|
|
||||||
__METHOD__ );
|
|
||||||
if ( $rpage !== false ) {
|
if ( $rpage !== false ) {
|
||||||
$this->initializeFromDatabaseRow( $rpage );
|
$this->initializeFromCache( $rpage );
|
||||||
$this->storedInDatabase = true;
|
$this->storedInCache = true;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
# Missing from the database and/or the render cache
|
# Missing from the database and/or the render cache
|
||||||
$this->storedInDatabase = false;
|
$this->storedInCache = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,82 +214,38 @@ abstract class MathRenderer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the values from the database but does not overwrite set values with empty values
|
* Reads the values from the database but does not overwrite set values with empty values
|
||||||
* @param stdClass $rpage (a database row)
|
* @param array $rpage (a database row)
|
||||||
*/
|
*/
|
||||||
protected function initializeFromDatabaseRow( $rpage ) {
|
public function initializeFromCache( $rpage ) {
|
||||||
$this->inputHash = $rpage->math_inputhash; // MUST NOT BE NULL
|
$this->inputHash = $rpage['math_inputhash']; // MUST NOT BE NULL
|
||||||
$this->md5 = self::dbHash2md5( $this->inputHash );
|
if ( isset( $rpage['math_mathml'] ) ) {
|
||||||
if ( !empty( $rpage->math_mathml ) ) {
|
$this->mathml = $rpage['math_mathml'];
|
||||||
$this->mathml = $rpage->math_mathml;
|
|
||||||
}
|
}
|
||||||
if ( !empty( $rpage->math_inputtex ) ) {
|
if ( isset( $rpage['math_inputtex'] ) ) {
|
||||||
// in the current database the field is probably not set.
|
$this->userInputTex = $rpage['math_inputtex'];
|
||||||
$this->userInputTex = $rpage->math_inputtex;
|
|
||||||
}
|
}
|
||||||
if ( !empty( $rpage->math_tex ) ) {
|
if ( isset( $rpage['math_tex'] ) ) {
|
||||||
$this->tex = $rpage->math_tex;
|
$this->tex = $rpage['math_tex'];
|
||||||
}
|
}
|
||||||
if ( !empty( $rpage->math_svg ) ) {
|
if ( isset( $rpage['math_svg'] ) ) {
|
||||||
$this->svg = $rpage->math_svg;
|
$this->svg = $rpage['math_svg'];
|
||||||
}
|
}
|
||||||
$this->changed = false;
|
$this->changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes rendering entry to database.
|
* Writes rendering entry to cache.
|
||||||
*
|
*
|
||||||
* WARNING: Use writeCache() instead of this method to be sure that all
|
* WARNING: Use writeCache() instead of this method to be sure that all
|
||||||
* renderer specific (such as squid caching) are taken into account.
|
* renderer specific (such as squid caching) are taken into account.
|
||||||
* This function stores the values that are currently present in the class
|
* This function stores the values that are currently present in the class
|
||||||
* to the database even if they are empty.
|
* to the cache even if they are empty.
|
||||||
*
|
*
|
||||||
* This function can be seen as protected function.
|
* This function can be seen as protected function.
|
||||||
* @param \Wikimedia\Rdbms\IDatabase|null $dbw
|
|
||||||
*/
|
*/
|
||||||
public function writeToDatabase( $dbw = null ) {
|
public function writeToCache() {
|
||||||
# Now save it back to the DB:
|
|
||||||
if ( MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$outArray = $this->dbOutArray();
|
$outArray = $this->dbOutArray();
|
||||||
$mathTableName = $this->getMathTableName();
|
$this->cache->set( $this->getCacheKey(), $outArray );
|
||||||
$fname = __METHOD__;
|
|
||||||
if ( $this->isInDatabase() ) {
|
|
||||||
$this->debug( 'Update database entry' );
|
|
||||||
$inputHash = $this->getInputHash();
|
|
||||||
DeferredUpdates::addCallableUpdate( function () use (
|
|
||||||
$dbw, $outArray, $inputHash, $mathTableName, $fname
|
|
||||||
) {
|
|
||||||
$dbw = $dbw ?: wfGetDB( DB_PRIMARY );
|
|
||||||
|
|
||||||
$dbw->update( $mathTableName, $outArray,
|
|
||||||
[ 'math_inputhash' => $inputHash ], $fname );
|
|
||||||
$this->logger->debug(
|
|
||||||
'Row updated after db transaction was idle: ' .
|
|
||||||
var_export( $outArray, true ) . " to database" );
|
|
||||||
} );
|
|
||||||
} else {
|
|
||||||
$this->storedInDatabase = true;
|
|
||||||
$this->debug( 'Store new entry in database' );
|
|
||||||
DeferredUpdates::addCallableUpdate( function () use (
|
|
||||||
$dbw, $outArray, $mathTableName, $fname
|
|
||||||
) {
|
|
||||||
$dbw = $dbw ?: wfGetDB( DB_PRIMARY );
|
|
||||||
|
|
||||||
$dbw->insert( $mathTableName, $outArray, $fname, [ 'IGNORE' ] );
|
|
||||||
LoggerFactory::getInstance( 'Math' )->debug(
|
|
||||||
'Row inserted after db transaction was idle {out}.',
|
|
||||||
[
|
|
||||||
'out' => var_export( $outArray, true ),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
if ( $dbw->affectedRows() == 0 ) {
|
|
||||||
// That's the price for the delayed update.
|
|
||||||
$this->logger->warning(
|
|
||||||
'Entry could not be written. Might be changed in between.' );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -346,7 +258,8 @@ abstract class MathRenderer {
|
||||||
'math_mathml' => $this->mathml,
|
'math_mathml' => $this->mathml,
|
||||||
'math_inputtex' => $this->userInputTex,
|
'math_inputtex' => $this->userInputTex,
|
||||||
'math_tex' => $this->tex,
|
'math_tex' => $this->tex,
|
||||||
'math_svg' => $this->svg
|
'math_svg' => $this->svg,
|
||||||
|
'math_mode' => $this->mode
|
||||||
];
|
];
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
@ -409,7 +322,7 @@ abstract class MathRenderer {
|
||||||
$this->debug( 'Writing of cache requested' );
|
$this->debug( 'Writing of cache requested' );
|
||||||
if ( $this->isChanged() ) {
|
if ( $this->isChanged() ) {
|
||||||
$this->debug( 'Change detected. Perform writing' );
|
$this->debug( 'Change detected. Perform writing' );
|
||||||
$this->writeToDatabase();
|
$this->writeToCache();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
$this->debug( "Nothing was changed. Don't write to database" );
|
$this->debug( "Nothing was changed. Don't write to database" );
|
||||||
|
@ -591,7 +504,7 @@ abstract class MathRenderer {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if ( $texCheckDisabled === MathConfig::NEW && $this->mode != MathConfig::MODE_SOURCE ) {
|
if ( $texCheckDisabled === MathConfig::NEW && $this->mode != MathConfig::MODE_SOURCE ) {
|
||||||
if ( $this->readFromDatabase() ) {
|
if ( $this->readFromCache() ) {
|
||||||
$this->debug( 'Skip TeX check' );
|
$this->debug( 'Skip TeX check' );
|
||||||
$this->texSecure = true;
|
$this->texSecure = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -603,10 +516,10 @@ abstract class MathRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isInDatabase() {
|
public function isInDatabase() {
|
||||||
if ( $this->storedInDatabase === null ) {
|
if ( $this->storedInCache === null ) {
|
||||||
$this->readFromDatabase();
|
$this->readFromCache();
|
||||||
}
|
}
|
||||||
return $this->storedInDatabase;
|
return $this->storedInCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -697,4 +610,11 @@ abstract class MathRenderer {
|
||||||
protected function debug( $msg ) {
|
protected function debug( $msg ) {
|
||||||
$this->logger->debug( "$msg for \"{tex}\".", [ 'tex' => $this->userInputTex ] );
|
$this->logger->debug( "$msg for \"{tex}\".", [ 'tex' => $this->userInputTex ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getCacheKey() {
|
||||||
|
return $this->cache->makeGlobalKey(
|
||||||
|
self::class,
|
||||||
|
$this->getInputHash()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace MediaWiki\Extension\Math\Render;
|
namespace MediaWiki\Extension\Math\Render;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
use MediaWiki\Config\ServiceOptions;
|
use MediaWiki\Config\ServiceOptions;
|
||||||
use MediaWiki\Extension\Math\MathConfig;
|
use MediaWiki\Extension\Math\MathConfig;
|
||||||
use MediaWiki\Extension\Math\MathLaTeXML;
|
use MediaWiki\Extension\Math\MathLaTeXML;
|
||||||
|
@ -12,6 +13,7 @@ use MediaWiki\Extension\Math\MathRenderer;
|
||||||
use MediaWiki\Extension\Math\MathSource;
|
use MediaWiki\Extension\Math\MathSource;
|
||||||
use MediaWiki\User\Options\UserOptionsLookup;
|
use MediaWiki\User\Options\UserOptionsLookup;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use WANObjectCache;
|
||||||
|
|
||||||
class RendererFactory {
|
class RendererFactory {
|
||||||
|
|
||||||
|
@ -34,23 +36,28 @@ class RendererFactory {
|
||||||
/** @var LoggerInterface */
|
/** @var LoggerInterface */
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
|
private WANObjectCache $cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServiceOptions $serviceOptions
|
* @param ServiceOptions $serviceOptions
|
||||||
* @param MathConfig $mathConfig
|
* @param MathConfig $mathConfig
|
||||||
* @param UserOptionsLookup $userOptionsLookup
|
* @param UserOptionsLookup $userOptionsLookup
|
||||||
* @param LoggerInterface $logger
|
* @param LoggerInterface $logger
|
||||||
|
* @param WANObjectCache $cache
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ServiceOptions $serviceOptions,
|
ServiceOptions $serviceOptions,
|
||||||
MathConfig $mathConfig,
|
MathConfig $mathConfig,
|
||||||
UserOptionsLookup $userOptionsLookup,
|
UserOptionsLookup $userOptionsLookup,
|
||||||
LoggerInterface $logger
|
LoggerInterface $logger,
|
||||||
|
WANObjectCache $cache
|
||||||
) {
|
) {
|
||||||
$serviceOptions->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
$serviceOptions->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||||
$this->options = $serviceOptions;
|
$this->options = $serviceOptions;
|
||||||
$this->mathConfig = $mathConfig;
|
$this->mathConfig = $mathConfig;
|
||||||
$this->userOptionsLookup = $userOptionsLookup;
|
$this->userOptionsLookup = $userOptionsLookup;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
$this->cache = $cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,17 +98,17 @@ class RendererFactory {
|
||||||
$renderer = new MathSource( $tex, $params );
|
$renderer = new MathSource( $tex, $params );
|
||||||
break;
|
break;
|
||||||
case MathConfig::MODE_NATIVE_MML:
|
case MathConfig::MODE_NATIVE_MML:
|
||||||
$renderer = new MathNativeMML( $tex, $params );
|
$renderer = new MathNativeMML( $tex, $params, $this->cache );
|
||||||
break;
|
break;
|
||||||
case MathConfig::MODE_LATEXML:
|
case MathConfig::MODE_LATEXML:
|
||||||
$renderer = new MathLaTeXML( $tex, $params );
|
$renderer = new MathLaTeXML( $tex, $params, $this->cache );
|
||||||
break;
|
break;
|
||||||
case MathConfig::MODE_MATHML:
|
case MathConfig::MODE_MATHML:
|
||||||
default:
|
default:
|
||||||
if ( $this->options->get( 'MathoidCli' ) ) {
|
if ( $this->options->get( 'MathoidCli' ) ) {
|
||||||
$renderer = new MathMathMLCli( $tex, $params );
|
$renderer = new MathMathMLCli( $tex, $params, $this->cache );
|
||||||
} else {
|
} else {
|
||||||
$renderer = new MathMathML( $tex, $params );
|
$renderer = new MathMathML( $tex, $params, $this->cache );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger->debug(
|
$this->logger->debug(
|
||||||
|
@ -113,4 +120,15 @@ class RendererFactory {
|
||||||
);
|
);
|
||||||
return $renderer;
|
return $renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFromHash( $hash ) {
|
||||||
|
$rpage = $this->cache->get( $hash );
|
||||||
|
if ( $rpage === false ) {
|
||||||
|
throw new InvalidArgumentException( 'Cache key is invalid' );
|
||||||
|
}
|
||||||
|
$mode = $rpage['math_mode'];
|
||||||
|
$renderer = $this->getRenderer( '', [], $mode );
|
||||||
|
$renderer->initializeFromCache( $rpage );
|
||||||
|
return $renderer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,9 @@ class SpecialMathShowImage extends SpecialPage {
|
||||||
echo $this->printSvgError( 'No Inputhash specified' );
|
echo $this->printSvgError( 'No Inputhash specified' );
|
||||||
} else {
|
} else {
|
||||||
if ( $tex === '' && $asciimath === '' ) {
|
if ( $tex === '' && $asciimath === '' ) {
|
||||||
$this->renderer = $this->rendererFactory->getRenderer( '', [], $this->mode );
|
$this->renderer = $this->rendererFactory->getFromHash( $hash );
|
||||||
$this->renderer->setMd5( $hash );
|
|
||||||
$this->noRender = $request->getBool( 'noRender', false );
|
$this->noRender = $request->getBool( 'noRender', false );
|
||||||
$isInDatabase = $this->renderer->readFromDatabase();
|
$isInDatabase = $this->renderer->readFromCache();
|
||||||
if ( $isInDatabase || $this->noRender ) {
|
if ( $isInDatabase || $this->noRender ) {
|
||||||
$success = $isInDatabase;
|
$success = $isInDatabase;
|
||||||
} else {
|
} else {
|
||||||
|
|
79
tests/phpunit/MathCacheTest.php
Normal file
79
tests/phpunit/MathCacheTest.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use MediaWiki\Extension\Math\MathMathML;
|
||||||
|
use MediaWiki\Extension\Math\MathRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the database access and core functionality of MathRenderer.
|
||||||
|
*
|
||||||
|
* @covers \MediaWiki\Extension\Math\MathRenderer
|
||||||
|
*
|
||||||
|
* @group Math
|
||||||
|
*
|
||||||
|
* @license GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
class MathCacheTest extends MediaWikiIntegrationTestCase {
|
||||||
|
/**
|
||||||
|
* @var MathRenderer
|
||||||
|
*/
|
||||||
|
private $renderer;
|
||||||
|
private const SOME_TEX = "a+b";
|
||||||
|
private const SOME_MATHML = "iℏ∂_tΨ=H^Ψ<mrow><\ci>";
|
||||||
|
|
||||||
|
protected function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
$this->renderer = new MathMathML( self::SOME_TEX );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the tex and hash functions
|
||||||
|
* @covers \MediaWiki\Extension\Math\MathRenderer::getInputHash
|
||||||
|
*/
|
||||||
|
public function testInputHash() {
|
||||||
|
$this->assertEquals( 'beb7506b16f7c36aa0f9c8c9ef41b40b', $this->renderer->getInputHash() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to set the current state of the sample renderer instance to the test values
|
||||||
|
*/
|
||||||
|
public function setValues() {
|
||||||
|
// set some values
|
||||||
|
$this->renderer->setTex( self::SOME_TEX );
|
||||||
|
$this->renderer->setMathml( self::SOME_MATHML );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks database access. Writes an entry and reads it back.
|
||||||
|
* @covers \MediaWiki\Extension\Math\MathRenderer::writeToCache
|
||||||
|
* @covers \MediaWiki\Extension\Math\MathRenderer::readFromCache
|
||||||
|
*/
|
||||||
|
public function testDBBasics() {
|
||||||
|
$this->setValues();
|
||||||
|
$this->renderer->writeToCache();
|
||||||
|
$renderer2 = new MathMathML( self::SOME_TEX, [ 'display' => '' ] );
|
||||||
|
$this->assertTrue( $renderer2->readFromCache(), 'Reading from database failed' );
|
||||||
|
// comparing the class object does now work due to null values etc.
|
||||||
|
$this->assertEquals(
|
||||||
|
$this->renderer->getTex(), $renderer2->getTex(), "test if tex is the same"
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$this->renderer->getMathml(), $renderer2->getMathml(), "Check MathML encoding"
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$this->renderer->getHtmlOutput(), $renderer2->getHtmlOutput(), 'test if HTML is the same'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test checks if no additional write operation
|
||||||
|
* is performed, if the entry already existed in the database.
|
||||||
|
*/
|
||||||
|
public function testNoWrite() {
|
||||||
|
$this->setValues();
|
||||||
|
$inputHash = $this->renderer->getInputHash();
|
||||||
|
$this->assertTrue( $this->renderer->isChanged() );
|
||||||
|
$this->assertTrue( $this->renderer->writeCache(), "Write new entry" );
|
||||||
|
$this->assertTrue( $this->renderer->readFromCache(), "Read entry from database" );
|
||||||
|
$this->assertFalse( $this->renderer->isChanged() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,126 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use MediaWiki\Extension\Math\MathConfig;
|
|
||||||
use MediaWiki\Extension\Math\MathMathML;
|
|
||||||
use MediaWiki\Extension\Math\MathRenderer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the database access and core functionality of MathRenderer.
|
|
||||||
*
|
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer
|
|
||||||
*
|
|
||||||
* @group Math
|
|
||||||
* @group Database
|
|
||||||
*
|
|
||||||
* @license GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
class MathDatabaseTest extends MediaWikiIntegrationTestCase {
|
|
||||||
/**
|
|
||||||
* @var MathRenderer
|
|
||||||
*/
|
|
||||||
private $renderer;
|
|
||||||
private const SOME_TEX = "a+b";
|
|
||||||
private const SOME_MATHML = "iℏ∂_tΨ=H^Ψ<mrow><\ci>";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a new database connection and a new math renderer
|
|
||||||
* TODO: Check if there is a way to get database access without creating
|
|
||||||
* the connection to the database explicitly
|
|
||||||
* function addDBData() {
|
|
||||||
* $this->tablesUsed[] = 'math';
|
|
||||||
* }
|
|
||||||
* was not sufficient.
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected function setUp(): void {
|
|
||||||
parent::setUp();
|
|
||||||
// TODO: figure out why this is necessary
|
|
||||||
$this->db = $this->getServiceContainer()
|
|
||||||
->getDBLoadBalancer()
|
|
||||||
->getConnection( DB_PRIMARY );
|
|
||||||
$this->renderer = new MathMathML( self::SOME_TEX );
|
|
||||||
$this->tablesUsed[] = 'mathoid';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the tex and hash functions
|
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer::getInputHash
|
|
||||||
*/
|
|
||||||
public function testInputHash() {
|
|
||||||
$expectedhash = $this->db->encodeBlob( pack( "H32", md5( self::SOME_TEX ) ) );
|
|
||||||
$this->assertEquals( $expectedhash, $this->renderer->getInputHash() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to set the current state of the sample renderer instance to the test values
|
|
||||||
*/
|
|
||||||
public function setValues() {
|
|
||||||
// set some values
|
|
||||||
$this->renderer->setTex( self::SOME_TEX );
|
|
||||||
$this->renderer->setMathml( self::SOME_MATHML );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks database access. Writes an entry and reads it back.
|
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer::writeToDatabase
|
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer::readFromDatabase
|
|
||||||
*/
|
|
||||||
public function testDBBasics() {
|
|
||||||
$this->setValues();
|
|
||||||
$this->renderer->writeToDatabase( $this->db );
|
|
||||||
$renderer2 = new MathMathML( self::SOME_TEX );
|
|
||||||
$this->assertTrue( $renderer2->readFromDatabase(), 'Reading from database failed' );
|
|
||||||
// comparing the class object does now work due to null values etc.
|
|
||||||
$this->assertEquals(
|
|
||||||
$this->renderer->getTex(), $renderer2->getTex(), "test if tex is the same"
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
$this->renderer->getMathml(), $renderer2->getMathml(), "Check MathML encoding"
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
$this->renderer->getHtmlOutput(), $renderer2->getHtmlOutput(), 'test if HTML is the same'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the creation of the math table.
|
|
||||||
* @covers \MediaWiki\Extension\Math\HookHandlers\SchemaHooksHandler::onLoadExtensionSchemaUpdates
|
|
||||||
*/
|
|
||||||
public function testCreateTable() {
|
|
||||||
$this->markTestSkippedIfDbType( 'postgres' );
|
|
||||||
$this->markTestSkippedIfDbType( 'sqlite' );
|
|
||||||
|
|
||||||
$this->setMwGlobals( 'wgMathValidModes', [ MathConfig::MODE_MATHML ] );
|
|
||||||
$this->db->dropTable( "mathoid", __METHOD__ );
|
|
||||||
$dbu = DatabaseUpdater::newForDB( $this->db );
|
|
||||||
$dbu->doUpdates( [ "extensions" ] );
|
|
||||||
$this->expectOutputRegex( '/(.*)Creating mathoid table(.*)/' );
|
|
||||||
$this->setValues();
|
|
||||||
$this->renderer->writeToDatabase();
|
|
||||||
$res = $this->db->select( "mathoid", "*" );
|
|
||||||
$row = $res->fetchRow();
|
|
||||||
$this->assertCount( 16, $row );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test checks if no additional write operation
|
|
||||||
* is performed, if the entry already existed in the database.
|
|
||||||
*/
|
|
||||||
public function testNoWrite() {
|
|
||||||
$this->setValues();
|
|
||||||
$inputHash = $this->renderer->getInputHash();
|
|
||||||
$this->assertTrue( $this->renderer->isChanged() );
|
|
||||||
$this->assertTrue( $this->renderer->writeCache(), "Write new entry" );
|
|
||||||
$res = $this->db->selectField( "mathoid", "math_inputhash",
|
|
||||||
[ "math_inputhash" => $inputHash ] );
|
|
||||||
$this->assertTrue( $res !== false, "Check database entry" );
|
|
||||||
$this->assertTrue( $this->renderer->readFromDatabase(), "Read entry from database" );
|
|
||||||
$this->assertFalse( $this->renderer->isChanged() );
|
|
||||||
// modify the database entry manually
|
|
||||||
$this->db->delete( "mathoid", [ "math_inputhash" => $inputHash ] );
|
|
||||||
// the renderer should not be aware of the modification and should not recreate the entry
|
|
||||||
$this->assertFalse( $this->renderer->writeCache() );
|
|
||||||
// as a result no entry can be found in the database.
|
|
||||||
$this->assertFalse( $this->renderer->readFromDatabase() );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use MediaWiki\Extension\Math\InputCheck\BaseChecker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @covers \MediaWiki\Extension\Math\InputCheck\BaseChecker
|
|
||||||
*
|
|
||||||
* @group Math
|
|
||||||
*
|
|
||||||
* @license GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
class MathInputCheckTest extends MediaWikiIntegrationTestCase {
|
|
||||||
|
|
||||||
public function testAbstractClass() {
|
|
||||||
$InputCheck = $this->getMockForAbstractClass( BaseChecker::class );
|
|
||||||
/** @var BaseChecker $InputCheck */
|
|
||||||
$this->assertFalse( $InputCheck->IsValid() );
|
|
||||||
$this->assertNull( $InputCheck->getError() );
|
|
||||||
$this->assertNull( $InputCheck->getValidTex() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use MediaWiki\Extension\Math\MathConfig;
|
|
||||||
use MediaWiki\Extension\Math\MathLaTeXML;
|
use MediaWiki\Extension\Math\MathLaTeXML;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \MediaWiki\Extension\Math\MathLaTeXML
|
* @covers \MediaWiki\Extension\Math\MathLaTeXML
|
||||||
*
|
*
|
||||||
* @group Math
|
* @group Math
|
||||||
* @group Database
|
|
||||||
*
|
*
|
||||||
* @license GPL-2.0-or-later
|
* @license GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
class MathLaTeXMLDatabaseTest extends MediaWikiIntegrationTestCase {
|
class MathLaTeXMLCacheTest extends MediaWikiIntegrationTestCase {
|
||||||
public $renderer;
|
public $renderer;
|
||||||
private const SOME_TEX = "a+b";
|
private const SOME_TEX = "a+b";
|
||||||
private const SOME_HTML = "a<sub>b</sub>";
|
|
||||||
private const SOME_MATHML = "iℏ∂_tΨ=H^Ψ<mrow><\ci>";
|
private const SOME_MATHML = "iℏ∂_tΨ=H^Ψ<mrow><\ci>";
|
||||||
private const SOME_LOG = "Sample Log Text.";
|
|
||||||
private const SOME_TIMESTAMP = 1272509157;
|
|
||||||
private const SOME_SVG = "<?xml </svg >>%%LIKE;'\" DROP TABLE math;";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to test protected/private Methods
|
* Helper function to test protected/private Methods
|
||||||
|
@ -32,21 +26,9 @@ class MathLaTeXMLDatabaseTest extends MediaWikiIntegrationTestCase {
|
||||||
return $method;
|
return $method;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a new database connection and a new math renderer
|
|
||||||
* TODO: Check if there is a way to get database access without creating
|
|
||||||
* the connection to the database explicitly
|
|
||||||
* function addDBData() {
|
|
||||||
* $this->tablesUsed[] = 'math';
|
|
||||||
* }
|
|
||||||
* was not sufficient.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void {
|
protected function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
// TODO: figure out why this is necessary
|
|
||||||
$this->db = wfGetDB( DB_PRIMARY );
|
|
||||||
$this->renderer = new MathLaTeXML( self::SOME_TEX );
|
$this->renderer = new MathLaTeXML( self::SOME_TEX );
|
||||||
self::setupTestDB( $this->db, "mathtest" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,8 +36,8 @@ class MathLaTeXMLDatabaseTest extends MediaWikiIntegrationTestCase {
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer::getInputHash
|
* @covers \MediaWiki\Extension\Math\MathRenderer::getInputHash
|
||||||
*/
|
*/
|
||||||
public function testInputHash() {
|
public function testInputHash() {
|
||||||
$expectedhash = $this->db->encodeBlob( pack( "H32", md5( self::SOME_TEX ) ) );
|
$this->assertIsString( $this->renderer->getInputHash() );
|
||||||
$this->assertEquals( $expectedhash, $this->renderer->getInputHash() );
|
$this->assertStringMatchesFormat( '%x', $this->renderer->getInputHash() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,38 +59,17 @@ class MathLaTeXMLDatabaseTest extends MediaWikiIntegrationTestCase {
|
||||||
$this->assertEquals( "mathlatexml", $tableName, "Wrong latexml table name" );
|
$this->assertEquals( "mathlatexml", $tableName, "Wrong latexml table name" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the creation of the math table.
|
|
||||||
* @covers \MediaWiki\Extension\Math\HookHandlers\SchemaHooksHandler::onLoadExtensionSchemaUpdates
|
|
||||||
*/
|
|
||||||
public function testCreateTable() {
|
|
||||||
$this->markTestSkippedIfDbType( 'postgres' );
|
|
||||||
$this->markTestSkippedIfDbType( 'sqlite' );
|
|
||||||
|
|
||||||
$this->setMwGlobals( 'wgMathValidModes', [ MathConfig::MODE_LATEXML ] );
|
|
||||||
$this->db->dropTable( "mathlatexml", __METHOD__ );
|
|
||||||
$dbu = DatabaseUpdater::newForDB( $this->db );
|
|
||||||
$dbu->doUpdates( [ "extensions" ] );
|
|
||||||
$this->expectOutputRegex( '/(.*)Creating mathlatexml table(.*)/' );
|
|
||||||
$this->setValues();
|
|
||||||
$this->renderer->writeToDatabase();
|
|
||||||
$res = $this->db->select( "mathlatexml", "*" );
|
|
||||||
$row = $res->fetchRow();
|
|
||||||
$this->assertCount( 12, $row );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks database access. Writes an entry and reads it back.
|
* Checks database access. Writes an entry and reads it back.
|
||||||
* @depends testCreateTable
|
* @covers \MediaWiki\Extension\Math\MathRenderer::writeToCache
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer::writeToDatabase
|
* @covers \MediaWiki\Extension\Math\MathRenderer::readFromCache
|
||||||
* @covers \MediaWiki\Extension\Math\MathRenderer::readFromDatabase
|
|
||||||
*/
|
*/
|
||||||
public function testDBBasics() {
|
public function testDBBasics() {
|
||||||
$this->setValues();
|
$this->setValues();
|
||||||
$this->renderer->writeToDatabase();
|
$this->renderer->writeToCache();
|
||||||
|
|
||||||
$renderer2 = $this->renderer = new MathLaTeXML( self::SOME_TEX );
|
$renderer2 = $this->renderer = new MathLaTeXML( self::SOME_TEX );
|
||||||
$renderer2->readFromDatabase();
|
$renderer2->readFromCache();
|
||||||
// comparing the class object does now work due to null values etc.
|
// comparing the class object does now work due to null values etc.
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
$this->renderer->getTex(), $renderer2->getTex(), "test if tex is the same"
|
$this->renderer->getTex(), $renderer2->getTex(), "test if tex is the same"
|
|
@ -39,12 +39,12 @@ class MathRendererTest extends MediaWikiIntegrationTestCase {
|
||||||
public function testWriteCacheSkip() {
|
public function testWriteCacheSkip() {
|
||||||
$renderer =
|
$renderer =
|
||||||
$this->getMockBuilder( MathRenderer::class )->onlyMethods( [
|
$this->getMockBuilder( MathRenderer::class )->onlyMethods( [
|
||||||
'writeToDatabase',
|
'writeToCache',
|
||||||
'render',
|
'render',
|
||||||
'getMathTableName',
|
'getMathTableName',
|
||||||
'getHtmlOutput'
|
'getHtmlOutput'
|
||||||
] )->getMock();
|
] )->getMock();
|
||||||
$renderer->expects( $this->never() )->method( 'writeToDatabase' );
|
$renderer->expects( $this->never() )->method( 'writeToCache' );
|
||||||
/** @var MathRenderer $renderer */
|
/** @var MathRenderer $renderer */
|
||||||
$renderer->writeCache();
|
$renderer->writeCache();
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,12 @@ class MathRendererTest extends MediaWikiIntegrationTestCase {
|
||||||
public function testWriteCache() {
|
public function testWriteCache() {
|
||||||
$renderer =
|
$renderer =
|
||||||
$this->getMockBuilder( MathRenderer::class )->onlyMethods( [
|
$this->getMockBuilder( MathRenderer::class )->onlyMethods( [
|
||||||
'writeToDatabase',
|
'writeToCache',
|
||||||
'render',
|
'render',
|
||||||
'getMathTableName',
|
'getMathTableName',
|
||||||
'getHtmlOutput'
|
'getHtmlOutput'
|
||||||
] )->getMock();
|
] )->getMock();
|
||||||
$renderer->expects( $this->never() )->method( 'writeToDatabase' );
|
$renderer->expects( $this->never() )->method( 'writeToCache' );
|
||||||
/** @var MathRenderer $renderer */
|
/** @var MathRenderer $renderer */
|
||||||
$renderer->writeCache();
|
$renderer->writeCache();
|
||||||
}
|
}
|
||||||
|
@ -87,10 +87,10 @@ class MathRendererTest extends MediaWikiIntegrationTestCase {
|
||||||
'render',
|
'render',
|
||||||
'getMathTableName',
|
'getMathTableName',
|
||||||
'getHtmlOutput',
|
'getHtmlOutput',
|
||||||
'readFromDatabase',
|
'readFromCache',
|
||||||
'setTex'
|
'setTex'
|
||||||
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
||||||
$renderer->expects( $this->never() )->method( 'readFromDatabase' );
|
$renderer->expects( $this->never() )->method( 'readFromCache' );
|
||||||
$renderer->expects( $this->once() )->method( 'setTex' )->with( self::TEXVCCHECK_OUTPUT );
|
$renderer->expects( $this->once() )->method( 'setTex' )->with( self::TEXVCCHECK_OUTPUT );
|
||||||
|
|
||||||
/** @var MathRenderer $renderer */
|
/** @var MathRenderer $renderer */
|
||||||
|
@ -106,10 +106,10 @@ class MathRendererTest extends MediaWikiIntegrationTestCase {
|
||||||
'render',
|
'render',
|
||||||
'getMathTableName',
|
'getMathTableName',
|
||||||
'getHtmlOutput',
|
'getHtmlOutput',
|
||||||
'readFromDatabase',
|
'readFromCache',
|
||||||
'setTex'
|
'setTex'
|
||||||
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
||||||
$renderer->expects( $this->never() )->method( 'readFromDatabase' );
|
$renderer->expects( $this->never() )->method( 'readFromCache' );
|
||||||
$renderer->expects( $this->never() )->method( 'setTex' );
|
$renderer->expects( $this->never() )->method( 'setTex' );
|
||||||
|
|
||||||
/** @var MathRenderer $renderer */
|
/** @var MathRenderer $renderer */
|
||||||
|
@ -125,10 +125,10 @@ class MathRendererTest extends MediaWikiIntegrationTestCase {
|
||||||
'render',
|
'render',
|
||||||
'getMathTableName',
|
'getMathTableName',
|
||||||
'getHtmlOutput',
|
'getHtmlOutput',
|
||||||
'readFromDatabase',
|
'readFromCache',
|
||||||
'setTex'
|
'setTex'
|
||||||
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
||||||
$renderer->expects( $this->once() )->method( 'readFromDatabase' )
|
$renderer->expects( $this->once() )->method( 'readFromCache' )
|
||||||
->willReturn( false );
|
->willReturn( false );
|
||||||
$renderer->expects( $this->once() )->method( 'setTex' )->with( self::TEXVCCHECK_OUTPUT );
|
$renderer->expects( $this->once() )->method( 'setTex' )->with( self::TEXVCCHECK_OUTPUT );
|
||||||
|
|
||||||
|
@ -147,10 +147,10 @@ class MathRendererTest extends MediaWikiIntegrationTestCase {
|
||||||
'render',
|
'render',
|
||||||
'getMathTableName',
|
'getMathTableName',
|
||||||
'getHtmlOutput',
|
'getHtmlOutput',
|
||||||
'readFromDatabase',
|
'readFromCache',
|
||||||
'setTex'
|
'setTex'
|
||||||
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
] )->setConstructorArgs( [ self::TEXVCCHECK_INPUT ] )->getMock();
|
||||||
$renderer->expects( $this->once() )->method( 'readFromDatabase' )
|
$renderer->expects( $this->once() )->method( 'readFromCache' )
|
||||||
->willReturn( true );
|
->willReturn( true );
|
||||||
$renderer->expects( $this->never() )->method( 'setTex' );
|
$renderer->expects( $this->never() )->method( 'setTex' );
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue