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 StringUtils;
23use Wikimedia\ObjectCache\WANObjectCache;
24
25/**
26 * Abstract base class with static methods for rendering the <math> tags using
27 * different technologies. These static methods create a new instance of the
28 * extending classes and render the math tags based on the mode setting of the user.
29 * Furthermore, this class handles the caching of the rendered output.
30 *
31 * @author Tomasz Wegrzanowski
32 * @author Brion Vibber
33 * @author Moritz Schubotz
34 */
35abstract class MathRenderer {
36
37    // REPRESENTATIONS OF THE MATHEMATICAL CONTENT
38    /** @var ?string tex representation */
39    protected $tex = '';
40    /** @var string MathML content and presentation */
41    protected $mathml = '';
42    /** @var string SVG layout only (no semantics) */
43    protected $svg = '';
44    /** @var string the original user input string (which was used to calculate the inputhash) */
45    protected $userInputTex = '';
46    // FURTHER PROPERTIES OF THE MATHEMATICAL CONTENT
47    /** @var string ('inlineDisplaystyle'|'display'|'inline'|'linebreak') the rendering style */
48    protected $mathStyle = 'inlineDisplaystyle';
49    /** @var array with userdefined parameters passed to the extension (not used) */
50    protected $params = [];
51    /** @var string a userdefined identifier to link to the equation. */
52    protected $id = '';
53
54    // STATE OF THE CLASS INSTANCE
55    /** @var bool has variable tex been security-checked */
56    protected $texSecure = false;
57    /** @var bool has the mathematical content changed */
58    protected $changed = false;
59    /** @var bool|null is there a database entry for the mathematical content */
60    protected $storedInCache = null;
61    /** @var bool is there a request to purge the existing mathematical content */
62    protected $purge = false;
63    /** @var string with last occurred error */
64    protected $lastError = '';
65    /** @var string binary packed inputhash */
66    protected $inputHash = '';
67    /** @var string rendering mode */
68    protected $mode = MathConfig::MODE_MATHML;
69    /** @var string input type */
70    protected $inputType = 'tex';
71    /** @var MathRestbaseInterface used for checking */
72    protected $rbi;
73    /** @var array with rendering warnings */
74    protected $warnings;
75    /** @var LoggerInterface */
76    private $logger;
77
78    private WANObjectCache $cache;
79    private MathConfig $mathConfig;
80    private bool $rawError = false;
81
82    public function setRawError( bool $rawError ): void {
83        $this->rawError = $rawError;
84    }
85
86    /**
87     * Constructs a base MathRenderer
88     *
89     * @param string $tex (optional) LaTeX markup
90     * @param array $params (optional) HTML attributes
91     * @param WANObjectCache|null $cache (optional)
92     * @param MathConfig|null $mathConfig (optional)
93     */
94    public function __construct( string $tex = '', $params = [], $cache = null, $mathConfig = null ) {
95        $this->cache = $cache ?? MediaWikiServices::getInstance()->getMainWANObjectCache();
96        $this->mathConfig = $mathConfig ?? Math::getMathConfig();
97        $this->params = $params;
98        if ( isset( $params['id'] ) ) {
99            $this->id = $params['id'];
100        }
101        if ( isset( $params['display'] ) ) {
102            $layoutMode = $params['display'];
103            if ( $layoutMode == 'block' ) {
104                $this->mathStyle = 'display';
105                $tex = '{\displaystyle ' . $tex . '}';
106                $this->inputType = 'tex';
107            } elseif ( $layoutMode == 'inline' ) {
108                $this->mathStyle = 'inline';
109                $this->inputType = 'inline-tex';
110                $tex = '{\textstyle ' . $tex . '}';
111            } elseif ( $layoutMode == 'linebreak' ) {
112                $this->mathStyle = 'linebreak';
113                $tex = '\[ ' . $tex . ' \]';
114            }
115        }
116        // TODO: Implement caching for attributes of the math tag
117        // Currently the key for the database entry relating to an equation
118        // is md5($tex) the new option to determine if the tex input
119        // is rendered in displaystyle or textstyle would require a database
120        // layout change to use a composite key e.g. (md5($tex),$mathStyle).
121        // As a workaround we use the prefix \displaystyle so that the key becomes
122        // md5((\{\\displaystyle|\{\\textstyle)?\s?$tex\}?)
123        // The new value of $tex string describes now how the rendering should look like.
124        // The variable MathRenderer::mathStyle determines if the rendered equation should
125        // be centered in a new line, or just in be displayed in the current line.
126        $this->userInputTex = $tex;
127        $this->tex = $tex;
128        $this->logger = LoggerFactory::getInstance( 'Math' );
129    }
130
131    /**
132     * Static factory method for getting a renderer based on mode
133     *
134     * @deprecated since 3.0.0. Use Math.RendererFactory service instead.
135     * @param string $tex LaTeX markup
136     * @param array $params HTML attributes
137     * @param string $mode indicating rendering mode
138     * @return self appropriate renderer for mode
139     */
140    public static function getRenderer( $tex, $params = [], $mode = MathConfig::MODE_MATHML ) {
141        return MediaWikiServices::getInstance()
142            ->get( 'Math.RendererFactory' )
143            ->getRenderer( $tex, $params, $mode );
144    }
145
146    /**
147     * Performs the rendering
148     *
149     * @return bool if rendering was successful.
150     */
151    abstract public function render();
152
153    /**
154     * @param bool $svg
155     * @return string Html output that is embedded in the page
156     */
157    abstract public function getHtmlOutput( bool $svg = true ): string;
158
159    /**
160     * texvc error messages
161     * TODO: update to MathML
162     * Returns an internationalized HTML error string
163     *
164     * @param string $msg message key for specific error
165     * @param string ...$parameters zero or more message
166     *  parameters for specific error
167     *
168     * @return string HTML error string
169     */
170    public function getError( $msg, ...$parameters ) {
171        if ( $this->rawError ) {
172            return 'Error: ' . $msg . ' param ' . implode( ',', $parameters );
173        }
174        $mf = wfMessage( 'math_failure' )->inContentLanguage()->escaped();
175        $errmsg = wfMessage( $msg, $parameters )->inContentLanguage()->escaped();
176        $source = htmlspecialchars( str_replace( "\n", ' ', $this->tex ) );
177        return "<strong class=\"error texerror\">$mf ($errmsg): $source</strong>\n";
178    }
179
180    /**
181     * Return hash of input
182     *
183     * @return string hash
184     */
185    public function getInputHash(): string {
186        if ( !$this->inputHash ) {
187            $this->inputHash = hash( 'md5', // xxh128 might be better when dropping php 7 support
188                $this->mode .
189                $this->userInputTex .
190                implode( $this->params )
191            );
192        }
193        return $this->inputHash;
194    }
195
196    /**
197     * Reads rendering data from database
198     *
199     * @return bool true if read successfully, false otherwise
200     */
201    public function readFromCache(): bool {
202        $rpage = $this->cache->get( $this->getCacheKey() );
203        if ( $rpage !== false ) {
204            $this->initializeFromCache( $rpage );
205            return true;
206        } else {
207            # Missing from the database and/or the render cache
208            return false;
209        }
210    }
211
212    /**
213     * @return array with the database column names
214     */
215    protected function dbInArray() {
216        $in = [ 'math_inputhash',
217            'math_mathml',
218            'math_inputtex',
219            'math_tex',
220            'math_svg'
221        ];
222        return $in;
223    }
224
225    /**
226     * Reads the values from the database but does not overwrite set values with empty values
227     * @param array $rpage (a database row)
228     */
229    public function initializeFromCache( $rpage ) {
230        $this->inputHash = $rpage['math_inputhash']; // MUST NOT BE NULL
231        if ( isset( $rpage['math_mathml'] ) ) {
232            $this->mathml = $rpage['math_mathml'];
233        }
234        if ( isset( $rpage['math_inputtex'] ) ) {
235            $this->userInputTex = $rpage['math_inputtex'];
236        }
237        if ( isset( $rpage['math_tex'] ) ) {
238            $this->tex = $rpage['math_tex'];
239        }
240        if ( isset( $rpage['math_svg'] ) ) {
241            $this->svg = $rpage['math_svg'];
242        }
243        $this->changed = false;
244    }
245
246    /**
247     * Writes rendering entry to cache.
248     *
249     * WARNING: Use writeCache() instead of this method to be sure that all
250     * renderer specific (such as squid caching) are taken into account.
251     * This function stores the values that are currently present in the class
252     * to the cache even if they are empty.
253     *
254     * This function can be seen as protected function.
255     */
256    public function writeToCache() {
257        $outArray = $this->dbOutArray();
258        $this->cache->set( $this->getCacheKey(), $outArray );
259    }
260
261    /**
262     * Gets an array that matches the variables of the class to the database columns
263     * @return array
264     */
265    protected function dbOutArray() {
266        $out = [
267            'math_inputhash' => $this->getInputHash(),
268            'math_mathml' => $this->mathml,
269            'math_inputtex' => $this->userInputTex,
270            'math_tex' => $this->tex,
271            'math_svg' => $this->svg,
272            'math_mode' => $this->mode
273        ];
274        return $out;
275    }
276
277    /**
278     * @param MathRestbaseInterface $param
279     */
280    public function setRestbaseInterface( $param ) {
281        $this->rbi = $param;
282        $this->rbi->setPurge( $this->isPurge() );
283    }
284
285    public function hasWarnings(): bool {
286        if ( is_array( $this->warnings ) && count( $this->warnings ) ) {
287            return true;
288        }
289
290        return false;
291    }
292
293    /**
294     * Adds tracking categories to the parser
295     *
296     * @param Parser $parser
297     */
298    public function addTrackingCategories( $parser ) {
299        if ( !$this->checkTeX() ) {
300            $parser->addTrackingCategory( 'math-tracking-category-error' );
301        }
302        if ( $this->lastError ) {
303            // Add a tracking category specialized on render errors.
304            $parser->addTrackingCategory( 'math-tracking-category-render-error' );
305        }
306    }
307
308    protected function getChecker(): BaseChecker {
309        return Math::getCheckerFactory()
310            ->newDefaultChecker( $this->tex, $this->getInputType(), $this->rbi, $this->isPurge() );
311    }
312
313    /**
314     * Returns sanitized attributes
315     *
316     * @param string $tag element name
317     * @param array $defaults default attributes
318     * @param array $overrides attributes to override defaults
319     * @return array HTML attributes
320     */
321    protected function getAttributes( $tag, $defaults = [], $overrides = [] ) {
322        $attribs = Sanitizer::validateTagAttributes( $this->params, $tag );
323        $attribs = Sanitizer::mergeAttributes( $defaults, $attribs );
324        return Sanitizer::mergeAttributes( $attribs, $overrides );
325    }
326
327    /**
328     * Writes cache. Writes the database entry if values were changed
329     * @return bool
330     */
331    public function writeCache() {
332        $this->debug( 'Writing of cache requested' );
333        if ( $this->isChanged() ) {
334            $this->debug( 'Change detected. Perform writing' );
335            $this->writeToCache();
336            return true;
337        } else {
338            $this->debug( "Nothing was changed. Don't write to database" );
339            return false;
340        }
341    }
342
343    /**
344     * Gets TeX markup
345     *
346     * @return string TeX markup
347     */
348    public function getTex() {
349        return $this->tex;
350    }
351
352    /**
353     * Gets the rendering mode
354     *
355     * @return string
356     */
357    public function getMode() {
358        return $this->mode;
359    }
360
361    /**
362     * Sets the rendering mode
363     * @param string $newMode element of the array $wgMathValidModes
364     * @return bool
365     */
366    public function setMode( string $newMode ): bool {
367        if ( $this->mathConfig->isValidRenderingMode( $newMode ) ) {
368            $this->mode = $newMode;
369            return true;
370        } else {
371            return false;
372        }
373    }
374
375    /**
376     * Sets the TeX code
377     *
378     * @param ?string $tex
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}