MediaWiki  master
RenderedRevisionTest.php
Go to the documentation of this file.
1 <?php
2 
4 
21 use Title;
22 use User;
25 
30 
33 
34  public function setUp() {
35  parent::setUp();
36 
37  $this->combinerCallback = function ( RenderedRevision $rr, array $hints = [] ) {
38  return $this->combineOutput( $rr, $hints );
39  };
40  }
41 
42  private function combineOutput( RenderedRevision $rrev, array $hints = [] ) {
43  // NOTE: the is a slightly simplified version of RevisionRenderer::combineSlotOutput
44 
45  $withHtml = $hints['generate-html'] ?? true;
46 
47  $revision = $rrev->getRevision();
48  $slots = $revision->getSlots()->getSlots();
49 
50  $combinedOutput = new ParserOutput( null );
51  $slotOutput = [];
52  foreach ( $slots as $role => $slot ) {
53  $out = $rrev->getSlotParserOutput( $role, $hints );
54  $slotOutput[$role] = $out;
55 
56  $combinedOutput->mergeInternalMetaDataFrom( $out );
57  $combinedOutput->mergeTrackingMetaDataFrom( $out );
58  }
59 
60  if ( $withHtml ) {
61  $html = '';
63  foreach ( $slotOutput as $role => $out ) {
64 
65  if ( $html !== '' ) {
66  // skip header for the first slot
67  $html .= "(($role))";
68  }
69 
70  $html .= $out->getRawText();
71  $combinedOutput->mergeHtmlMetaDataFrom( $out );
72  }
73 
74  $combinedOutput->setText( $html );
75  }
76 
77  return $combinedOutput;
78  }
79 
85  private function getMockTitle( $articleId, $revisionId ) {
87  $mock = $this->getMockBuilder( Title::class )
88  ->disableOriginalConstructor()
89  ->getMock();
90  $mock->expects( $this->any() )
91  ->method( 'getNamespace' )
92  ->will( $this->returnValue( NS_MAIN ) );
93  $mock->expects( $this->any() )
94  ->method( 'getText' )
95  ->will( $this->returnValue( 'RenderTestPage' ) );
96  $mock->expects( $this->any() )
97  ->method( 'getPrefixedText' )
98  ->will( $this->returnValue( 'RenderTestPage' ) );
99  $mock->expects( $this->any() )
100  ->method( 'getDBkey' )
101  ->will( $this->returnValue( 'RenderTestPage' ) );
102  $mock->expects( $this->any() )
103  ->method( 'getArticleID' )
104  ->will( $this->returnValue( $articleId ) );
105  $mock->expects( $this->any() )
106  ->method( 'getLatestRevId' )
107  ->will( $this->returnValue( $revisionId ) );
108  $mock->expects( $this->any() )
109  ->method( 'getContentModel' )
110  ->will( $this->returnValue( CONTENT_MODEL_WIKITEXT ) );
111  $mock->expects( $this->any() )
112  ->method( 'getPageLanguage' )
113  ->will( $this->returnValue( Language::factory( 'en' ) ) );
114  $mock->expects( $this->any() )
115  ->method( 'isContentPage' )
116  ->will( $this->returnValue( true ) );
117  $mock->expects( $this->any() )
118  ->method( 'equals' )
119  ->willReturnCallback( function ( Title $other ) use ( $mock ) {
120  return $mock->getPrefixedText() === $other->getPrefixedText();
121  } );
122  $mock->expects( $this->any() )
123  ->method( 'userCan' )
124  ->willReturnCallback( function ( $perm, User $user ) use ( $mock ) {
125  return $user->isAllowed( $perm );
126  } );
127 
128  return $mock;
129  }
130 
138  private function getMockRevision(
139  $class,
140  $title,
141  $id = null,
142  $visibility = 0,
143  array $content = null
144  ) {
145  $frank = new UserIdentityValue( 9, 'Frank', 0 );
146 
147  if ( !$content ) {
148  $text = "";
149  $text .= "* page:{{PAGENAME}}!\n";
150  $text .= "* rev:{{REVISIONID}}!\n";
151  $text .= "* user:{{REVISIONUSER}}!\n";
152  $text .= "* time:{{REVISIONTIMESTAMP}}!\n";
153  $text .= "* [[Link It]]\n";
154 
155  $content = [ 'main' => new WikitextContent( $text ) ];
156  }
157 
159  $mock = $this->getMockBuilder( $class )
160  ->disableOriginalConstructor()
161  ->setMethods( [
162  'getId',
163  'getPageId',
164  'getPageAsLinkTarget',
165  'getUser',
166  'getVisibility',
167  'getTimestamp',
168  ] )->getMock();
169 
170  $mock->method( 'getId' )->willReturn( $id );
171  $mock->method( 'getPageId' )->willReturn( $title->getArticleID() );
172  $mock->method( 'getPageAsLinkTarget' )->willReturn( $title );
173  $mock->method( 'getUser' )->willReturn( $frank );
174  $mock->method( 'getVisibility' )->willReturn( $visibility );
175  $mock->method( 'getTimestamp' )->willReturn( '20180101000003' );
176 
178  $mockAccess = TestingAccessWrapper::newFromObject( $mock );
179  $mockAccess->mSlots = new MutableRevisionSlots();
180 
181  foreach ( $content as $role => $cnt ) {
182  $mockAccess->mSlots->setContent( $role, $cnt );
183  }
184 
185  return $mock;
186  }
187 
189  $title = $this->getMockTitle( 0, 21 );
191 
192  $options = ParserOptions::newCanonical( 'canonical' );
193  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
194 
195  $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
196 
197  $this->assertSame( $rev, $rr->getRevision() );
198  $this->assertSame( $options, $rr->getOptions() );
199 
200  $html = $rr->getRevisionParserOutput()->getText();
201 
202  $this->assertContains( 'page:RenderTestPage!', $html );
203  $this->assertContains( 'user:Frank!', $html );
204  $this->assertContains( 'time:20180101000003!', $html );
205  }
206 
208  $title = $this->getMockTitle( 0, 21 );
209  $name = $title->getPrefixedText();
210 
211  $text = "(ONE)<includeonly>(TWO)</includeonly><noinclude>#{{:$name}}#</noinclude>";
212 
213  $content = [
214  'main' => new WikitextContent( $text )
215  ];
216 
218 
219  $options = ParserOptions::newCanonical( 'canonical' );
220  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
221 
222  $html = $rr->getRevisionParserOutput()->getText();
223  $this->assertContains( '(ONE)#(ONE)(TWO)#', $html );
224  }
225 
227  $title = $this->getMockTitle( 7, 21 );
229 
230  $options = ParserOptions::newCanonical( 'canonical' );
231  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
232 
233  $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
234 
235  $this->assertSame( $rev, $rr->getRevision() );
236  $this->assertSame( $options, $rr->getOptions() );
237 
238  $html = $rr->getRevisionParserOutput()->getText();
239 
240  $this->assertContains( 'page:RenderTestPage!', $html );
241  $this->assertContains( 'rev:21!', $html );
242  $this->assertContains( 'user:Frank!', $html );
243  $this->assertContains( 'time:20180101000003!', $html );
244 
245  $this->assertSame( $html, $rr->getSlotParserOutput( SlotRecord::MAIN )->getText() );
246  }
247 
249  $title = $this->getMockTitle( 7, 21 );
251 
252  $options = ParserOptions::newCanonical( 'canonical' );
253  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
254 
255  $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
256 
257  $this->assertSame( $rev, $rr->getRevision() );
258  $this->assertSame( $options, $rr->getOptions() );
259 
260  $html = $rr->getRevisionParserOutput()->getText();
261 
262  $this->assertContains( 'page:RenderTestPage!', $html );
263  $this->assertContains( 'rev:11!', $html );
264  $this->assertContains( 'user:Frank!', $html );
265  $this->assertContains( 'time:20180101000003!', $html );
266 
267  $this->assertSame( $html, $rr->getSlotParserOutput( SlotRecord::MAIN )->getText() );
268  }
269 
271  $title = $this->getMockTitle( 7, 21 );
273 
274  $options = ParserOptions::newCanonical( 'canonical' );
275  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
276 
277  $this->assertFalse( $rr->isContentDeleted(), 'isContentDeleted' );
278 
279  $this->assertSame( $rev, $rr->getRevision() );
280  $this->assertSame( $options, $rr->getOptions() );
281 
282  $html = $rr->getRevisionParserOutput()->getText();
283 
284  $this->assertContains( 'page:RenderTestPage!', $html );
285  $this->assertContains( 'rev:11!', $html );
286  $this->assertContains( 'user:Frank!', $html );
287  $this->assertContains( 'time:20180101000003!', $html );
288 
289  $this->assertSame( $html, $rr->getSlotParserOutput( SlotRecord::MAIN )->getText() );
290  }
291 
293  $title = $this->getMockTitle( 7, 21 );
294  $rev = $this->getMockRevision(
296  $title,
297  11,
299  );
300 
301  $options = ParserOptions::newCanonical( 'canonical' );
302  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
303 
304  $this->setExpectedException( SuppressedDataException::class );
305  $rr->getRevisionParserOutput();
306  }
307 
309  $title = $this->getMockTitle( 7, 21 );
310  $rev = $this->getMockRevision(
312  $title,
313  11,
315  );
316 
317  $options = ParserOptions::newCanonical( 'canonical' );
318  $sysop = $this->getTestUser( [ 'sysop' ] )->getUser(); // privileged!
319  $rr = new RenderedRevision(
320  $title,
321  $rev,
322  $options,
323  $this->combinerCallback,
325  $sysop
326  );
327 
328  $this->assertTrue( $rr->isContentDeleted(), 'isContentDeleted' );
329 
330  $this->assertSame( $rev, $rr->getRevision() );
331  $this->assertSame( $options, $rr->getOptions() );
332 
333  $html = $rr->getRevisionParserOutput()->getText();
334 
335  // Suppressed content should be visible for sysops
336  $this->assertContains( 'page:RenderTestPage!', $html );
337  $this->assertContains( 'rev:11!', $html );
338  $this->assertContains( 'user:Frank!', $html );
339  $this->assertContains( 'time:20180101000003!', $html );
340 
341  $this->assertSame( $html, $rr->getSlotParserOutput( SlotRecord::MAIN )->getText() );
342  }
343 
345  $title = $this->getMockTitle( 7, 21 );
346  $rev = $this->getMockRevision(
348  $title,
349  11,
351  );
352 
353  $options = ParserOptions::newCanonical( 'canonical' );
354  $rr = new RenderedRevision(
355  $title,
356  $rev,
357  $options,
358  $this->combinerCallback,
360  );
361 
362  $this->assertTrue( $rr->isContentDeleted(), 'isContentDeleted' );
363 
364  $this->assertSame( $rev, $rr->getRevision() );
365  $this->assertSame( $options, $rr->getOptions() );
366 
367  $html = $rr->getRevisionParserOutput()->getText();
368 
369  // Suppressed content should be visible for sysops
370  $this->assertContains( 'page:RenderTestPage!', $html );
371  $this->assertContains( 'rev:11!', $html );
372  $this->assertContains( 'user:Frank!', $html );
373  $this->assertContains( 'time:20180101000003!', $html );
374 
375  $this->assertSame( $html, $rr->getSlotParserOutput( SlotRecord::MAIN )->getText() );
376  }
377 
379  $content = [
380  'main' => new WikitextContent( '[[Kittens]]' ),
381  'aux' => new WikitextContent( '[[Goats]]' ),
382  ];
383 
384  $title = $this->getMockTitle( 7, 21 );
386 
387  $options = ParserOptions::newCanonical( 'canonical' );
388  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
389 
390  $combinedOutput = $rr->getRevisionParserOutput();
391  $mainOutput = $rr->getSlotParserOutput( SlotRecord::MAIN );
392  $auxOutput = $rr->getSlotParserOutput( 'aux' );
393 
394  $combinedHtml = $combinedOutput->getText();
395  $mainHtml = $mainOutput->getText();
396  $auxHtml = $auxOutput->getText();
397 
398  $this->assertContains( 'Kittens', $mainHtml );
399  $this->assertContains( 'Goats', $auxHtml );
400  $this->assertNotContains( 'Goats', $mainHtml );
401  $this->assertNotContains( 'Kittens', $auxHtml );
402  $this->assertContains( 'Kittens', $combinedHtml );
403  $this->assertContains( 'Goats', $combinedHtml );
404  $this->assertContains( 'aux', $combinedHtml, 'slot section header' );
405 
406  $combinedLinks = $combinedOutput->getLinks();
407  $mainLinks = $mainOutput->getLinks();
408  $auxLinks = $auxOutput->getLinks();
409  $this->assertTrue( isset( $combinedLinks[NS_MAIN]['Kittens'] ), 'links from main slot' );
410  $this->assertTrue( isset( $combinedLinks[NS_MAIN]['Goats'] ), 'links from aux slot' );
411  $this->assertFalse( isset( $mainLinks[NS_MAIN]['Goats'] ), 'no aux links in main' );
412  $this->assertFalse( isset( $auxLinks[NS_MAIN]['Kittens'] ), 'no main links in aux' );
413  }
414 
416  $title = $this->getMockTitle( 7, 21 );
417 
419 
420  $text = "";
421  $text .= "* page:{{PAGENAME}}!\n";
422  $text .= "* rev:{{REVISIONID}}!\n";
423  $text .= "* user:{{REVISIONUSER}}!\n";
424  $text .= "* time:{{REVISIONTIMESTAMP}}!\n";
425 
426  $rev->setContent( SlotRecord::MAIN, new WikitextContent( $text ) );
427 
428  $options = ParserOptions::newCanonical( 'canonical' );
429  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
430 
431  // MutableRevisionRecord without ID should be used by the parser.
432  // USeful for fake
433  $html = $rr->getRevisionParserOutput()->getText();
434 
435  $this->assertContains( 'page:RenderTestPage!', $html );
436  $this->assertContains( 'rev:!', $html );
437  $this->assertContains( 'user:!', $html );
438  $this->assertContains( 'time:!', $html );
439  }
440 
442  $title = $this->getMockTitle( 7, 21 );
443 
445  $rev->setId( 21 );
446 
447  $text = "";
448  $text .= "* page:{{PAGENAME}}!\n";
449  $text .= "* rev:{{REVISIONID}}!\n";
450  $text .= "* user:{{REVISIONUSER}}!\n";
451  $text .= "* time:{{REVISIONTIMESTAMP}}!\n";
452 
453  $rev->setContent( SlotRecord::MAIN, new WikitextContent( $text ) );
454 
455  $actualRevision = $this->getMockRevision(
457  $title,
458  21,
460  );
461 
462  $options = ParserOptions::newCanonical( 'canonical' );
463  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
464 
465  // MutableRevisionRecord with ID should not be used by the parser,
466  // revision should be loaded instead!
467  $revisionStore = $this->getMockBuilder( RevisionStore::class )
468  ->disableOriginalConstructor()
469  ->getMock();
470 
471  $revisionStore->expects( $this->once() )
472  ->method( 'getKnownCurrentRevision' )
473  ->with( $title, 0 )
474  ->willReturn( $actualRevision );
475 
476  $this->setService( 'RevisionStore', $revisionStore );
477 
478  $html = $rr->getRevisionParserOutput()->getText();
479 
480  $this->assertContains( 'page:RenderTestPage!', $html );
481  $this->assertContains( 'rev:21!', $html );
482  $this->assertContains( 'user:Frank!', $html );
483  $this->assertContains( 'time:20180101000003!', $html );
484  }
485 
486  public function testSetRevisionParserOutput() {
487  $title = $this->getMockTitle( 3, 21 );
489 
490  $options = ParserOptions::newCanonical( 'canonical' );
491  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
492 
493  $output = new ParserOutput( 'Kittens' );
494  $rr->setRevisionParserOutput( $output );
495 
496  $this->assertSame( $output, $rr->getRevisionParserOutput() );
497  $this->assertSame( 'Kittens', $rr->getRevisionParserOutput()->getText() );
498 
499  $this->assertSame( $output, $rr->getSlotParserOutput( SlotRecord::MAIN ) );
500  $this->assertSame( 'Kittens', $rr->getSlotParserOutput( SlotRecord::MAIN )->getText() );
501  }
502 
503  public function testNoHtml() {
505  $mockContent = $this->getMockBuilder( WikitextContent::class )
506  ->setMethods( [ 'getParserOutput' ] )
507  ->setConstructorArgs( [ 'Whatever' ] )
508  ->getMock();
509  $mockContent->method( 'getParserOutput' )
510  ->willReturnCallback( function ( Title $title, $revId = null,
511  ParserOptions $options = null, $generateHtml = true
512  ) {
513  if ( !$generateHtml ) {
514  return new ParserOutput( null );
515  } else {
516  $this->fail( 'Should not be called with $generateHtml == true' );
517  return null; // never happens, make analyzer happy
518  }
519  } );
520 
521  $title = $this->getMockTitle( 7, 21 );
522 
523  $rev = new MutableRevisionRecord( $title );
524  $rev->setContent( SlotRecord::MAIN, $mockContent );
525  $rev->setContent( 'aux', $mockContent );
526 
527  $options = ParserOptions::newCanonical( 'canonical' );
528  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
529 
530  $output = $rr->getSlotParserOutput( SlotRecord::MAIN, [ 'generate-html' => false ] );
531  $this->assertFalse( $output->hasText(), 'hasText' );
532 
533  $output = $rr->getRevisionParserOutput( [ 'generate-html' => false ] );
534  $this->assertFalse( $output->hasText(), 'hasText' );
535  }
536 
537  public function testUpdateRevision() {
538  $title = $this->getMockTitle( 7, 21 );
539 
541 
542  $text = "";
543  $text .= "* page:{{PAGENAME}}!\n";
544  $text .= "* rev:{{REVISIONID}}!\n";
545  $text .= "* user:{{REVISIONUSER}}!\n";
546  $text .= "* time:{{REVISIONTIMESTAMP}}!\n";
547 
548  $rev->setContent( SlotRecord::MAIN, new WikitextContent( $text ) );
549  $rev->setContent( 'aux', new WikitextContent( '[[Goats]]' ) );
550 
551  $options = ParserOptions::newCanonical( 'canonical' );
552  $rr = new RenderedRevision( $title, $rev, $options, $this->combinerCallback );
553 
554  $firstOutput = $rr->getRevisionParserOutput();
555  $mainOutput = $rr->getSlotParserOutput( SlotRecord::MAIN );
556  $auxOutput = $rr->getSlotParserOutput( 'aux' );
557 
558  // emulate a saved revision
559  $savedRev = new MutableRevisionRecord( $title );
560  $savedRev->setContent( SlotRecord::MAIN, new WikitextContent( $text ) );
561  $savedRev->setContent( 'aux', new WikitextContent( '[[Goats]]' ) );
562  $savedRev->setId( 23 ); // saved, new
563  $savedRev->setUser( new UserIdentityValue( 9, 'Frank', 0 ) );
564  $savedRev->setTimestamp( '20180101000003' );
565 
566  $rr->updateRevision( $savedRev );
567 
568  $this->assertNotSame( $mainOutput, $rr->getSlotParserOutput( SlotRecord::MAIN ), 'Reset main' );
569  $this->assertSame( $auxOutput, $rr->getSlotParserOutput( 'aux' ), 'Keep aux' );
570 
571  $updatedOutput = $rr->getRevisionParserOutput();
572  $html = $updatedOutput->getText();
573 
574  $this->assertNotSame( $firstOutput, $updatedOutput, 'Reset merged' );
575  $this->assertContains( 'page:RenderTestPage!', $html );
576  $this->assertContains( 'rev:23!', $html );
577  $this->assertContains( 'user:Frank!', $html );
578  $this->assertContains( 'time:20180101000003!', $html );
579  $this->assertContains( 'Goats', $html );
580 
581  $rr->updateRevision( $savedRev ); // should do nothing
582  $this->assertSame( $updatedOutput, $rr->getRevisionParserOutput(), 'no more reset needed' );
583  }
584 
585 }
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1978
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:215
const NS_MAIN
Definition: Defines.php:60
RenderedRevision represents the rendered representation of a revision.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
getSlotParserOutput( $role, array $hints=[])
getPrefixedText()
Get the prefixed title with spaces.
Definition: Title.php:1724
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response after the basic globals have been set but before ordinary actions take place $output
Definition: hooks.txt:2211
Mutable RevisionRecord implementation, for building new revision entries programmatically.
static newCanonical( $context=null, $userLang=null)
Creates a "canonical" ParserOptions object.
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:773
getMockRevision( $class, $title, $id=null, $visibility=0, array $content=null)
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1978
isAllowed( $action='')
Internal mechanics of testing a permission.
Definition: User.php:3642
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:773
Value object representing a user&#39;s identity.
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:918
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:216
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1754
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
combineOutput(RenderedRevision $rrev, array $hints=[])
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
\MediaWiki\Revision\RenderedRevision
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:277
Mutable version of RevisionSlots, for constructing a new revision.
$content
Definition: pageupdater.txt:72
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1460