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