MediaWiki  1.32.0
DerivedPageDataUpdaterTest.php
Go to the documentation of this file.
1 <?php
2 
4 
19 use PHPUnit\Framework\MockObject\MockObject;
22 use Title;
23 use User;
24 use Wikimedia\TestingAccessWrapper;
27 
34 
35  public function tearDown() {
36  MWTimestamp::setFakeTime( false );
37 
38  parent::tearDown();
39  }
40 
46  private function getTitle( $title ) {
48  }
49 
55  private function getPage( $title ) {
56  $title = ( $title instanceof Title ) ? $title : $this->getTitle( $title );
57 
58  return WikiPage::factory( $title );
59  }
60 
66  private function getDerivedPageDataUpdater( $page, RevisionRecord $rec = null ) {
67  if ( is_string( $page ) || $page instanceof Title ) {
68  $page = $this->getPage( $page );
69  }
70 
71  $page = TestingAccessWrapper::newFromObject( $page );
72  return $page->getDerivedDataUpdater( null, $rec );
73  }
74 
84  private function createRevision( WikiPage $page, $summary, $content = null ) {
85  $user = $this->getTestUser()->getUser();
86  $comment = CommentStoreComment::newUnsavedComment( $summary );
87 
88  if ( $content === null || is_string( $content ) ) {
89  $content = new WikitextContent( $content ?? $summary );
90  }
91 
92  if ( !is_array( $content ) ) {
93  $content = [ 'main' => $content ];
94  }
95 
96  $this->getDerivedPageDataUpdater( $page ); // flush cached instance before.
97 
98  $updater = $page->newPageUpdater( $user );
99 
100  foreach ( $content as $role => $c ) {
101  $updater->setContent( $role, $c );
102  }
103 
104  $rev = $updater->saveRevision( $comment );
105 
106  $this->getDerivedPageDataUpdater( $page ); // flush cached instance after.
107  return $rev;
108  }
109 
110  // TODO: test setArticleCountMethod() and isCountable();
111  // TODO: test isRedirect() and wasRedirect()
112 
116  public function testGetCanonicalParserOptions() {
117  $user = $this->getTestUser()->getUser();
118  $page = $this->getPage( __METHOD__ );
119 
120  $parentRev = $this->createRevision( $page, 'first' );
121 
122  $mainContent = new WikitextContent( 'Lorem ipsum' );
123 
124  $update = new RevisionSlotsUpdate();
125  $update->modifyContent( SlotRecord::MAIN, $mainContent );
126  $updater = $this->getDerivedPageDataUpdater( $page );
127  $updater->prepareContent( $user, $update, false );
128 
129  $options1 = $updater->getCanonicalParserOptions();
130  $this->assertSame( MediaWikiServices::getInstance()->getContentLanguage(),
131  $options1->getUserLangObj() );
132 
133  $speculativeId = $options1->getSpeculativeRevId();
134  $this->assertSame( $parentRev->getId() + 1, $speculativeId );
135 
136  $rev = $this->makeRevision(
137  $page->getTitle(),
138  $update,
139  $user,
140  $parentRev->getId() + 7,
141  $parentRev->getId()
142  );
143  $updater->prepareUpdate( $rev );
144 
145  $options2 = $updater->getCanonicalParserOptions();
146 
147  $currentRev = call_user_func( $options2->getCurrentRevisionCallback(), $page->getTitle() );
148  $this->assertSame( $rev->getId(), $currentRev->getId() );
149  }
150 
155  public function testGrabCurrentRevision() {
156  $page = $this->getPage( __METHOD__ );
157 
158  $updater0 = $this->getDerivedPageDataUpdater( $page );
159  $this->assertNull( $updater0->grabCurrentRevision() );
160  $this->assertFalse( $updater0->pageExisted() );
161 
162  $rev1 = $this->createRevision( $page, 'first' );
163  $updater1 = $this->getDerivedPageDataUpdater( $page );
164  $this->assertSame( $rev1->getId(), $updater1->grabCurrentRevision()->getId() );
165  $this->assertFalse( $updater0->pageExisted() );
166  $this->assertTrue( $updater1->pageExisted() );
167 
168  $rev2 = $this->createRevision( $page, 'second' );
169  $updater2 = $this->getDerivedPageDataUpdater( $page );
170  $this->assertSame( $rev1->getId(), $updater1->grabCurrentRevision()->getId() );
171  $this->assertSame( $rev2->getId(), $updater2->grabCurrentRevision()->getId() );
172  }
173 
188  public function testPrepareContent() {
189  $sysop = $this->getTestUser( [ 'sysop' ] )->getUser();
190  $updater = $this->getDerivedPageDataUpdater( __METHOD__ );
191 
192  $this->assertFalse( $updater->isContentPrepared() );
193 
194  // TODO: test stash
195  // TODO: MCR: Test multiple slots. Test slot removal.
196  $mainContent = new WikitextContent( 'first [[main]] ~~~' );
197  $auxContent = new WikitextContent( 'inherited ~~~ content' );
198  $auxSlot = SlotRecord::newSaved(
199  10, 7, 'tt:7',
200  SlotRecord::newUnsaved( 'aux', $auxContent )
201  );
202 
203  $update = new RevisionSlotsUpdate();
204  $update->modifyContent( SlotRecord::MAIN, $mainContent );
205  $update->modifySlot( SlotRecord::newInherited( $auxSlot ) );
206  // TODO: MCR: test removing slots!
207 
208  $updater->prepareContent( $sysop, $update, false );
209 
210  // second be ok to call again with the same params
211  $updater->prepareContent( $sysop, $update, false );
212 
213  $this->assertNull( $updater->grabCurrentRevision() );
214  $this->assertTrue( $updater->isContentPrepared() );
215  $this->assertFalse( $updater->isUpdatePrepared() );
216  $this->assertFalse( $updater->pageExisted() );
217  $this->assertTrue( $updater->isCreation() );
218  $this->assertTrue( $updater->isChange() );
219  $this->assertFalse( $updater->isContentDeleted() );
220 
221  $this->assertNotNull( $updater->getRevision() );
222  $this->assertNotNull( $updater->getRenderedRevision() );
223 
224  $this->assertEquals( [ 'main', 'aux' ], $updater->getSlots()->getSlotRoles() );
225  $this->assertEquals( [ 'main' ], array_keys( $updater->getSlots()->getOriginalSlots() ) );
226  $this->assertEquals( [ 'aux' ], array_keys( $updater->getSlots()->getInheritedSlots() ) );
227  $this->assertEquals( [ 'main', 'aux' ], $updater->getModifiedSlotRoles() );
228  $this->assertEquals( [ 'main', 'aux' ], $updater->getTouchedSlotRoles() );
229 
230  $mainSlot = $updater->getRawSlot( SlotRecord::MAIN );
231  $this->assertInstanceOf( SlotRecord::class, $mainSlot );
232  $this->assertNotContains( '~~~', $mainSlot->getContent()->serialize(), 'PST should apply.' );
233  $this->assertContains( $sysop->getName(), $mainSlot->getContent()->serialize() );
234 
235  $auxSlot = $updater->getRawSlot( 'aux' );
236  $this->assertInstanceOf( SlotRecord::class, $auxSlot );
237  $this->assertContains( '~~~', $auxSlot->getContent()->serialize(), 'No PST should apply.' );
238 
239  $mainOutput = $updater->getCanonicalParserOutput();
240  $this->assertContains( 'first', $mainOutput->getText() );
241  $this->assertContains( '<a ', $mainOutput->getText() );
242  $this->assertNotEmpty( $mainOutput->getLinks() );
243 
244  $canonicalOutput = $updater->getCanonicalParserOutput();
245  $this->assertContains( 'first', $canonicalOutput->getText() );
246  $this->assertContains( '<a ', $canonicalOutput->getText() );
247  $this->assertContains( 'inherited ', $canonicalOutput->getText() );
248  $this->assertNotEmpty( $canonicalOutput->getLinks() );
249  }
250 
257  public function testPrepareContentInherit() {
258  $sysop = $this->getTestUser( [ 'sysop' ] )->getUser();
259  $page = $this->getPage( __METHOD__ );
260 
261  $mainContent1 = new WikitextContent( 'first [[main]] ({{REVISIONUSER}}) #~~~#' );
262  $mainContent2 = new WikitextContent( 'second ({{subst:REVISIONUSER}}) #~~~#' );
263 
264  $rev = $this->createRevision( $page, 'first', $mainContent1 );
265  $mainContent1 = $rev->getContent( SlotRecord::MAIN ); // get post-pst content
266  $userName = $rev->getUser()->getName();
267  $sysopName = $sysop->getName();
268 
269  $update = new RevisionSlotsUpdate();
270  $update->modifyContent( SlotRecord::MAIN, $mainContent1 );
271  $updater1 = $this->getDerivedPageDataUpdater( $page );
272  $updater1->prepareContent( $sysop, $update, false );
273 
274  $this->assertNotNull( $updater1->grabCurrentRevision() );
275  $this->assertTrue( $updater1->isContentPrepared() );
276  $this->assertTrue( $updater1->pageExisted() );
277  $this->assertFalse( $updater1->isCreation() );
278  $this->assertFalse( $updater1->isChange() );
279 
280  $this->assertNotNull( $updater1->getRevision() );
281  $this->assertNotNull( $updater1->getRenderedRevision() );
282 
283  // parser-output for null-edit uses the original author's name
284  $html = $updater1->getRenderedRevision()->getRevisionParserOutput()->getText();
285  $this->assertNotContains( $sysopName, $html, '{{REVISIONUSER}}' );
286  $this->assertNotContains( '{{REVISIONUSER}}', $html, '{{REVISIONUSER}}' );
287  $this->assertNotContains( '~~~', $html, 'signature ~~~' );
288  $this->assertContains( '(' . $userName . ')', $html, '{{REVISIONUSER}}' );
289  $this->assertContains( '>' . $userName . '<', $html, 'signature ~~~' );
290 
291  // TODO: MCR: test inheritance from parent
292  $update = new RevisionSlotsUpdate();
293  $update->modifyContent( SlotRecord::MAIN, $mainContent2 );
294  $updater2 = $this->getDerivedPageDataUpdater( $page );
295  $updater2->prepareContent( $sysop, $update, false );
296 
297  // non-null edit use the new user name in PST
298  $pstText = $updater2->getSlots()->getContent( SlotRecord::MAIN )->serialize();
299  $this->assertNotContains( '{{subst:REVISIONUSER}}', $pstText, '{{subst:REVISIONUSER}}' );
300  $this->assertNotContains( '~~~', $pstText, 'signature ~~~' );
301  $this->assertContains( '(' . $sysopName . ')', $pstText, '{{subst:REVISIONUSER}}' );
302  $this->assertContains( ':' . $sysopName . '|', $pstText, 'signature ~~~' );
303 
304  $this->assertFalse( $updater2->isCreation() );
305  $this->assertTrue( $updater2->isChange() );
306  }
307 
308  // TODO: test failure of prepareContent() when called again...
309  // - with different user
310  // - with different update
311  // - after calling prepareUpdate()
312 
325  public function testPrepareUpdate() {
326  $page = $this->getPage( __METHOD__ );
327 
328  $mainContent1 = new WikitextContent( 'first [[main]] ~~~' );
329  $rev1 = $this->createRevision( $page, 'first', $mainContent1 );
330  $updater1 = $this->getDerivedPageDataUpdater( $page, $rev1 );
331 
332  $options = []; // TODO: test *all* the options...
333  $updater1->prepareUpdate( $rev1, $options );
334 
335  $this->assertTrue( $updater1->isUpdatePrepared() );
336  $this->assertTrue( $updater1->isContentPrepared() );
337  $this->assertTrue( $updater1->isCreation() );
338  $this->assertTrue( $updater1->isChange() );
339  $this->assertFalse( $updater1->isContentDeleted() );
340 
341  $this->assertNotNull( $updater1->getRevision() );
342  $this->assertNotNull( $updater1->getRenderedRevision() );
343 
344  $this->assertEquals( [ 'main' ], $updater1->getSlots()->getSlotRoles() );
345  $this->assertEquals( [ 'main' ], array_keys( $updater1->getSlots()->getOriginalSlots() ) );
346  $this->assertEquals( [], array_keys( $updater1->getSlots()->getInheritedSlots() ) );
347  $this->assertEquals( [ 'main' ], $updater1->getModifiedSlotRoles() );
348  $this->assertEquals( [ 'main' ], $updater1->getTouchedSlotRoles() );
349 
350  // TODO: MCR: test multiple slots, test slot removal!
351 
352  $this->assertInstanceOf( SlotRecord::class, $updater1->getRawSlot( SlotRecord::MAIN ) );
353  $this->assertNotContains( '~~~~', $updater1->getRawContent( SlotRecord::MAIN )->serialize() );
354 
355  $mainOutput = $updater1->getCanonicalParserOutput();
356  $this->assertContains( 'first', $mainOutput->getText() );
357  $this->assertContains( '<a ', $mainOutput->getText() );
358  $this->assertNotEmpty( $mainOutput->getLinks() );
359 
360  $canonicalOutput = $updater1->getCanonicalParserOutput();
361  $this->assertContains( 'first', $canonicalOutput->getText() );
362  $this->assertContains( '<a ', $canonicalOutput->getText() );
363  $this->assertNotEmpty( $canonicalOutput->getLinks() );
364 
365  $mainContent2 = new WikitextContent( 'second' );
366  $rev2 = $this->createRevision( $page, 'second', $mainContent2 );
367  $updater2 = $this->getDerivedPageDataUpdater( $page, $rev2 );
368 
369  $options = []; // TODO: test *all* the options...
370  $updater2->prepareUpdate( $rev2, $options );
371 
372  $this->assertFalse( $updater2->isCreation() );
373  $this->assertTrue( $updater2->isChange() );
374 
375  $canonicalOutput = $updater2->getCanonicalParserOutput();
376  $this->assertContains( 'second', $canonicalOutput->getText() );
377  }
378 
383  $user = $this->getTestUser()->getUser();
384  $page = $this->getPage( __METHOD__ );
385 
386  $mainContent1 = new WikitextContent( 'first [[main]] ~~~' );
387 
388  $update = new RevisionSlotsUpdate();
389  $update->modifyContent( SlotRecord::MAIN, $mainContent1 );
390  $updater = $this->getDerivedPageDataUpdater( $page );
391  $updater->prepareContent( $user, $update, false );
392 
393  $mainOutput = $updater->getSlotParserOutput( SlotRecord::MAIN );
394  $canonicalOutput = $updater->getCanonicalParserOutput();
395 
396  $rev = $this->createRevision( $page, 'first', $mainContent1 );
397 
398  $options = []; // TODO: test *all* the options...
399  $updater->prepareUpdate( $rev, $options );
400 
401  $this->assertTrue( $updater->isUpdatePrepared() );
402  $this->assertTrue( $updater->isContentPrepared() );
403 
404  $this->assertSame( $mainOutput, $updater->getSlotParserOutput( SlotRecord::MAIN ) );
405  $this->assertSame( $canonicalOutput, $updater->getCanonicalParserOutput() );
406  }
407 
412  public function testPrepareUpdateOutputReset() {
413  $user = $this->getTestUser()->getUser();
414  $page = $this->getPage( __METHOD__ );
415 
416  $mainContent1 = new WikitextContent( 'first --{{REVISIONID}}--' );
417 
418  $update = new RevisionSlotsUpdate();
419  $update->modifyContent( SlotRecord::MAIN, $mainContent1 );
420  $updater = $this->getDerivedPageDataUpdater( $page );
421  $updater->prepareContent( $user, $update, false );
422 
423  $mainOutput = $updater->getSlotParserOutput( SlotRecord::MAIN );
424  $canonicalOutput = $updater->getCanonicalParserOutput();
425 
426  // prevent optimization on matching speculative ID
427  $mainOutput->setSpeculativeRevIdUsed( 0 );
428  $canonicalOutput->setSpeculativeRevIdUsed( 0 );
429 
430  $rev = $this->createRevision( $page, 'first', $mainContent1 );
431 
432  $options = []; // TODO: test *all* the options...
433  $updater->prepareUpdate( $rev, $options );
434 
435  $this->assertTrue( $updater->isUpdatePrepared() );
436  $this->assertTrue( $updater->isContentPrepared() );
437 
438  // ParserOutput objects should have been flushed.
439  $this->assertNotSame( $mainOutput, $updater->getSlotParserOutput( SlotRecord::MAIN ) );
440  $this->assertNotSame( $canonicalOutput, $updater->getCanonicalParserOutput() );
441 
442  $html = $updater->getCanonicalParserOutput()->getText();
443  $this->assertContains( '--' . $rev->getId() . '--', $html );
444 
445  // TODO: MCR: ensure that when the main slot uses {{REVISIONID}} but another slot is
446  // updated, the main slot is still re-rendered!
447  }
448 
449  // TODO: test failure of prepareUpdate() when called again with a different revision
450  // TODO: test failure of prepareUpdate() on inconsistency with prepareContent.
451 
456  $user = $this->getTestUser()->getUser();
457 
458  $mainContent = new WikitextContent( 'first [[main]] ~~~' );
459  $update = new RevisionSlotsUpdate();
460  $update->modifyContent( SlotRecord::MAIN, $mainContent );
461 
462  $updater = $this->getDerivedPageDataUpdater( __METHOD__ );
463  $updater->prepareContent( $user, $update, false );
464 
465  $canonicalOutput = $updater->getCanonicalParserOutput();
466 
467  $preparedEdit = $updater->getPreparedEdit();
468  $this->assertSame( $canonicalOutput->getCacheTime(), $preparedEdit->timestamp );
469  $this->assertSame( $canonicalOutput, $preparedEdit->output );
470  $this->assertSame( $mainContent, $preparedEdit->newContent );
471  $this->assertSame( $updater->getRawContent( SlotRecord::MAIN ), $preparedEdit->pstContent );
472  $this->assertSame( $updater->getCanonicalParserOptions(), $preparedEdit->popts );
473  $this->assertSame( null, $preparedEdit->revid );
474  }
475 
480  $clock = MWTimestamp::convert( TS_UNIX, '20100101000000' );
481  MWTimestamp::setFakeTime( function () use ( &$clock ) {
482  return $clock++;
483  } );
484 
485  $page = $this->getPage( __METHOD__ );
486 
487  $mainContent = new WikitextContent( 'first [[main]] ~~~' );
488  $update = new MutableRevisionSlots();
489  $update->setContent( SlotRecord::MAIN, $mainContent );
490 
491  $rev = $this->createRevision( $page, __METHOD__ );
492 
493  $updater = $this->getDerivedPageDataUpdater( $page );
494  $updater->prepareUpdate( $rev );
495 
496  $canonicalOutput = $updater->getCanonicalParserOutput();
497 
498  $preparedEdit = $updater->getPreparedEdit();
499  $this->assertSame( $canonicalOutput->getCacheTime(), $preparedEdit->timestamp );
500  $this->assertSame( $canonicalOutput, $preparedEdit->output );
501  $this->assertSame( $updater->getRawContent( SlotRecord::MAIN ), $preparedEdit->pstContent );
502  $this->assertSame( $updater->getCanonicalParserOptions(), $preparedEdit->popts );
503  $this->assertSame( $rev->getId(), $preparedEdit->revid );
504  }
505 
507  $user = $this->getTestUser()->getUser();
508  $page = $this->getPage( __METHOD__ );
509  $this->createRevision( $page, __METHOD__ );
510 
511  $mainContent1 = new WikitextContent( 'first' );
512 
513  $update = new RevisionSlotsUpdate();
514  $update->modifyContent( SlotRecord::MAIN, $mainContent1 );
515  $updater = $this->getDerivedPageDataUpdater( $page );
516  $updater->prepareContent( $user, $update, false );
517 
518  $dataUpdates = $updater->getSecondaryDataUpdates();
519 
520  $this->assertNotEmpty( $dataUpdates );
521 
522  $linksUpdates = array_filter( $dataUpdates, function ( $du ) {
523  return $du instanceof LinksUpdate;
524  } );
525  $this->assertCount( 1, $linksUpdates );
526  }
527 
535  $handler = $this->getMockBuilder( TextContentHandler::class )
536  ->setConstructorArgs( [ $name ] )
537  ->setMethods(
538  [ 'getSecondaryDataUpdates', 'getDeletionUpdates', 'unserializeContent' ]
539  )
540  ->getMock();
541 
542  $dataUpdate = new MWCallableUpdate( 'time' );
543  $dataUpdate->_name = "$name data update";
544 
545  $deletionUpdate = new MWCallableUpdate( 'time' );
546  $deletionUpdate->_name = "$name deletion update";
547 
548  $handler->method( 'getSecondaryDataUpdates' )->willReturn( [ $dataUpdate ] );
549  $handler->method( 'getDeletionUpdates' )->willReturn( [ $deletionUpdate ] );
550  $handler->method( 'unserializeContent' )->willReturnCallback(
551  function ( $text ) use ( $handler ) {
552  return $this->createMockContent( $handler, $text );
553  }
554  );
555 
557  'wgContentHandlers', [
558  $name => function () use ( $handler ){
559  return $handler;
560  }
561  ]
562  );
563 
564  return $handler;
565  }
566 
573  private function createMockContent( ContentHandler $handler, $text ) {
575  $content = $this->getMockBuilder( TextContent::class )
576  ->setConstructorArgs( [ $text ] )
577  ->setMethods( [ 'getModel', 'getContentHandler' ] )
578  ->getMock();
579 
580  $content->method( 'getModel' )->willReturn( $handler->getModelID() );
581  $content->method( 'getContentHandler' )->willReturn( $handler );
582 
583  return $content;
584  }
585 
588 
590  $this->markTestSkipped( 'Slot removal cannot happen with MCR being enabled' );
591  }
592 
593  $m1 = $this->defineMockContentModelForUpdateTesting( 'M1' );
594  $a1 = $this->defineMockContentModelForUpdateTesting( 'A1' );
595  $m2 = $this->defineMockContentModelForUpdateTesting( 'M2' );
596 
597  $mainContent1 = $this->createMockContent( $m1, 'main 1' );
598  $auxContent1 = $this->createMockContent( $a1, 'aux 1' );
599  $mainContent2 = $this->createMockContent( $m2, 'main 2' );
600 
601  $user = $this->getTestUser()->getUser();
602  $page = $this->getPage( __METHOD__ );
603  $this->createRevision(
604  $page,
605  __METHOD__,
606  [ 'main' => $mainContent1, 'aux' => $auxContent1 ]
607  );
608 
609  $update = new RevisionSlotsUpdate();
610  $update->modifyContent( SlotRecord::MAIN, $mainContent2 );
611  $update->removeSlot( 'aux' );
612 
613  $page = $this->getPage( __METHOD__ );
614  $updater = $this->getDerivedPageDataUpdater( $page );
615  $updater->prepareContent( $user, $update, false );
616 
617  $dataUpdates = $updater->getSecondaryDataUpdates();
618 
619  $this->assertNotEmpty( $dataUpdates );
620 
621  $updateNames = array_map( function ( $du ) {
622  return isset( $du->_name ) ? $du->_name : get_class( $du );
623  }, $dataUpdates );
624 
625  $this->assertContains( LinksUpdate::class, $updateNames );
626  $this->assertContains( 'A1 deletion update', $updateNames );
627  $this->assertContains( 'M2 data update', $updateNames );
628  $this->assertNotContains( 'M1 data update', $updateNames );
629  }
630 
643  private function makeRevision(
644  Title $title,
645  RevisionSlotsUpdate $update,
646  User $user,
647  $comment,
648  $id = 0,
649  $parentId = 0
650  ) {
652 
653  $rev->applyUpdate( $update );
654  $rev->setUser( $user );
655  $rev->setComment( CommentStoreComment::newUnsavedComment( $comment ) );
656  $rev->setPageId( $title->getArticleID() );
657  $rev->setParentId( $parentId );
658 
659  if ( $id ) {
660  $rev->setId( $id );
661  }
662 
663  return $rev;
664  }
665 
670  private function getMockTitle( $id = 23 ) {
671  $mock = $this->getMockBuilder( Title::class )
672  ->disableOriginalConstructor()
673  ->getMock();
674  $mock->expects( $this->any() )
675  ->method( 'getDBkey' )
676  ->will( $this->returnValue( __CLASS__ ) );
677  $mock->expects( $this->any() )
678  ->method( 'getArticleID' )
679  ->will( $this->returnValue( $id ) );
680 
681  return $mock;
682  }
683 
684  public function provideIsReusableFor() {
685  $title = $this->getMockTitle();
686 
687  $user1 = User::newFromName( 'Alice' );
688  $user2 = User::newFromName( 'Bob' );
689 
690  $content1 = new WikitextContent( 'one' );
691  $content2 = new WikitextContent( 'two' );
692 
693  $update1 = new RevisionSlotsUpdate();
694  $update1->modifyContent( SlotRecord::MAIN, $content1 );
695 
696  $update1b = new RevisionSlotsUpdate();
697  $update1b->modifyContent( 'xyz', $content1 );
698 
699  $update2 = new RevisionSlotsUpdate();
700  $update2->modifyContent( SlotRecord::MAIN, $content2 );
701 
702  $rev1 = $this->makeRevision( $title, $update1, $user1, 'rev1', 11 );
703  $rev1b = $this->makeRevision( $title, $update1b, $user1, 'rev1', 11 );
704 
705  $rev2 = $this->makeRevision( $title, $update2, $user1, 'rev2', 12 );
706  $rev2x = $this->makeRevision( $title, $update2, $user2, 'rev2', 12 );
707  $rev2y = $this->makeRevision( $title, $update2, $user1, 'rev2', 122 );
708 
709  yield 'any' => [
710  '$prepUser' => null,
711  '$prepRevision' => null,
712  '$prepUpdate' => null,
713  '$forUser' => null,
714  '$forRevision' => null,
715  '$forUpdate' => null,
716  '$forParent' => null,
717  '$isReusable' => true,
718  ];
719  yield 'for any' => [
720  '$prepUser' => $user1,
721  '$prepRevision' => $rev1,
722  '$prepUpdate' => $update1,
723  '$forUser' => null,
724  '$forRevision' => null,
725  '$forUpdate' => null,
726  '$forParent' => null,
727  '$isReusable' => true,
728  ];
729  yield 'unprepared' => [
730  '$prepUser' => null,
731  '$prepRevision' => null,
732  '$prepUpdate' => null,
733  '$forUser' => $user1,
734  '$forRevision' => $rev1,
735  '$forUpdate' => $update1,
736  '$forParent' => 0,
737  '$isReusable' => true,
738  ];
739  yield 'match prepareContent' => [
740  '$prepUser' => $user1,
741  '$prepRevision' => null,
742  '$prepUpdate' => $update1,
743  '$forUser' => $user1,
744  '$forRevision' => null,
745  '$forUpdate' => $update1,
746  '$forParent' => 0,
747  '$isReusable' => true,
748  ];
749  yield 'match prepareUpdate' => [
750  '$prepUser' => null,
751  '$prepRevision' => $rev1,
752  '$prepUpdate' => null,
753  '$forUser' => $user1,
754  '$forRevision' => $rev1,
755  '$forUpdate' => null,
756  '$forParent' => 0,
757  '$isReusable' => true,
758  ];
759  yield 'match all' => [
760  '$prepUser' => $user1,
761  '$prepRevision' => $rev1,
762  '$prepUpdate' => $update1,
763  '$forUser' => $user1,
764  '$forRevision' => $rev1,
765  '$forUpdate' => $update1,
766  '$forParent' => 0,
767  '$isReusable' => true,
768  ];
769  yield 'mismatch prepareContent update' => [
770  '$prepUser' => $user1,
771  '$prepRevision' => null,
772  '$prepUpdate' => $update1,
773  '$forUser' => $user1,
774  '$forRevision' => null,
775  '$forUpdate' => $update1b,
776  '$forParent' => 0,
777  '$isReusable' => false,
778  ];
779  yield 'mismatch prepareContent user' => [
780  '$prepUser' => $user1,
781  '$prepRevision' => null,
782  '$prepUpdate' => $update1,
783  '$forUser' => $user2,
784  '$forRevision' => null,
785  '$forUpdate' => $update1,
786  '$forParent' => 0,
787  '$isReusable' => false,
788  ];
789  yield 'mismatch prepareContent parent' => [
790  '$prepUser' => $user1,
791  '$prepRevision' => null,
792  '$prepUpdate' => $update1,
793  '$forUser' => $user1,
794  '$forRevision' => null,
795  '$forUpdate' => $update1,
796  '$forParent' => 7,
797  '$isReusable' => false,
798  ];
799  yield 'mismatch prepareUpdate revision update' => [
800  '$prepUser' => null,
801  '$prepRevision' => $rev1,
802  '$prepUpdate' => null,
803  '$forUser' => null,
804  '$forRevision' => $rev1b,
805  '$forUpdate' => null,
806  '$forParent' => 0,
807  '$isReusable' => false,
808  ];
809  yield 'mismatch prepareUpdate revision user' => [
810  '$prepUser' => null,
811  '$prepRevision' => $rev2,
812  '$prepUpdate' => null,
813  '$forUser' => null,
814  '$forRevision' => $rev2x,
815  '$forUpdate' => null,
816  '$forParent' => 0,
817  '$isReusable' => false,
818  ];
819  yield 'mismatch prepareUpdate revision id' => [
820  '$prepUser' => null,
821  '$prepRevision' => $rev2,
822  '$prepUpdate' => null,
823  '$forUser' => null,
824  '$forRevision' => $rev2y,
825  '$forUpdate' => null,
826  '$forParent' => 0,
827  '$isReusable' => false,
828  ];
829  }
830 
844  public function testIsReusableFor(
845  User $prepUser = null,
846  RevisionRecord $prepRevision = null,
847  RevisionSlotsUpdate $prepUpdate = null,
848  User $forUser = null,
849  RevisionRecord $forRevision = null,
850  RevisionSlotsUpdate $forUpdate = null,
851  $forParent = null,
852  $isReusable = null
853  ) {
854  $updater = $this->getDerivedPageDataUpdater( __METHOD__ );
855 
856  if ( $prepUpdate ) {
857  $updater->prepareContent( $prepUser, $prepUpdate, false );
858  }
859 
860  if ( $prepRevision ) {
861  $updater->prepareUpdate( $prepRevision );
862  }
863 
864  $this->assertSame(
865  $isReusable,
866  $updater->isReusableFor( $forUser, $forRevision, $forUpdate, $forParent )
867  );
868  }
869 
875  public function testDoUpdates() {
876  $page = $this->getPage( __METHOD__ );
877 
878  $content = [ 'main' => new WikitextContent( 'first [[main]]' ) ];
879 
880  if ( $this->hasMultiSlotSupport() ) {
881  $content['aux'] = new WikitextContent( 'Aux [[Nix]]' );
882  }
883 
884  $rev = $this->createRevision( $page, 'first', $content );
885  $pageId = $page->getId();
886 
887  $oldStats = $this->db->selectRow( 'site_stats', '*', '1=1' );
888  $this->db->delete( 'pagelinks', '*' );
889 
890  $pcache = MediaWikiServices::getInstance()->getParserCache();
891  $pcache->deleteOptionsKey( $page );
892 
893  $updater = $this->getDerivedPageDataUpdater( $page, $rev );
894  $updater->setArticleCountMethod( 'link' );
895 
896  $options = []; // TODO: test *all* the options...
897  $updater->prepareUpdate( $rev, $options );
898 
899  $updater->doUpdates();
900 
901  // links table update
902  $pageLinks = $this->db->select(
903  'pagelinks',
904  '*',
905  [ 'pl_from' => $pageId ],
906  __METHOD__,
907  [ 'ORDER BY' => 'pl_namespace, pl_title' ]
908  );
909 
910  $pageLinksRow = $pageLinks->fetchObject();
911  $this->assertInternalType( 'object', $pageLinksRow );
912  $this->assertSame( 'Main', $pageLinksRow->pl_title );
913 
914  if ( $this->hasMultiSlotSupport() ) {
915  $pageLinksRow = $pageLinks->fetchObject();
916  $this->assertInternalType( 'object', $pageLinksRow );
917  $this->assertSame( 'Nix', $pageLinksRow->pl_title );
918  }
919 
920  // parser cache update
921  $cached = $pcache->get( $page, $updater->getCanonicalParserOptions() );
922  $this->assertInternalType( 'object', $cached );
923  $this->assertSame( $updater->getCanonicalParserOutput(), $cached );
924 
925  // site stats
926  $stats = $this->db->selectRow( 'site_stats', '*', '1=1' );
927  $this->assertSame( $oldStats->ss_total_pages + 1, (int)$stats->ss_total_pages );
928  $this->assertSame( $oldStats->ss_total_edits + 1, (int)$stats->ss_total_edits );
929  $this->assertSame( $oldStats->ss_good_articles + 1, (int)$stats->ss_good_articles );
930 
931  // TODO: MCR: test data updates for additional slots!
932  // TODO: test update for edit without page creation
933  // TODO: test message cache purge
934  // TODO: test module cache purge
935  // TODO: test CDN purge
936  // TODO: test newtalk update
937  // TODO: test search update
938  // TODO: test site stats good_articles while turning the page into (or back from) a redir.
939  // TODO: test category membership update (with setRcWatchCategoryMembership())
940  }
941 
945  public function testDoParserCacheUpdate() {
946  $page = $this->getPage( __METHOD__ );
947  $this->createRevision( $page, 'Dummy' );
948 
949  $user = $this->getTestUser()->getUser();
950 
951  $update = new RevisionSlotsUpdate();
952  $update->modifyContent( 'main', new WikitextContent( 'first [[Main]]' ) );
953 
954  if ( $this->hasMultiSlotSupport() ) {
955  $update->modifyContent( 'aux', new WikitextContent( 'Aux [[Nix]]' ) );
956  }
957 
958  // Emulate update after edit ----------
959  $pcache = MediaWikiServices::getInstance()->getParserCache();
960  $pcache->deleteOptionsKey( $page );
961 
962  $rev = $this->makeRevision( $page->getTitle(), $update, $user, 'rev', null );
963  $rev->setTimestamp( '20100101000000' );
964  $rev->setParentId( $page->getLatest() );
965 
966  $updater = $this->getDerivedPageDataUpdater( $page );
967  $updater->prepareContent( $user, $update, false );
968 
969  $rev->setId( 11 );
970  $updater->prepareUpdate( $rev );
971 
972  // Force the page timestamp, so we notice whether ParserOutput::getTimestamp
973  // or ParserOutput::getCacheTime are used.
974  $page->setTimestamp( $rev->getTimestamp() );
975  $updater->doParserCacheUpdate();
976 
977  // The cached ParserOutput should not use the revision timestamp
978  $cached = $pcache->get( $page, $updater->getCanonicalParserOptions(), true );
979  $this->assertInternalType( 'object', $cached );
980  $this->assertSame( $updater->getCanonicalParserOutput(), $cached );
981 
982  $this->assertSame( $rev->getTimestamp(), $cached->getCacheTime() );
983  $this->assertSame( $rev->getId(), $cached->getCacheRevisionId() );
984 
985  // Emulate forced update of an old revision ----------
986  $pcache->deleteOptionsKey( $page );
987 
988  $updater = $this->getDerivedPageDataUpdater( $page );
989  $updater->prepareUpdate( $rev );
990 
991  // Force the page timestamp, so we notice whether ParserOutput::getTimestamp
992  // or ParserOutput::getCacheTime are used.
993  $page->setTimestamp( $rev->getTimestamp() );
994  $updater->doParserCacheUpdate();
995 
996  // The cached ParserOutput should not use the revision timestamp
997  $cached = $pcache->get( $page, $updater->getCanonicalParserOptions(), true );
998  $this->assertInternalType( 'object', $cached );
999  $this->assertSame( $updater->getCanonicalParserOutput(), $cached );
1000 
1001  $this->assertGreaterThan( $rev->getTimestamp(), $cached->getCacheTime() );
1002  $this->assertSame( $rev->getId(), $cached->getCacheRevisionId() );
1003  }
1004 
1008  private function hasMultiSlotSupport() {
1010 
1013  }
1014 
1015 }
MWTimestamp
Library for creating and parsing MW-style timestamps.
Definition: MWTimestamp.php:32
ContentHandler
A content handler knows how do deal with a specific type of content on a wiki page.
Definition: ContentHandler.php:53
CommentStoreComment\newUnsavedComment
static newUnsavedComment( $comment, array $data=null)
Create a new, unsaved CommentStoreComment.
Definition: CommentStoreComment.php:66
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:244
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testIsReusableFor
testIsReusableFor(User $prepUser=null, RevisionRecord $prepRevision=null, RevisionSlotsUpdate $prepUpdate=null, User $forUser=null, RevisionRecord $forRevision=null, RevisionSlotsUpdate $forUpdate=null, $forParent=null, $isReusable=null)
provideIsReusableFor \MediaWiki\Storage\DerivedPageDataUpdater::isReusableFor()
Definition: DerivedPageDataUpdaterTest.php:844
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:45
SCHEMA_COMPAT_READ_NEW
const SCHEMA_COMPAT_READ_NEW
Definition: Defines.php:287
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\provideIsReusableFor
provideIsReusableFor()
Definition: DerivedPageDataUpdaterTest.php:684
MediaWikiTestCase\mergeMwGlobalArrayValue
mergeMwGlobalArrayValue( $name, $values)
Merges the given values into a MW global array variable.
Definition: MediaWikiTestCase.php:901
MediaWikiTestCase\getTestUser
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
Definition: MediaWikiTestCase.php:179
Revision\SlotRecord\newInherited
static newInherited(SlotRecord $slot)
Constructs a new SlotRecord for a new revision, inheriting the content of the given SlotRecord of a p...
Definition: SlotRecord.php:103
WikiPage\newPageUpdater
newPageUpdater(User $user, RevisionSlotsUpdate $forUpdate=null)
Returns a PageUpdater for creating new revisions on this page (or creating the page).
Definition: WikiPage.php:1762
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\tearDown
tearDown()
Definition: DerivedPageDataUpdaterTest.php:35
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testPrepareContentInherit
testPrepareContentInherit()
\MediaWiki\Storage\DerivedPageDataUpdater::prepareContent() \MediaWiki\Storage\DerivedPageDataUpdater...
Definition: DerivedPageDataUpdaterTest.php:257
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\createMockContent
createMockContent(ContentHandler $handler, $text)
Definition: DerivedPageDataUpdaterTest.php:573
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\getTitle
getTitle( $title)
Definition: DerivedPageDataUpdaterTest.php:46
WikiPage
Class representing a MediaWiki article and history.
Definition: WikiPage.php:44
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testDoParserCacheUpdate
testDoParserCacheUpdate()
\MediaWiki\Storage\DerivedPageDataUpdater::doParserCacheUpdate()
Definition: DerivedPageDataUpdaterTest.php:945
LinksUpdate
Class the manages updates of *_link tables as well as similar extension-managed tables.
Definition: LinksUpdate.php:35
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testGetPreparedEditAfterPrepareUpdate
testGetPreparedEditAfterPrepareUpdate()
\MediaWiki\Storage\DerivedPageDataUpdater::getPreparedEdit()
Definition: DerivedPageDataUpdaterTest.php:479
$wgMultiContentRevisionSchemaMigrationStage
int $wgMultiContentRevisionSchemaMigrationStage
RevisionStore table schema migration stage (content, slots, content_models & slot_roles tables).
Definition: DefaultSettings.php:8988
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:592
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\getMockTitle
getMockTitle( $id=23)
Definition: DerivedPageDataUpdaterTest.php:670
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testPrepareUpdateReusesParserOutput
testPrepareUpdateReusesParserOutput()
\MediaWiki\Storage\DerivedPageDataUpdater::prepareUpdate()
Definition: DerivedPageDataUpdaterTest.php:382
Revision\MutableRevisionSlots
Mutable version of RevisionSlots, for constructing a new revision.
Definition: MutableRevisionSlots.php:33
User
User
Definition: All_system_messages.txt:425
php
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\Tests\Storage\DerivedPageDataUpdaterTest\testGetPreparedEditAfterPrepareContent
testGetPreparedEditAfterPrepareContent()
\MediaWiki\Storage\DerivedPageDataUpdater::getPreparedEdit()
Definition: DerivedPageDataUpdaterTest.php:455
DerivedPageDataUpdater
This document provides an overview of the usage of PageUpdater and DerivedPageDataUpdater
Definition: pageupdater.txt:3
MediaWiki\Tests\Storage
Definition: BlobStoreFactoryTest.php:3
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testGetSecondaryDataUpdatesAfterPrepareContent
testGetSecondaryDataUpdatesAfterPrepareContent()
Definition: DerivedPageDataUpdaterTest.php:506
$html
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:2036
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:964
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:127
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\hasMultiSlotSupport
hasMultiSlotSupport()
Definition: DerivedPageDataUpdaterTest.php:1008
MediaWikiTestCase
Definition: MediaWikiTestCase.php:16
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testDoUpdates
testDoUpdates()
\MediaWiki\Storage\DerivedPageDataUpdater::doUpdates() \MediaWiki\Storage\DerivedPageDataUpdater::doS...
Definition: DerivedPageDataUpdaterTest.php:875
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testPrepareContent
testPrepareContent()
\MediaWiki\Storage\DerivedPageDataUpdater::prepareContent() \MediaWiki\Storage\DerivedPageDataUpdater...
Definition: DerivedPageDataUpdaterTest.php:188
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\getDerivedPageDataUpdater
getDerivedPageDataUpdater( $page, RevisionRecord $rec=null)
Definition: DerivedPageDataUpdaterTest.php:66
MediaWikiTestCase\getDefaultWikitextNS
getDefaultWikitextNS()
Returns the ID of a namespace that defaults to Wikitext.
Definition: MediaWikiTestCase.php:2177
WikitextContent
Content object for wiki text pages.
Definition: WikitextContent.php:35
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\getPage
getPage( $title)
Definition: DerivedPageDataUpdaterTest.php:55
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\createRevision
createRevision(WikiPage $page, $summary, $content=null)
Creates a revision in the database.
Definition: DerivedPageDataUpdaterTest.php:84
Revision\SlotRecord\newUnsaved
static newUnsaved( $role, Content $content)
Constructs a new Slot from a Content object for a new revision.
Definition: SlotRecord.php:129
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testGrabCurrentRevision
testGrabCurrentRevision()
\MediaWiki\Storage\DerivedPageDataUpdater::grabCurrentRevision() \MediaWiki\Storage\DerivedPageDataUp...
Definition: DerivedPageDataUpdaterTest.php:155
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
MediaWiki\Storage\RevisionSlotsUpdate
Value object representing a modification of revision slots.
Definition: RevisionSlotsUpdate.php:36
MediaWiki\MediaWikiServices\getInstance
static getInstance()
Returns the global default instance of the top level service locator.
Definition: MediaWikiServices.php:120
any
they could even be mouse clicks or menu items whatever suits your program You should also get your if any
Definition: COPYING.txt:326
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:573
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest
Database.
Definition: DerivedPageDataUpdaterTest.php:33
Revision\MutableRevisionRecord
Mutable RevisionRecord implementation, for building new revision entries programmatically.
Definition: MutableRevisionRecord.php:41
TextContentHandler
Base content handler implementation for flat text contents.
Definition: TextContentHandler.php:31
SCHEMA_COMPAT_WRITE_NEW
const SCHEMA_COMPAT_WRITE_NEW
Definition: Defines.php:286
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testPrepareUpdateOutputReset
testPrepareUpdateOutputReset()
\MediaWiki\Storage\DerivedPageDataUpdater::prepareUpdate() \MediaWiki\Storage\DerivedPageDataUpdater:...
Definition: DerivedPageDataUpdaterTest.php:412
$handler
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub 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 modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check set to true or false to override the $wgMaxImageArea check result gives extension the possibility to transform it themselves $handler
Definition: hooks.txt:813
Revision\SlotRecord\MAIN
const MAIN
Definition: SlotRecord.php:41
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:37
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testGetSecondaryDataUpdatesWithSlotRemoval
testGetSecondaryDataUpdatesWithSlotRemoval()
Definition: DerivedPageDataUpdaterTest.php:586
Content
Base interface for content objects.
Definition: Content.php:34
MWCallableUpdate
Deferrable Update for closure/callback.
Definition: MWCallableUpdate.php:8
Title
Represents a title within MediaWiki.
Definition: Title.php:39
$options
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:2036
Revision\SlotRecord\newSaved
static newSaved( $revisionId, $contentId, $contentAddress, SlotRecord $protoSlot)
Constructs a complete SlotRecord for a newly saved revision, based on the incomplete proto-slot.
Definition: SlotRecord.php:164
$rev
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:1808
as
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
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\defineMockContentModelForUpdateTesting
defineMockContentModelForUpdateTesting( $name)
Definition: DerivedPageDataUpdaterTest.php:533
$updater
$page->newPageUpdater($user) $updater
Definition: pageupdater.txt:63
true
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 true
Definition: hooks.txt:2036
$content
$content
Definition: pageupdater.txt:72
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\makeRevision
makeRevision(Title $title, RevisionSlotsUpdate $update, User $user, $comment, $id=0, $parentId=0)
Creates a dummy revision object without touching the database.
Definition: DerivedPageDataUpdaterTest.php:643
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testPrepareUpdate
testPrepareUpdate()
\MediaWiki\Storage\DerivedPageDataUpdater::prepareUpdate() \MediaWiki\Storage\DerivedPageDataUpdater:...
Definition: DerivedPageDataUpdaterTest.php:325
class
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
MediaWikiServices
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 MediaWikiServices
Definition: injection.txt:23
MediaWiki\Tests\Storage\DerivedPageDataUpdaterTest\testGetCanonicalParserOptions
testGetCanonicalParserOptions()
\MediaWiki\Storage\DerivedPageDataUpdater::getCanonicalParserOptions()
Definition: DerivedPageDataUpdaterTest.php:116
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:47
CommentStoreComment
CommentStoreComment represents a comment stored by CommentStore.
Definition: CommentStoreComment.php:29
Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:39