Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
60.80% covered (warning)
60.80%
107 / 176
43.18% covered (danger)
43.18%
19 / 44
CRAP
0.00% covered (danger)
0.00%
0 / 1
MathRenderer
60.80% covered (warning)
60.80%
107 / 176
43.18% covered (danger)
43.18%
19 / 44
476.35
0.00% covered (danger)
0.00%
0 / 1
 setRawError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 __construct
61.90% covered (warning)
61.90%
13 / 21
0.00% covered (danger)
0.00%
0 / 1
7.99
 getRenderer
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 render
n/a
0 / 0
n/a
0 / 0
0
 getHtmlOutput
n/a
0 / 0
n/a
0 / 0
0
 getError
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getInputHash
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 readFromCache
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
2.03
 dbInArray
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 initializeFromCache
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
5.03
 writeToCache
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 dbOutArray
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 setRestbaseInterface
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 hasWarnings
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 addTrackingCategories
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getChecker
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getAttributes
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeCache
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getTex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMode
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setTex
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getMathml
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 setMathml
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isChanged
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isPurge
41.67% covered (danger)
41.67%
5 / 12
0.00% covered (danger)
0.00%
0 / 1
13.15
 setPurge
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getLastError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setMathStyle
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getMathStyle
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isTexSecure
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 checkTeX
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
6
 isInDatabase
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getUserInputTex
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getID
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setID
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setSvg
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getSvg
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 getMathTableName
n/a
0 / 0
n/a
0 / 0
0
 getModeName
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 setInputType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInputType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 doCheck
50.00% covered (danger)
50.00%
5 / 10
0.00% covered (danger)
0.00%
0 / 1
4.12
 debug
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCacheKey
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * MediaWiki math extension
4 *
5 * @copyright 2002-2012 Tomasz Wegrzanowski, Brion Vibber, Moritz Schubotz,
6 * and other MediaWiki contributors
7 * @license GPL-2.0-or-later
8 *
9 * @file
10 */
11
12namespace MediaWiki\Extension\Math;
13
14use MediaWiki\Context\RequestContext;
15use MediaWiki\Extension\Math\InputCheck\BaseChecker;
16use MediaWiki\Logger\LoggerFactory;
17use MediaWiki\MediaWikiServices;
18use MediaWiki\Message\Message;
19use MediaWiki\Parser\Parser;
20use MediaWiki\Parser\Sanitizer;
21use Psr\Log\LoggerInterface;
22use Wikimedia\Message\MessageParam;
23use Wikimedia\Message\MessageSpecifier as MsgSp;
24use Wikimedia\ObjectCache\WANObjectCache;
25use Wikimedia\StringUtils\StringUtils;
26
27/**
28 * Abstract base class with static methods for rendering the <math> tags using
29 * different technologies. These static methods create a new instance of the
30 * extending classes and render the math tags based on the mode setting of the user.
31 * Furthermore, this class handles the caching of the rendered output.
32 *
33 * @author Tomasz Wegrzanowski
34 * @author Brion Vibber
35 * @author Moritz Schubotz
36 */
37abstract class MathRenderer {
38
39    // REPRESENTATIONS OF THE MATHEMATICAL CONTENT
40    /** @var ?string tex representation */
41    protected $tex = '';
42    /** @var string MathML content and presentation */
43    protected $mathml = '';
44    /** @var string SVG layout only (no semantics) */
45    protected $svg = '';
46    /** @var string the original user input string (which was used to calculate the inputhash) */
47    protected $userInputTex = '';
48    // FURTHER PROPERTIES OF THE MATHEMATICAL CONTENT
49    /** @var string ('inlineDisplaystyle'|'display'|'inline'|'linebreak') the rendering style */
50    protected $mathStyle = 'inlineDisplaystyle';
51    /** @var array with userdefined parameters passed to the extension (not used) */
52    protected $params = [];
53    /** @var string a userdefined identifier to link to the equation. */
54    protected $id = '';
55
56    // STATE OF THE CLASS INSTANCE
57    /** @var bool has variable tex been security-checked */
58    protected $texSecure = false;
59    /** @var bool has the mathematical content changed */
60    protected $changed = false;
61    /** @var bool|null is there a database entry for the mathematical content */
62    protected $storedInCache = null;
63    /** @var bool is there a request to purge the existing mathematical content */
64    protected $purge = false;
65    /** @var string with last occurred error */
66    protected $lastError = '';
67    /** @var string binary packed inputhash */
68    protected $inputHash = '';
69    /** @var string rendering mode */
70    protected $mode = MathConfig::MODE_MATHML;
71    /** @var string input type */
72    protected $inputType = 'tex';
73    /** @var MathRestbaseInterface used for checking */
74    protected $rbi;
75    /** @var array with rendering warnings */
76    protected $warnings;
77    /** @var LoggerInterface */
78    private $logger;
79
80    private WANObjectCache $cache;
81    private MathConfig $mathConfig;
82    private bool $rawError = false;
83
84    public function setRawError( bool $rawError ): void {
85        $this->rawError = $rawError;
86    }
87
88    /**
89     * Constructs a base MathRenderer
90     *
91     * @param string $tex (optional) LaTeX markup
92     * @param array $params (optional) HTML attributes
93     * @param WANObjectCache|null $cache (optional)
94     * @param MathConfig|null $mathConfig (optional)
95     */
96    public function __construct( string $tex = '', $params = [], $cache = null, $mathConfig = null ) {
97        $this->cache = $cache ?? MediaWikiServices::getInstance()->getMainWANObjectCache();
98        $this->mathConfig = $mathConfig ?? Math::getMathConfig();
99        $this->params = $params;
100        if ( isset( $params['id'] ) ) {
101            $this->id = $params['id'];
102        }
103        if ( isset( $params['display'] ) ) {
104            $layoutMode = $params['display'];
105            if ( $layoutMode == 'block' ) {
106                $this->mathStyle = 'display';
107                $tex = '{\displaystyle ' . $tex . '}';
108                $this->inputType = 'tex';
109            } elseif ( $layoutMode == 'inline' ) {
110                $this->mathStyle = 'inline';
111                $this->inputType = 'inline-tex';
112                $tex = '{\textstyle ' . $tex . '}';
113            } elseif ( $layoutMode == 'linebreak' ) {
114                $this->mathStyle = 'linebreak';
115                $tex = '\[ ' . $tex . ' \]';
116            }
117        }
118        // TODO: Implement caching for attributes of the math tag
119        // Currently the key for the database entry relating to an equation
120        // is md5($tex) the new option to determine if the tex input
121        // is rendered in displaystyle or textstyle would require a database
122        // layout change to use a composite key e.g. (md5($tex),$mathStyle).
123        // As a workaround we use the prefix \displaystyle so that the key becomes
124        // md5((\{\\displaystyle|\{\\textstyle)?\s?$tex\}?)
125        // The new value of $tex string describes now how the rendering should look like.
126        // The variable MathRenderer::mathStyle determines if the rendered equation should
127        // be centered in a new line, or just in be displayed in the current line.
128        $this->userInputTex = $tex;
129        $this->tex = $tex;
130        $this->logger = LoggerFactory::getInstance( 'Math' );
131    }
132
133    /**
134     * Static factory method for getting a renderer based on mode
135     *
136     * @deprecated since 3.0.0. Use Math.RendererFactory service instead.
137     * @param string $tex LaTeX markup
138     * @param array $params HTML attributes
139     * @param string $mode indicating rendering mode
140     * @return self appropriate renderer for mode
141     */
142    public static function getRenderer( $tex, $params = [], $mode = MathConfig::MODE_MATHML ) {
143        return MediaWikiServices::getInstance()
144            ->get( 'Math.RendererFactory' )
145            ->getRenderer( $tex, $params, $mode );
146    }
147
148    /**
149     * Performs the rendering
150     *
151     * @return bool if rendering was successful.
152     */
153    abstract public function render();
154
155    /**
156     * @param bool $svg
157     * @return string Html output that is embedded in the page
158     */
159    abstract public function getHtmlOutput( bool $svg = true ): string;
160
161    /**
162     * texvc error messages
163     * TODO: update to MathML
164     * Returns an internationalized HTML error string
165     *
166     * @param string $msg message key for the specific error
167     * @param MessageParam|MsgSp|string|int|float|list<MessageParam|MsgSp|string|int|float> ...$parameters
168     * See Message::params()
169     *
170     * @return string HTML error string
171     */
172    public function getError( string $msg, ...$parameters ): string {
173        if ( $this->rawError ) {
174            return 'Error: ' . $msg . ' param ' . implode( ',', $parameters );
175        }
176        $mf = wfMessage( 'math_failure' )->inContentLanguage()->escaped();
177        $errmsg = wfMessage( $msg, $parameters )->inContentLanguage()->escaped();
178        $source = htmlspecialchars( str_replace( "\n", ' ', $this->tex ) );
179        return "<strong class=\"error texerror\">$mf ($errmsg): $source</strong>\n";
180    }
181
182    /**
183     * Return hash of input
184     *
185     * @return string hash
186     */
187    public function getInputHash(): string {
188        if ( !$this->inputHash ) {
189            $this->inputHash = hash( 'md5', // xxh128 might be better when dropping php 7 support
190                $this->mode .
191                $this->userInputTex .
192                implode( $this->params )
193            );
194        }
195        return $this->inputHash;
196    }
197
198    /**
199     * Reads rendering data from database
200     *
201     * @return bool true if read successfully, false otherwise
202     */
203    public function readFromCache(): bool {
204        $rpage = $this->cache->get( $this->getCacheKey() );
205        if ( $rpage !== false ) {
206            $this->initializeFromCache( $rpage );
207            return true;
208        } else {
209            # Missing from the database and/or the render cache
210            return false;
211        }
212    }
213
214    /**
215     * @return array with the database column names
216     */
217    protected function dbInArray() {
218        $in = [ 'math_inputhash',
219            'math_mathml',
220            'math_inputtex',
221            'math_tex',
222            'math_svg'
223        ];
224        return $in;
225    }
226
227    /**
228     * Reads the values from the database but does not overwrite set values with empty values
229     * @param array $rpage (a database row)
230     */
231    public function initializeFromCache( $rpage ) {
232        $this->inputHash = $rpage['math_inputhash']; // MUST NOT BE NULL
233        if ( isset( $rpage['math_mathml'] ) ) {
234            $this->mathml = $rpage['math_mathml'];
235        }
236        if ( isset( $rpage['math_inputtex'] ) ) {
237            $this->userInputTex = $rpage['math_inputtex'];
238        }
239        if ( isset( $rpage['math_tex'] ) ) {
240            $this->tex = $rpage['math_tex'];
241        }
242        if ( isset( $rpage['math_svg'] ) ) {
243            $this->svg = $rpage['math_svg'];
244        }
245        $this->changed = false;
246    }
247
248    /**
249     * Writes rendering entry to cache.
250     *
251     * WARNING: Use writeCache() instead of this method to be sure that all
252     * renderer specific (such as squid caching) are taken into account.
253     * This function stores the values that are currently present in the class
254     * to the cache even if they are empty.
255     *
256     * This function can be seen as protected function.
257     */
258    public function writeToCache() {
259        $outArray = $this->dbOutArray();
260        $this->cache->set( $this->getCacheKey(), $outArray );
261    }
262
263    /**
264     * Gets an array that matches the variables of the class to the database columns
265     * @return array
266     */
267    protected function dbOutArray() {
268        $out = [
269            'math_inputhash' => $this->getInputHash(),
270            'math_mathml' => $this->mathml,
271            'math_inputtex' => $this->userInputTex,
272            'math_tex' => $this->tex,
273            'math_svg' => $this->svg,
274            'math_mode' => $this->mode
275        ];
276        return $out;
277    }
278
279    /**
280     * @param MathRestbaseInterface $param
281     */
282    public function setRestbaseInterface( $param ) {
283        $this->rbi = $param;
284        $this->rbi->setPurge( $this->isPurge() );
285    }
286
287    public function hasWarnings(): bool {
288        if ( is_array( $this->warnings ) && count( $this->warnings ) ) {
289            return true;
290        }
291
292        return false;
293    }
294
295    /**
296     * Adds tracking categories to the parser
297     *
298     * @param Parser $parser
299     */
300    public function addTrackingCategories( $parser ) {
301        if ( !$this->checkTeX() ) {
302            $parser->addTrackingCategory( 'math-tracking-category-error' );
303        }
304        if ( $this->lastError ) {
305            // Add a tracking category specialized on render errors.
306            $parser->addTrackingCategory( 'math-tracking-category-render-error' );
307        }
308    }
309
310    protected function getChecker(): BaseChecker {
311        return Math::getCheckerFactory()
312            ->newDefaultChecker( $this->tex, $this->getInputType(), $this->rbi, $this->isPurge() );
313    }
314
315    /**
316     * Returns sanitized attributes
317     *
318     * @param string $tag element name
319     * @param array $defaults default attributes
320     * @param array $overrides attributes to override defaults
321     * @return array HTML attributes
322     */
323    protected function getAttributes( $tag, $defaults = [], $overrides = [] ) {
324        $attribs = Sanitizer::validateTagAttributes( $this->params, $tag );
325        $attribs = Sanitizer::mergeAttributes( $defaults, $attribs );
326        return Sanitizer::mergeAttributes( $attribs, $overrides );
327    }
328
329    /**
330     * Writes cache. Writes the database entry if values were changed
331     * @return bool
332     */
333    public function writeCache() {
334        $this->debug( 'Writing of cache requested' );
335        if ( $this->isChanged() ) {
336            $this->debug( 'Change detected. Perform writing' );
337            $this->writeToCache();
338            return true;
339        } else {
340            $this->debug( "Nothing was changed. Don't write to database" );
341            return false;
342        }
343    }
344
345    /**
346     * Gets TeX markup
347     *
348     * @return string TeX markup
349     */
350    public function getTex() {
351        return $this->tex;
352    }
353
354    /**
355     * Gets the rendering mode
356     *
357     * @return string
358     */
359    public function getMode() {
360        return $this->mode;
361    }
362
363    /**
364     * Sets the rendering mode
365     * @param string $newMode element of the array $wgMathValidModes
366     * @return bool
367     */
368    public function setMode( string $newMode ): bool {
369        if ( $this->mathConfig->isValidRenderingMode( $newMode ) ) {
370            $this->mode = $newMode;
371            return true;
372        } else {
373            return false;
374        }
375    }
376
377    /**
378     * Sets the TeX code
379     */
380    public function setTex( ?string $tex ) {
381        if ( $this->tex != $tex ) {
382            $this->changed = true;
383            $this->tex = $tex;
384        }
385    }
386
387    /**
388     * Gets the MathML XML element
389     * @return string in UTF-8 encoding
390     */
391    public function getMathml() {
392        if ( !StringUtils::isUtf8( $this->mathml ) ) {
393            $this->setMathml( '' );
394        }
395        return $this->mathml;
396    }
397
398    /**
399     * @param string $mathml use UTF-8 encoding
400     */
401    public function setMathml( $mathml ) {
402        $this->changed = true;
403        $this->mathml = $mathml;
404    }
405
406    /**
407     * Get the attributes of the math tag
408     *
409     * @return array
410     */
411    public function getParams() {
412        return $this->params;
413    }
414
415    /**
416     * @param array $params
417     */
418    public function setParams( $params ) {
419        // $changed is not set to true here, because the attributes do not affect
420        // the rendering in the current implementation.
421        // If this behavior will change in the future $this->tex is no longer a
422        // primary key and the input hash cannot be calculate form $this->tex
423        // only. See the discussion 'Tag extensions in Block mode' on wikitech-l.
424        $this->params = $params;
425    }
426
427    /**
428     * Checks if the instance was modified i.e., because math was rendered
429     *
430     * @return bool true if something was changed false otherwise
431     */
432    public function isChanged() {
433        return $this->changed;
434    }
435
436    /**
437     * Checks if there is an explicit user request to rerender the math-tag.
438     * @return bool purge state
439     */
440    public function isPurge() {
441        if ( $this->purge ) {
442            return true;
443        }
444        $refererHeader = RequestContext::getMain()->getRequest()->getHeader( 'REFERER' );
445        if ( $refererHeader ) {
446            $url = parse_url( $refererHeader, PHP_URL_QUERY );
447            if ( !is_string( $url ) ) {
448                return false;
449            }
450            parse_str( $url, $refererParam );
451            if ( isset( $refererParam['action'] ) && $refererParam['action'] === 'purge' ) {
452                $this->logger->debug( 'Re-Rendering on user request' );
453                return true;
454            }
455        }
456        return false;
457    }
458
459    /**
460     * Sets purge. If set to true the render is forced to rerender and must not
461     * use a cached version.
462     * @param bool $purge
463     */
464    public function setPurge( $purge = true ) {
465        $this->changed = true;
466        $this->purge = $purge;
467    }
468
469    public function getLastError(): string {
470        return $this->lastError;
471    }
472
473    /**
474     * @param string $mathStyle ('inlineDisplaystyle'|'display'|'inline')
475     */
476    public function setMathStyle( $mathStyle = 'display' ) {
477        if ( $this->mathStyle !== $mathStyle ) {
478            $this->mathStyle = $mathStyle;
479            $this->changed = true;
480            $this->inputType = $mathStyle === 'inline' ? 'inline-tex' : 'tex';
481        }
482    }
483
484    /**
485     * Returns the value of the DisplayStyle attribute
486     * @return string ('inlineDisplaystyle'|'display'|'inline'|'linebreak') the DisplayStyle
487     */
488    public function getMathStyle() {
489        return $this->mathStyle;
490    }
491
492    /**
493     * Get if the input tex was marked as secure
494     * @return bool
495     */
496    public function isTexSecure() {
497        return $this->texSecure;
498    }
499
500    /**
501     * @return bool
502     */
503    public function checkTeX() {
504        if ( $this->texSecure ) {
505            // equation was already checked
506            return true;
507        }
508        $texCheckDisabled = MediaWikiServices::getInstance()
509            ->get( 'Math.Config' )
510            ->texCheckDisabled();
511        if ( $texCheckDisabled === MathConfig::ALWAYS ) {
512            // checking is disabled
513            $this->debug( 'Skip TeX check ' );
514            return true;
515        } else {
516            if ( $texCheckDisabled === MathConfig::NEW && $this->mode != MathConfig::MODE_SOURCE ) {
517                if ( $this->readFromCache() ) {
518                    $this->debug( 'Skip TeX check' );
519                    $this->texSecure = true;
520                    return true;
521                }
522            }
523            $this->debug( 'Perform TeX check' );
524            return $this->doCheck();
525        }
526    }
527
528    public function isInDatabase(): bool {
529        if ( $this->storedInCache === null ) {
530            $this->storedInCache = $this->readFromCache();
531        }
532        return $this->storedInCache;
533    }
534
535    /**
536     * @return string TeX the original tex string specified by the user
537     */
538    public function getUserInputTex() {
539        return $this->userInputTex;
540    }
541
542    /**
543     * @return string user defined ID
544     */
545    public function getID() {
546        return $this->id;
547    }
548
549    /**
550     * @param string $id user defined ID
551     */
552    public function setID( $id ) {
553        // Changes in the ID affect the container for the math element on the current page
554        // only. Therefore an id change does not affect the $this->changed variable, which
555        // indicates if database relevant fields have been changed.
556        $this->id = $id;
557    }
558
559    /**
560     * @param string $svg
561     */
562    public function setSvg( $svg ) {
563        $this->changed = true;
564        $this->svg = trim( $svg );
565    }
566
567    /**
568     * Gets the SVG image
569     *
570     * @param string $render if set to 'render' (default) and no SVG image exists, the function
571     *                       tries to generate it on the fly.
572     *                       Otherwise, if set to 'cached', and there is no SVG in the database
573     *                       cache, an empty string is returned.
574     *
575     * @return string XML-Document of the rendered SVG
576     */
577    public function getSvg( $render = 'render' ) {
578        // Spaces will prevent the image from being displayed correctly in the browser
579        if ( !$this->svg && $this->rbi ) {
580            $this->svg = $this->rbi->getSvg();
581        }
582        return trim( $this->svg );
583    }
584
585    /**
586     * @return string
587     */
588    abstract protected function getMathTableName();
589
590    protected function getModeName(): Message {
591        return MediaWikiServices::getInstance()
592            ->get( 'Math.Config' )
593            ->getRenderingModeName( $this->getMode() );
594    }
595
596    public function setInputType( string $inputType ) {
597        $this->inputType = $inputType;
598    }
599
600    public function getInputType(): string {
601        return $this->inputType;
602    }
603
604    protected function doCheck(): bool {
605        $checker = $this->getChecker();
606
607        if ( $checker->isValid() ) {
608            $this->setTex( $checker->getValidTex() );
609            $this->texSecure = true;
610            return true;
611        }
612
613        $checkerError = $checker->getError();
614        $this->lastError = $checkerError === null ?
615            $this->getError( 'math_unknown_error' ) :
616            $this->getError( $checkerError->getKey(), ...$checkerError->getParams() );
617        return false;
618    }
619
620    protected function debug( string $msg ) {
621        $this->logger->debug( "$msg for \"{tex}\".", [ 'tex' => $this->userInputTex ] );
622    }
623
624    private function getCacheKey(): string {
625            return $this->cache->makeGlobalKey(
626                self::class,
627                $this->getInputHash()
628            );
629    }
630}