Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
4.17% |
9 / 216 |
|
0.00% |
0 / 18 |
CRAP | |
0.00% |
0 / 1 |
MathSearchHooks | |
4.17% |
9 / 216 |
|
0.00% |
0 / 18 |
2431.89 | |
0.00% |
0 / 1 |
onLoadExtensionSchemaUpdates | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
12 | |||
updateIndex | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
42 | |||
setMathId | |
8.33% |
1 / 12 |
|
0.00% |
0 / 1 |
24.26 | |||
updateMathIndex | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
addIdentifierDescription | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
addLinkToFormulaInfoPage | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
onMathFormulaRenderedNoLink | |
88.89% |
8 / 9 |
|
0.00% |
0 / 1 |
4.02 | |||
generateMathAnchorString | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
writeMathIndex | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
onParserFirstCallInit | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
mQueryTagHook | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
onArticleDeleteComplete | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
onArticleUndelete | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
onPageSaveComplete | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
30 | |||
onPageContentSaveComplete | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
registerExtension | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getRevIdGenerator | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getMwsHarvest | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | use MediaWiki\Extension\Math\MathLaTeXML; |
4 | use MediaWiki\Extension\Math\MathRenderer; |
5 | use MediaWiki\Logger\LoggerFactory; |
6 | use MediaWiki\MediaWikiServices; |
7 | use MediaWiki\Revision\RevisionRecord; |
8 | use MediaWiki\Revision\SlotRecord; |
9 | use Wikimedia\Rdbms\DBConnRef; |
10 | |
11 | /** |
12 | * MediaWiki MathSearch extension |
13 | * |
14 | * (c) 2012 various MediaWiki contributors |
15 | * GPLv2 license; info in main package. |
16 | */ |
17 | class MathSearchHooks { |
18 | |
19 | private static $idGenerators = []; |
20 | |
21 | /** |
22 | * LoadExtensionSchemaUpdates handler; set up math table on install/upgrade. |
23 | * |
24 | * @param DatabaseUpdater|null $updater |
25 | * @return bool |
26 | */ |
27 | public static function onLoadExtensionSchemaUpdates( DatabaseUpdater $updater = null ) { |
28 | global $wgMathWmcServer; |
29 | $type = $updater->getDB()->getType(); |
30 | if ( $type == "mysql" ) { |
31 | $dir = __DIR__ . '/../db/'; |
32 | $updater->addExtensionTable( 'mathindex', $dir . 'mathindex.sql' ); |
33 | $updater->addExtensionTable( 'mathobservation', $dir . 'mathobservation.sql' ); |
34 | $updater->addExtensionTable( 'mathvarstat', $dir . 'mathvarstat.sql' ); |
35 | $updater->addExtensionTable( 'mathrevisionstat', $dir . 'mathrevisionstat.sql' ); |
36 | $updater->addExtensionTable( 'mathsemantics', $dir . 'mathsemantics.sql' ); |
37 | $updater->addExtensionTable( 'mathperformance', $dir . 'mathperformance.sql' ); |
38 | $updater->addExtensionTable( 'mathidentifier', $dir . 'mathidentifier.sql' ); |
39 | $updater->addExtensionTable( 'mathlog', $dir . 'mathlog.sql' ); |
40 | $updater->addExtensionTable( 'math_mlp', $dir . 'math_mlp.sql' ); |
41 | $updater->addExtensionTable( 'math_review_list', "{$dir}math_review_list.sql" ); |
42 | $updater->addExtensionTable( 'math_wbs_entity_map', "{$dir}math_wbs_entity_map.sql" ); |
43 | $updater->addExtensionTable( 'math_wbs_text_store', "{$dir}math_wbs_text_store.sql" ); |
44 | $updater->addExtensionTable( 'mathpagesimilarity', "{$dir}mathpagesimilarity.sql" ); |
45 | if ( $wgMathWmcServer ) { |
46 | $wmcDir = $dir . 'wmc/persistent/'; |
47 | $updater->addExtensionTable( 'math_wmc_ref', $wmcDir . "math_wmc_ref.sql" ); |
48 | $updater->addExtensionTable( 'math_wmc_runs', $wmcDir . "math_wmc_runs.sql" ); |
49 | $updater->addExtensionTable( 'math_wmc_results', $wmcDir . "math_wmc_results.sql" ); |
50 | $updater->addExtensionTable( 'math_wmc_assessed_formula', |
51 | $wmcDir . "math_wmc_assessed_formula.sql" ); |
52 | $updater->addExtensionTable( 'math_wmc_assessed_revision', |
53 | $wmcDir . "math_wmc_assessed_revision.sql" ); |
54 | |
55 | } |
56 | } else { |
57 | throw new Exception( "MathSearch extension does not currently support $type database." ); |
58 | } |
59 | return true; |
60 | } |
61 | |
62 | /** |
63 | * Updates the formula index in the database |
64 | * |
65 | * @param int $revId Page-ID |
66 | * @param string $eid Equation-ID (get updated incrementally for every math element on the page) |
67 | * @param MathRenderer $renderer |
68 | * @param ?DBConnRef $dbr |
69 | */ |
70 | private static function updateIndex( int $revId, string $eid, MathRenderer $renderer, |
71 | ?DBConnRef $dbr = null ) { |
72 | if ( $revId > 0 && $eid ) { |
73 | try { |
74 | $inputHash = $renderer->getInputHash(); |
75 | $tex = $renderer->getTex(); |
76 | $mo = MathObject::cloneFromRenderer( $renderer ); |
77 | if ( !$mo->isInDatabase() ) { |
78 | $mo->writeToCache(); |
79 | } |
80 | $exists = ( $dbr ?? MediaWikiServices::getInstance()->getDBLoadBalancerFactory() |
81 | ->getReplicaDatabase() )->selectRow( 'mathindex', |
82 | [ 'mathindex_revision_id', 'mathindex_anchor', 'mathindex_inputhash' ], |
83 | [ |
84 | 'mathindex_revision_id' => $revId, |
85 | 'mathindex_anchor' => $eid, |
86 | 'mathindex_inputhash' => $inputHash |
87 | ] |
88 | ); |
89 | if ( $exists ) { |
90 | LoggerFactory::getInstance( |
91 | 'MathSearch' |
92 | )->warning( 'Index $' . $tex . '$ already in database.' ); |
93 | LoggerFactory::getInstance( |
94 | 'MathSearch' |
95 | )->warning( "$revId-$eid with hash " . bin2hex( $inputHash ) ); |
96 | } else { |
97 | self::writeMathIndex( $revId, $eid, $inputHash, $tex ); |
98 | } |
99 | } catch ( Exception $e ) { |
100 | LoggerFactory::getInstance( "MathSearch" )->error( 'Problem writing to math index!' |
101 | . ' You might want the rebuild the index by running:' |
102 | . '"php extensions/MathSearch/ReRenderMath.php". The error is' |
103 | . $e->getMessage() ); |
104 | } |
105 | } |
106 | } |
107 | |
108 | /** |
109 | * Changes the specified defaultID given as argument ID to |
110 | * either the manually assignedID from the MathTag or |
111 | * prefixes it with "math" to increase the probability of |
112 | * having a unique id that can be referenced via the anchor |
113 | * #math{$id}. |
114 | * @param string &$id |
115 | * @param MathRenderer $renderer |
116 | * @param int $revId |
117 | * @return bool|null true if an ID has been assigned manually, |
118 | * false if the automatic fallback math{$id} was used. |
119 | */ |
120 | public static function setMathId( &$id, MathRenderer $renderer, $revId ) { |
121 | if ( $revId > 0 ) { |
122 | if ( $renderer->getID() ) { |
123 | $id = $renderer->getID(); |
124 | return true; |
125 | } else { |
126 | if ( $id === null ) { |
127 | try { |
128 | $id = self::getRevIdGenerator( $revId )->guessIdFromContent( $renderer->getUserInputTex() ); |
129 | } catch ( Exception $e ) { |
130 | LoggerFactory::getInstance( "MathSearch" )->warning( "Error generating Math ID", [ $e ] ); |
131 | return false; |
132 | } |
133 | $renderer->setID( $id ); |
134 | return true; |
135 | } |
136 | return false; |
137 | } |
138 | } |
139 | } |
140 | |
141 | /** |
142 | * Callback function that is called after a formula was rendered |
143 | * @param Parser $parser |
144 | * @param MathRenderer $renderer |
145 | * @param string|null &$Result reference to the rendering result |
146 | * @return bool |
147 | */ |
148 | static function updateMathIndex( Parser $parser, MathRenderer $renderer, &$Result = null ) { |
149 | $revId = $parser->getRevisionId(); |
150 | // Only store something if a pageid was set. |
151 | if ( $revId <= 0 ) { |
152 | return true; |
153 | } |
154 | // Use manually assigned IDs whenever possible |
155 | // and fallback to automatic IDs otherwise. |
156 | $hasEid = self::setMathId( $eid, $renderer, $revId ); |
157 | if ( $eid === null ) { |
158 | return true; |
159 | } |
160 | if ( $hasEid === false ) { |
161 | $Result = |
162 | preg_replace( '/(class="mwe-math-mathml-(inline|display))/', "id=\"$eid\" \\1", |
163 | $Result ); |
164 | } |
165 | self::updateIndex( $revId, $eid, $renderer ); |
166 | |
167 | return true; |
168 | } |
169 | |
170 | /** |
171 | * Callback function that is called after a formula was rendered |
172 | * @param Parser $parser |
173 | * @param MathRenderer $renderer |
174 | * @param string|null &$Result reference to the rendering result |
175 | * @return bool |
176 | */ |
177 | static function addIdentifierDescription( |
178 | Parser $parser, MathRenderer $renderer, &$Result = null |
179 | ) { |
180 | $revId = $parser->getRevisionId(); |
181 | self::setMathId( $eid, $renderer, $revId ); |
182 | $mo = MathObject::cloneFromRenderer( $renderer ); |
183 | $mo->setRevisionID( $revId ); |
184 | $mo->setID( $eid ); |
185 | $Result = preg_replace_callback( "#<(mi|mo)( ([^>].*?))?>(.*?)</\\1>#u", |
186 | [ $mo, 'addIdentifierTitle' ], $Result ); |
187 | return true; |
188 | } |
189 | |
190 | /** |
191 | * Callback function that is called after a formula was rendered |
192 | * @param Parser $parser |
193 | * @param MathRenderer $renderer |
194 | * @param string|null &$Result reference to the rendering result |
195 | * @return bool |
196 | */ |
197 | static function addLinkToFormulaInfoPage( |
198 | Parser $parser, MathRenderer $renderer, &$Result = null |
199 | ) { |
200 | global $wgMathSearchInfoPage; |
201 | $revId = $parser->getRevisionId(); |
202 | if ( $revId == 0 || self::setMathId( $eid, $renderer, $revId ) === false ) { |
203 | return true; |
204 | } |
205 | $url = SpecialPage::getTitleFor( $wgMathSearchInfoPage )->getLocalURL( [ |
206 | 'pid' => $revId, |
207 | 'eid' => $eid |
208 | ] ); |
209 | $Result = "<span><a href=\"$url\" id=\"$eid\" style=\"color:inherit;\">$Result</a></span>"; |
210 | return true; |
211 | } |
212 | |
213 | /** |
214 | * Alternative Callback function that is called after a formula was rendered |
215 | * used for test corpus generation for NTCIR11 Math-2 |
216 | * You can enable this alternative hook via setting |
217 | * <code>$wgHooks['MathFormulaRendered'] = array( |
218 | * 'MathSearchHooks::onMathFormulaRenderedNoLink' |
219 | * );</code> |
220 | * in your local settings |
221 | * |
222 | * @param Parser $parser |
223 | * @param MathRenderer $renderer |
224 | * @param string|null &$Result |
225 | * @return bool |
226 | */ |
227 | static function onMathFormulaRenderedNoLink( |
228 | Parser $parser, MathRenderer $renderer, &$Result = null |
229 | ) { |
230 | $revId = $parser->getRevisionId(); |
231 | if ( !self::setMathId( $eid, $renderer, $revId ) ) { |
232 | return true; |
233 | } |
234 | if ( $revId > 0 ) { // Only store something if a pageid was set. |
235 | self::updateIndex( $revId, $eid, $renderer ); |
236 | } |
237 | if ( preg_match( '#<math(.*)?\sid="(?P<id>[\w\.]+)"#', $Result, $matches ) ) { |
238 | $rendererId = $matches['id']; |
239 | $Result = str_replace( $rendererId, $eid, $Result ); |
240 | } |
241 | return true; |
242 | } |
243 | |
244 | static function generateMathAnchorString( $revId, $anchorID, $prefix = "#" ) { |
245 | $result = "{$prefix}math.$revId.$anchorID"; |
246 | MediaWikiServices::getInstance()->getHookContainer()->run( "MathSearchGenerateAnchorString", |
247 | [ $revId, $anchorID, $prefix, &$result ] ); |
248 | return $result; |
249 | } |
250 | |
251 | /** |
252 | * @param int $oldID |
253 | * @param string $eid |
254 | * @param string $inputHash |
255 | * @param string $tex |
256 | */ |
257 | public static function writeMathIndex( $oldID, $eid, $inputHash, $tex ) { |
258 | LoggerFactory::getInstance( "MathSearch" )->warning( |
259 | "Store index for \$$tex\$ in database with id $eid for revision $oldID." ); |
260 | $dbw = MediaWikiServices::getInstance() |
261 | ->getConnectionProvider() |
262 | ->getPrimaryDatabase(); |
263 | $dbw->onTransactionCommitOrIdle( static function () use ( $oldID, $eid, $inputHash, $dbw ) { |
264 | $dbw->replace( 'mathindex', [ [ 'mathindex_revision_id', 'mathindex_anchor' ] ], [ |
265 | 'mathindex_revision_id' => $oldID, |
266 | 'mathindex_anchor' => $eid, |
267 | 'mathindex_inputhash' => $inputHash |
268 | ] ); |
269 | } ); |
270 | } |
271 | |
272 | /** |
273 | * Register the <mquery> tag with the Parser. |
274 | * |
275 | * @param Parser $parser instance of Parser |
276 | * @return bool true |
277 | */ |
278 | static function onParserFirstCallInit( $parser ) { |
279 | $parser->setHook( 'mquery', [ 'MathSearchHooks', 'mQueryTagHook' ] ); |
280 | LoggerFactory::getInstance( 'MathSearch' )->warning( 'mquery tag registered' ); |
281 | return true; |
282 | } |
283 | |
284 | /** |
285 | * Callback function for the <mquery> parser hook. |
286 | * |
287 | * @param string $content the LaTeX+MWS query input |
288 | * @param array $attributes |
289 | * @param Parser $parser |
290 | * @return string|string[] |
291 | */ |
292 | static function mQueryTagHook( $content, $attributes, $parser ) { |
293 | global $wgMathDefaultLaTeXMLSetting; |
294 | if ( trim( $content ) === '' ) { // bug 8372 |
295 | return ''; |
296 | } |
297 | LoggerFactory::getInstance( 'MathSearch' )->debug( 'Render mquery tag.' ); |
298 | // TODO: Report %\n problem to LaTeXML upstream |
299 | $content = preg_replace( '/%\n/', '', $content ); |
300 | $renderer = new MathLaTeXML( $content ); |
301 | $mQuerySettings = $wgMathDefaultLaTeXMLSetting; |
302 | $mQuerySettings['preload'][] = 'mws.sty'; |
303 | $renderer->setLaTeXMLSettings( $mQuerySettings ); |
304 | $renderer->render(); |
305 | $renderedMath = $renderer->getHtmlOutput(); |
306 | $renderer->writeCache(); |
307 | |
308 | return [ $renderedMath, "markerType" => 'nowiki' ]; |
309 | } |
310 | |
311 | static function onArticleDeleteComplete( |
312 | $article, User $user, $reason, $id, $content, $logEntry |
313 | ) { |
314 | $revId = $article->getTitle()->getLatestRevID(); |
315 | $mathEngineBaseX = new MathEngineBaseX(); |
316 | if ( $mathEngineBaseX->update( "", [ $revId ] ) ) { |
317 | LoggerFactory::getInstance( 'MathSearch' )->warning( "Deletion of $revId was successful." ); |
318 | } else { |
319 | LoggerFactory::getInstance( 'MathSearch' )->warning( "Deletion of $revId failed." ); |
320 | } |
321 | } |
322 | |
323 | /** |
324 | * This occurs when an article is undeleted (restored). |
325 | * The formulae of the undeleted article are restored then in the index. |
326 | * @param Title $title Title corresponding to the article restored |
327 | * @param bool $create Whether the restoration caused the page to be created. |
328 | * @param string $comment Comment explaining the undeletion. |
329 | * @param int $oldPageId ID of page previously deleted. ID will be used for restored page. |
330 | * @param array $restoredPages Set of page IDs that have revisions restored for undelete. |
331 | * @return true |
332 | */ |
333 | public static function onArticleUndelete( |
334 | Title $title, $create, $comment, $oldPageId, $restoredPages |
335 | ) { |
336 | if ( MediaWikiServices::getInstance() |
337 | ->getRevisionLookup() |
338 | ->getRevisionByPageId( $oldPageId ) |
339 | ->getSlot( SlotRecord::MAIN, RevisionRecord::RAW ) |
340 | ->getModel() !== CONTENT_MODEL_WIKITEXT |
341 | ) { |
342 | // Skip pages that do not contain wikitext |
343 | return true; |
344 | } |
345 | $revId = $title->getLatestRevID(); |
346 | $harvest = self::getMwsHarvest( $revId ); |
347 | $mathEngineBaseX = new MathEngineBaseX(); |
348 | if ( $mathEngineBaseX->update( $harvest, [] ) ) { |
349 | LoggerFactory::getInstance( 'MathSearch' )->warning( "Restoring of $revId was successful." ); |
350 | } else { |
351 | LoggerFactory::getInstance( 'MathSearch' )->warning( "Restoring of $revId failed." ); |
352 | } |
353 | return true; |
354 | } |
355 | |
356 | /** |
357 | * Occurs after the save page request has been processed. |
358 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageSaveComplete |
359 | * |
360 | * @param WikiPage $wikiPage |
361 | * @param MediaWiki\User\UserIdentity $user |
362 | * @param string $summary |
363 | * @param int $flags |
364 | * @param MediaWiki\Revision\RevisionRecord $revisionRecord |
365 | * |
366 | * @return bool |
367 | */ |
368 | public static function onPageSaveComplete( |
369 | WikiPage $wikiPage, $user, $summary, $flags, $revisionRecord |
370 | ) { |
371 | if ( $revisionRecord |
372 | ->getSlot( SlotRecord::MAIN, RevisionRecord::RAW ) |
373 | ->getModel() !== CONTENT_MODEL_WIKITEXT |
374 | ) { |
375 | // Skip pages that do not contain wikitext |
376 | return true; |
377 | } |
378 | |
379 | $revId = $revisionRecord->getId(); |
380 | $harvest = self::getMwsHarvest( $revId ); |
381 | $previousRevisionRecord = MediaWikiServices::getInstance() |
382 | ->getRevisionLookup() |
383 | ->getPreviousRevision( $revisionRecord ); |
384 | $res = false; |
385 | $baseXUpdater = new MathEngineBaseX(); |
386 | try { |
387 | if ( $previousRevisionRecord != null ) { |
388 | $prevRevId = $previousRevisionRecord->getId(); |
389 | # delete the entries previous revision. |
390 | $res = $baseXUpdater->update( $harvest, [ $prevRevId ] ); |
391 | } else { |
392 | # just create a new entry in index. |
393 | $res = $baseXUpdater->update( $harvest, [] ); |
394 | $prevRevId = -1; |
395 | } |
396 | } catch ( Exception $e ) { |
397 | LoggerFactory::getInstance( 'MathSearch' ) |
398 | ->warning( 'Harvest update failed: {exception}', |
399 | [ 'exception' => $e->getMessage() ] ); |
400 | } |
401 | if ( $res ) { |
402 | LoggerFactory::getInstance( |
403 | 'MathSearch' |
404 | )->warning( "Update for $revId (was $prevRevId) successful." ); |
405 | } else { |
406 | LoggerFactory::getInstance( |
407 | 'MathSearch' |
408 | )->warning( "Update for $revId (was $prevRevId) failed." ); |
409 | } |
410 | } |
411 | |
412 | /** |
413 | * Occurs after the save page request has been processed. |
414 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageContentSaveComplete |
415 | * @deprecated |
416 | * PageContentSaveComplete: legacy hook, deprecated in favor of PageSaveComplete |
417 | * |
418 | * @param WikiPage $wikiPage |
419 | * @param User $user |
420 | * @param Content $content |
421 | * @param string $summary |
422 | * @param bool $isMinor |
423 | * @param bool $isWatch |
424 | * @param string $section Deprecated |
425 | * @param int $flags |
426 | * @param Revision|null $revision |
427 | * @param Status $status |
428 | * @param int $baseRevId |
429 | * |
430 | * @return bool |
431 | */ |
432 | public static function onPageContentSaveComplete( |
433 | WikiPage $wikiPage, $user, $content, $summary, $isMinor, |
434 | $isWatch, $section, $flags, $revision, $status, $baseRevId |
435 | ) { |
436 | // TODO: Update to JOB |
437 | if ( $revision == null ) { |
438 | LoggerFactory::getInstance( |
439 | 'MathSearch' |
440 | )->warning( "Empty update for {$wikiPage->getTitle()->getFullText()}." ); |
441 | return true; |
442 | } |
443 | $revisionRecord = $revision->getRevisionRecord(); |
444 | self::onPageSaveComplete( $wikiPage, $user, $summary, $flags, $revisionRecord ); |
445 | |
446 | return true; |
447 | } |
448 | |
449 | /** |
450 | * Enable latexml rendering mode as option by default |
451 | */ |
452 | public static function registerExtension() { |
453 | global $wgMathValidModes, $wgHooks; |
454 | if ( !in_array( 'latexml', $wgMathValidModes ) ) { |
455 | $wgMathValidModes[] = 'latexml'; |
456 | } |
457 | if ( class_exists( MediaWiki\HookContainer\HookContainer::class ) ) { |
458 | // MW 1.35+ |
459 | $wgHooks['PageSaveComplete'][] = 'MathSearchHooks::onPageSaveComplete'; |
460 | } else { |
461 | $wgHooks['PageContentSaveComplete'][] = 'MathSearchHooks::onPageContentSaveComplete'; |
462 | } |
463 | } |
464 | |
465 | /** |
466 | * @param int $revId |
467 | * @return MathIdGenerator |
468 | */ |
469 | private static function getRevIdGenerator( $revId ) { |
470 | if ( !array_key_exists( $revId, self::$idGenerators ) ) { |
471 | self::$idGenerators[$revId] = MathIdGenerator::newFromRevisionId( $revId ); |
472 | } |
473 | return self::$idGenerators[$revId]; |
474 | } |
475 | |
476 | /** |
477 | * @param int|null $revId |
478 | * @return string |
479 | */ |
480 | protected static function getMwsHarvest( ?int $revId ): string { |
481 | $idGenerator = MathIdGenerator::newFromRevisionId( $revId ); |
482 | $mathTags = $idGenerator->getMathTags(); |
483 | $harvest = ""; |
484 | try { |
485 | if ( $mathTags ) { |
486 | $dw = new MwsDumpWriter(); |
487 | foreach ( $mathTags as $tag ) { |
488 | $id = null; |
489 | $tagContent = $tag[MathIdGenerator::CONTENT_POS]; |
490 | $attributes = $tag[MathIdGenerator::ATTRIB_POS]; |
491 | $renderer = MathRenderer::getRenderer( $tagContent, $attributes, 'latexml' ); |
492 | $renderer->render(); |
493 | self::setMathId( $id, $renderer, $revId ); |
494 | $dw->addMwsExpression( $renderer->getMathml(), $revId, $id ); |
495 | } |
496 | $harvest = $dw->getOutput(); |
497 | } |
498 | } catch ( Exception $e ) { |
499 | LoggerFactory::getInstance( 'MathSearch' ) |
500 | ->warning( 'Harvest strinc can not be generated: {exception}', |
501 | [ 'exception' => $e->getMessage() ] ); |
502 | } |
503 | return $harvest; |
504 | } |
505 | } |