Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
FilePageRedirectHandlingRevisionLookup
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
3 / 3
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEntityRevision
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLatestRevisionId
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2
3namespace Wikibase\MediaInfo\DataAccess\Store;
4
5use MediaWiki\Revision\RevisionStore;
6use Wikibase\DataModel\Entity\EntityId;
7use Wikibase\Lib\Store\EntityRevisionLookup;
8use Wikibase\Lib\Store\InconsistentRedirectException;
9use Wikibase\Lib\Store\LatestRevisionIdResult;
10use Wikibase\Lib\Store\LookupConstants;
11use Wikibase\Lib\Store\Sql\WikiPageEntityDataLoader;
12use Wikibase\Lib\Store\StorageException;
13use Wikimedia\Rdbms\IDBAccessObject;
14
15/**
16 * This service works around (intended behaviour does not seem fully defined as of 2019-10)
17 * issues that arise when the file page is marked as a redirected (e.g. by an edit to
18 * file page's wikitext content adding #REDIRECT) but the mediainfo entity data "slot"
19 * does not contain "entity redirect" data but "regular" entity data.
20 *
21 * In such cases, getLatestRevisionId returns the revision ID of the Entity related to
22 * the "source" file page, not of the entity related to the file page the page redirects to.
23 *
24 * For details see: https://phabricator.wikimedia.org/T229280
25 *
26 * @license GPL-2.0-or-later
27 */
28class FilePageRedirectHandlingRevisionLookup implements EntityRevisionLookup {
29
30    public function __construct(
31        private readonly EntityRevisionLookup $lookup,
32        private readonly RevisionStore $revisionStore,
33        private readonly WikiPageEntityDataLoader $entityDataLoader,
34    ) {
35    }
36
37    /** @inheritDoc */
38    public function getEntityRevision(
39        EntityId $entityId,
40        $revisionId = 0,
41        $mode = LookupConstants::LATEST_FROM_REPLICA
42    ) {
43        return $this->lookup->getEntityRevision( $entityId, $revisionId, $mode );
44    }
45
46    /** @inheritDoc */
47    public function getLatestRevisionId( EntityId $entityId, $mode = LookupConstants::LATEST_FROM_REPLICA ) {
48        try {
49            return $this->lookup->getLatestRevisionId( $entityId, $mode );
50        } catch ( InconsistentRedirectException $e ) {
51            $revStoreFlags = ( $mode == LookupConstants::LATEST_FROM_MASTER
52                || $mode == LookupConstants::LATEST_FROM_REPLICA_WITH_FALLBACK )
53                ? IDBAccessObject::READ_LATEST : 0;
54
55            // TODO: WikiPageEntityMetaDataLookup should use RevisionStore::getQueryInfo,
56            // then we could use RevisionStore::newRevisionFromRow here!
57            $revisionId = $e->getRevisionId();
58            $slotRole = $e->getSlotRole();
59            $revision = $this->revisionStore->getRevisionById( $revisionId, $revStoreFlags );
60            [ $entityRevision, $redirect ] = $this->entityDataLoader->loadEntityDataFromWikiPageRevision(
61                $revision, $slotRole, $revStoreFlags
62            );
63
64            if ( $redirect ) {
65                return LatestRevisionIdResult::redirect(
66                    $revisionId,
67                    $redirect->getTargetId()
68                );
69            }
70            // Otherwise, if a valid entity document can be created, return the latest revision ID.
71            if ( $entityRevision ) {
72                return LatestRevisionIdResult::concreteRevision( $revisionId, $entityRevision->getTimestamp() );
73            }
74            // Otherwise, something is wrong.
75            throw new StorageException(
76                'The serialized data of revision ' . $revisionId
77                . ' contains neither an Entity nor an EntityRedirect!'
78            );
79        }
80    }
81
82}