Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
87.69% |
57 / 65 |
|
60.00% |
6 / 10 |
CRAP | |
0.00% |
0 / 1 |
LocalChecker | |
87.69% |
57 / 65 |
|
60.00% |
6 / 10 |
20.75 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
isValid | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getValidTex | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
run | |
95.65% |
22 / 23 |
|
0.00% |
0 / 1 |
6 | |||
getError | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getPresentationMathMLFragment | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getInputCacheKey | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
runCheck | |
80.00% |
20 / 25 |
|
0.00% |
0 / 1 |
6.29 | |||
setContext | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setHookContainer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\Math\InputCheck; |
4 | |
5 | use Exception; |
6 | use MediaWiki\Extension\Math\Hooks\HookRunner; |
7 | use MediaWiki\Extension\Math\MathRenderer; |
8 | use MediaWiki\Extension\Math\WikiTexVC\TexVC; |
9 | use MediaWiki\HookContainer\HookContainer; |
10 | use MediaWiki\Message\Message; |
11 | use Wikimedia\ObjectCache\WANObjectCache; |
12 | |
13 | class LocalChecker extends BaseChecker { |
14 | |
15 | public const VERSION = 1; |
16 | private const VALID_TYPES = [ 'tex', 'inline-tex', 'chem' ]; |
17 | private ?Message $error = null; |
18 | private ?string $mathMl = null; |
19 | |
20 | private string $type; |
21 | private WANObjectCache $cache; |
22 | |
23 | private bool $isChecked = false; |
24 | private ?MathRenderer $context = null; |
25 | private ?HookContainer $hookContainer = null; |
26 | |
27 | public function __construct( WANObjectCache $cache, $tex = '', string $type = 'tex', bool $purge = false ) { |
28 | $this->cache = $cache; |
29 | parent::__construct( $tex, $purge ); |
30 | $this->type = $type; |
31 | } |
32 | |
33 | public function isValid(): bool { |
34 | $this->run(); |
35 | return parent::isValid(); |
36 | } |
37 | |
38 | public function getValidTex(): ?string { |
39 | $this->run(); |
40 | return parent::getValidTex(); |
41 | } |
42 | |
43 | public function run() { |
44 | if ( $this->isChecked ) { |
45 | return; |
46 | } |
47 | if ( !in_array( $this->type, self::VALID_TYPES, true ) ) { |
48 | $this->error = $this->errorObjectToMessage( |
49 | (object)[ "error" => "Unsupported type passed to LocalChecker: " . $this->type ], "LocalCheck" ); |
50 | return; |
51 | } |
52 | try { |
53 | $cacheInputKey = $this->getInputCacheKey(); |
54 | if ( $this->purge ) { |
55 | $this->cache->delete( $cacheInputKey, WANObjectCache::TTL_INDEFINITE ); |
56 | } |
57 | $result = $this->cache->getWithSetCallback( |
58 | $cacheInputKey, |
59 | WANObjectCache::TTL_INDEFINITE, |
60 | [ $this, 'runCheck' ], |
61 | [ 'version' => self::VERSION ], |
62 | ); |
63 | } catch ( Exception $e ) { // @codeCoverageIgnoreStart |
64 | // This is impossible since errors are thrown only if the option debug would be set. |
65 | $this->error = Message::newFromKey( 'math_failure' ); |
66 | return; |
67 | // @codeCoverageIgnoreEnd |
68 | } |
69 | if ( $result['status'] === '+' ) { |
70 | $this->isValid = true; |
71 | $this->validTeX = $result['output']; |
72 | $this->mathMl = $result['mathml']; |
73 | } else { |
74 | $this->error = $this->errorObjectToMessage( |
75 | (object)[ "error" => (object)$result["error"] ], |
76 | "LocalCheck" ); |
77 | } |
78 | $this->isChecked = true; |
79 | } |
80 | |
81 | /** |
82 | * Returns the string of the last error. |
83 | * @return ?Message |
84 | */ |
85 | public function getError(): ?Message { |
86 | $this->run(); |
87 | return $this->error; |
88 | } |
89 | |
90 | public function getPresentationMathMLFragment(): ?string { |
91 | $this->run(); |
92 | return $this->mathMl; |
93 | } |
94 | |
95 | public function getInputCacheKey(): string { |
96 | return $this->cache->makeGlobalKey( |
97 | self::class, |
98 | md5( $this->type . '-' . $this->inputTeX ) |
99 | ); |
100 | } |
101 | |
102 | public function runCheck(): array { |
103 | if ( $this->type == 'chem' ) { |
104 | $options = [ 'usemhchem' => true, 'usemhchemtexified' => true ]; |
105 | $texifyMhchem = true; |
106 | } else { |
107 | $options = []; |
108 | $texifyMhchem = false; |
109 | } |
110 | |
111 | try { |
112 | $warnings = []; |
113 | $result = ( new TexVC() )->check( $this->inputTeX, $options, $warnings, $texifyMhchem ); |
114 | } catch ( Exception $e ) { // @codeCoverageIgnoreStart |
115 | // This is impossible since errors are thrown only if the option debug would be set. |
116 | $this->error = Message::newFromKey( 'math_failure' ); |
117 | |
118 | return []; |
119 | // @codeCoverageIgnoreEnd |
120 | } |
121 | if ( $result['status'] === '+' ) { |
122 | $result['mathml'] = $result['input']->renderMML(); |
123 | $out = [ |
124 | 'status' => '+', |
125 | 'output' => $result['output'], |
126 | 'mathml' => $result['mathml'] |
127 | ]; |
128 | } else { |
129 | $out = [ |
130 | 'status' => $result['status'], |
131 | 'error' => $result['error'], |
132 | ]; |
133 | } |
134 | if ( $this->context !== null && $this->hookContainer !== null ) { |
135 | $resultObject = (object)$result; |
136 | ( new HookRunner( $this->hookContainer ) )->onMathRenderingResultRetrieved( |
137 | $this->context, |
138 | $resultObject |
139 | ); |
140 | } |
141 | return $out; |
142 | } |
143 | |
144 | public function setContext( ?MathRenderer $renderer ): void { |
145 | $this->context = $renderer; |
146 | } |
147 | |
148 | public function setHookContainer( ?HookContainer $hookContainer ): void { |
149 | $this->hookContainer = $hookContainer; |
150 | } |
151 | } |