Merge "Update OOUI to v0.29.1"
[lhc/web/wiklou.git] / includes / Storage / RevisionStore.php
index 8e66906..d9db8bd 100644 (file)
@@ -48,6 +48,7 @@ use Psr\Log\LoggerInterface;
 use Psr\Log\NullLogger;
 use RecentChange;
 use Revision;
+use RuntimeException;
 use stdClass;
 use Title;
 use User;
@@ -437,21 +438,25 @@ class RevisionStore
                $slotRoles = $rev->getSlotRoles();
 
                // Make sure the main slot is always provided throughout migration
-               if ( !in_array( 'main', $slotRoles ) ) {
+               if ( !in_array( SlotRecord::MAIN, $slotRoles ) ) {
                        throw new InvalidArgumentException(
                                'main slot must be provided'
                        );
                }
 
                // If we are not writing into the new schema, we can't support extra slots.
-               if ( !$this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_NEW ) && $slotRoles !== [ 'main' ] ) {
+               if ( !$this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_NEW )
+                       && $slotRoles !== [ SlotRecord::MAIN ]
+               ) {
                        throw new InvalidArgumentException(
                                'Only the main slot is supported when not writing to the MCR enabled schema!'
                        );
                }
 
                // As long as we are not reading from the new schema, we don't want to write extra slots.
-               if ( !$this->hasMcrSchemaFlags( SCHEMA_COMPAT_READ_NEW ) && $slotRoles !== [ 'main' ] ) {
+               if ( !$this->hasMcrSchemaFlags( SCHEMA_COMPAT_READ_NEW )
+                       && $slotRoles !== [ SlotRecord::MAIN ]
+               ) {
                        throw new InvalidArgumentException(
                                'Only the main slot is supported when not reading from the MCR enabled schema!'
                        );
@@ -519,17 +524,17 @@ class RevisionStore
                // Technically, this could go away after MCR migration: while
                // calling code may require a main slot to exist, RevisionStore
                // really should not know or care about that requirement.
-               $rev->getSlot( 'main', RevisionRecord::RAW );
+               $rev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
 
                foreach ( $slotRoles as $role ) {
                        $slot = $rev->getSlot( $role, RevisionRecord::RAW );
                        Assert::postcondition(
                                $slot->getContent() !== null,
-                               $role .  ' slot must have content'
+                               $role . ' slot must have content'
                        );
                        Assert::postcondition(
                                $slot->hasRevision(),
-                               $role .  ' slot must have a revision associated'
+                               $role . ' slot must have a revision associated'
                        );
                }
 
@@ -594,7 +599,7 @@ class RevisionStore
                                $newSlots[$role] = $slot;
 
                                // Write the main slot's text ID to the revision table for backwards compatibility
-                               if ( $slot->getRole() === 'main'
+                               if ( $slot->getRole() === SlotRecord::MAIN
                                        && $this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_OLD )
                                ) {
                                        $blobAddress = $slot->getAddress();
@@ -672,7 +677,7 @@ class RevisionStore
                $contentId = null;
 
                // Write the main slot's text ID to the revision table for backwards compatibility
-               if ( $protoSlot->getRole() === 'main'
+               if ( $protoSlot->getRole() === SlotRecord::MAIN
                        && $this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_OLD )
                ) {
                        // If SCHEMA_COMPAT_WRITE_NEW is also set, the fake content ID is overwritten
@@ -876,7 +881,7 @@ class RevisionStore
 
                if ( $this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_OLD ) ) {
                        // In non MCR mode this IF section will relate to the main slot
-                       $mainSlot = $rev->getSlot( 'main' );
+                       $mainSlot = $rev->getSlot( SlotRecord::MAIN );
                        $model = $mainSlot->getModel();
                        $format = $mainSlot->getFormat();
 
@@ -1054,13 +1059,15 @@ class RevisionStore
        ) {
                $this->checkDatabaseWikiId( $dbw );
 
+               $pageId = $title->getArticleID();
+
                // T51581: Lock the page table row to ensure no other process
                // is adding a revision to the page at the same time.
                // Avoid locking extra tables, compare T191892.
                $pageLatest = $dbw->selectField(
                        'page',
                        'page_latest',
-                       [ 'page_id' => $title->getArticleID() ],
+                       [ 'page_id' => $pageId ],
                        __METHOD__,
                        [ 'FOR UPDATE' ]
                );
@@ -1077,6 +1084,15 @@ class RevisionStore
                        $title
                );
 
+               if ( !$oldRevision ) {
+                       $msg = "Failed to load latest revision ID $pageLatest of page ID $pageId.";
+                       $this->logger->error(
+                               $msg,
+                               [ 'exception' => new RuntimeException( $msg ) ]
+                       );
+                       return null;
+               }
+
                // Construct the new revision
                $timestamp = wfTimestampNow(); // TODO: use a callback, so we can override it for testing.
                $newRevision = MutableRevisionRecord::newFromParentRevision( $oldRevision );
@@ -1209,7 +1225,7 @@ class RevisionStore
         */
        private function emulateMainSlot_1_29( $row, $queryFlags, Title $title ) {
                $mainSlotRow = new stdClass();
-               $mainSlotRow->role_name = 'main';
+               $mainSlotRow->role_name = SlotRecord::MAIN;
                $mainSlotRow->model_name = null;
                $mainSlotRow->slot_revision_id = null;
                $mainSlotRow->slot_content_id = null;
@@ -1358,7 +1374,7 @@ class RevisionStore
                        $mainSlotRow->slot_content_id =
                                function ( SlotRecord $slot ) use ( $queryFlags, $mainSlotRow ) {
                                        $db = $this->getDBConnectionRefForQueryFlags( $queryFlags );
-                                       return $this->findSlotContentId( $db, $mainSlotRow->slot_revision_id, 'main' );
+                                       return $this->findSlotContentId( $db, $mainSlotRow->slot_revision_id, SlotRecord::MAIN );
                                };
                }
 
@@ -1609,7 +1625,7 @@ class RevisionStore
                        $slots[$row->role_name] = new SlotRecord( $row, $contentCallback );
                }
 
-               if ( !isset( $slots['main'] ) ) {
+               if ( !isset( $slots[SlotRecord::MAIN] ) ) {
                        throw new RevisionAccessException(
                                'Main slot of revision ' . $revId . ' not found in database!'
                        );
@@ -1640,7 +1656,7 @@ class RevisionStore
        ) {
                if ( !$this->hasMcrSchemaFlags( SCHEMA_COMPAT_READ_NEW ) ) {
                        $mainSlot = $this->emulateMainSlot_1_29( $revisionRow, $queryFlags, $title );
-                       $slots = new RevisionSlots( [ 'main' => $mainSlot ] );
+                       $slots = new RevisionSlots( [ SlotRecord::MAIN => $mainSlot ] );
                } else {
                        // XXX: do we need the same kind of caching here
                        // that getKnownCurrentRevision uses (if $revId == page_latest?)
@@ -1711,8 +1727,8 @@ class RevisionStore
                                $row->ar_actor ?? null
                        );
                } catch ( InvalidArgumentException $ex ) {
-                       wfWarn( __METHOD__ . ': ' . $ex->getMessage() );
-                       $user = new UserIdentityValue( 0, '', 0 );
+                       wfWarn( __METHOD__ . ': ' . $title->getPrefixedDBkey() . ': ' . $ex->getMessage() );
+                       $user = new UserIdentityValue( 0, 'Unknown user', 0 );
                }
 
                $db = $this->getDBConnectionRefForQueryFlags( $queryFlags );
@@ -1759,8 +1775,8 @@ class RevisionStore
                                $row->rev_actor ?? null
                        );
                } catch ( InvalidArgumentException $ex ) {
-                       wfWarn( __METHOD__ . ': ' . $ex->getMessage() );
-                       $user = new UserIdentityValue( 0, '', 0 );
+                       wfWarn( __METHOD__ . ': ' . $title->getPrefixedDBkey() . ': ' . $ex->getMessage() );
+                       $user = new UserIdentityValue( 0, 'Unknown user', 0 );
                }
 
                $db = $this->getDBConnectionRefForQueryFlags( $queryFlags );
@@ -2346,7 +2362,7 @@ class RevisionStore
                        $ret['fields']['slot_revision_id'] = 'slots.rev_id';
                        $ret['fields']['slot_content_id'] = 'NULL';
                        $ret['fields']['slot_origin'] = 'slots.rev_id';
-                       $ret['fields']['role_name'] = $db->addQuotes( 'main' );
+                       $ret['fields']['role_name'] = $db->addQuotes( SlotRecord::MAIN );
 
                        if ( in_array( 'content', $options, true ) ) {
                                $ret['fields']['content_size'] = 'slots.rev_len';