Add support for adding deferred update within a deferred update
authorbsitu <bsitu@wikimedia.org>
Tue, 19 Aug 2014 22:23:05 +0000 (15:23 -0700)
committerEBernhardson <ebernhardson@wikimedia.org>
Wed, 20 Aug 2014 22:13:11 +0000 (22:13 +0000)
Under some configurations all Echo notifications are inserted
via a DeferredUpdate.  When an extension delays its own notification
trigger via DeferredUpdate as well the Echo notification will not
be run.

Change-Id: Ib40fcd4939ede5b0ff986ab109432630efd1be74

includes/deferred/DeferredUpdates.php
tests/phpunit/includes/deferred/DeferredUpdatesTest.php [new file with mode: 0644]

index 2178281..b0c1899 100644 (file)
@@ -99,25 +99,29 @@ class DeferredUpdates {
                        $dbw = wfGetDB( DB_MASTER );
                }
 
-               /** @var DeferrableUpdate $update */
-               foreach ( $updates as $update ) {
-                       try {
-                               $update->doUpdate();
+               while ( $updates ) {
+                       self::clearPendingUpdates();
 
-                               if ( $doCommit && $dbw->trxLevel() ) {
-                                       $dbw->commit( __METHOD__, 'flush' );
-                               }
-                       } catch ( MWException $e ) {
-                               // We don't want exceptions thrown during deferred updates to
-                               // be reported to the user since the output is already sent.
-                               // Instead we just log them.
-                               if ( !$e instanceof ErrorPageError ) {
-                                       MWExceptionHandler::logException( $e );
+                       /** @var DeferrableUpdate $update */
+                       foreach ( $updates as $update ) {
+                               try {
+                                       $update->doUpdate();
+
+                                       if ( $doCommit && $dbw->trxLevel() ) {
+                                               $dbw->commit( __METHOD__, 'flush' );
+                                       }
+                               } catch ( MWException $e ) {
+                                       // We don't want exceptions thrown during deferred updates to
+                                       // be reported to the user since the output is already sent.
+                                       // Instead we just log them.
+                                       if ( !$e instanceof ErrorPageError ) {
+                                               MWExceptionHandler::logException( $e );
+                                       }
                                }
                        }
+                       $updates = array_merge( $wgDeferredUpdateList, self::$updates );
                }
 
-               self::clearPendingUpdates();
                wfProfileOut( __METHOD__ );
        }
 
diff --git a/tests/phpunit/includes/deferred/DeferredUpdatesTest.php b/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
new file mode 100644 (file)
index 0000000..b3d57e7
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+class DeferredUpdatesTest extends MediaWikiTestCase {
+
+       public function testDoUpdates() {
+               $updates = array (
+                       '1' => 'deferred update 1',
+                       '2' => 'deferred update 2',
+                       '3' => 'deferred update 3',
+                       '2-1' => 'deferred update 1 within deferred update 2',
+               );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $updates ) {
+                               echo $updates['1'];
+                       }
+               );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $updates ) {
+                               echo $updates['2'];
+                               DeferredUpdates::addCallableUpdate(
+                                       function() use ( $updates ) {
+                                               echo $updates['2-1'];
+                                       }
+                               );
+                       }
+               );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $updates ) {
+                               echo $updates[3];
+                       }
+               );
+
+               $this->expectOutputString( implode( '', $updates ) );
+
+               DeferredUpdates::doUpdates();
+       }
+
+}