Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
69.23% covered (warning)
69.23%
18 / 26
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ArchiveChangeListener
69.23% covered (warning)
69.23%
18 / 26
40.00% covered (danger)
40.00%
2 / 5
11.36
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isEnabled
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 onPageDeleteComplete
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 onPageUndeleteComplete
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace CirrusSearch;
4
5use CirrusSearch\Job\DeleteArchive;
6use CirrusSearch\Job\IndexArchive;
7use JobQueueGroup;
8use ManualLogEntry;
9use MediaWiki\Config\ConfigFactory;
10use MediaWiki\Page\Hook\PageDeleteCompleteHook;
11use MediaWiki\Page\Hook\PageUndeleteCompleteHook;
12use MediaWiki\Page\ProperPageIdentity;
13use MediaWiki\Permissions\Authority;
14use MediaWiki\Revision\RevisionRecord;
15use MediaWiki\Title\Title;
16use MediaWiki\Utils\MWTimestamp;
17use Wikimedia\Assert\Assert;
18
19/**
20 * Change listener responsible for writing to the archive index.
21 */
22class ArchiveChangeListener implements PageDeleteCompleteHook, PageUndeleteCompleteHook {
23    private JobQueueGroup $jobQueue;
24    private SearchConfig $searchConfig;
25
26    public function __construct( JobQueueGroup $jobQueue, SearchConfig $searchConfig ) {
27        $this->jobQueue = $jobQueue;
28        $this->searchConfig = $searchConfig;
29    }
30
31    public static function create(
32        JobQueueGroup $jobQueue,
33        ConfigFactory $configFactory
34    ): ArchiveChangeListener {
35        /** @phan-suppress-next-line PhanTypeMismatchArgumentSuperType $config is actually a SearchConfig */
36        return new self( $jobQueue, $configFactory->makeConfig( "CirrusSearch" ) );
37    }
38
39    private function isEnabled(): bool {
40        if ( !$this->searchConfig->get( 'CirrusSearchIndexDeletes' ) ) {
41            return false;
42        }
43        return $this->searchConfig
44                   ->getClusterAssignment()
45                   ->getWritableClusters( UpdateGroup::ARCHIVE ) != [];
46    }
47
48    /**
49     * @param ProperPageIdentity $page
50     * @param Authority $deleter
51     * @param string $reason
52     * @param int $pageID
53     * @param RevisionRecord $deletedRev
54     * @param ManualLogEntry $logEntry
55     * @param int $archivedRevisionCount
56     * @return void
57     */
58    public function onPageDeleteComplete( ProperPageIdentity $page, Authority $deleter,
59        string $reason, int $pageID, RevisionRecord $deletedRev, ManualLogEntry $logEntry,
60        int $archivedRevisionCount
61    ) {
62        if ( !$this->isEnabled() ) {
63            // Not indexing, thus nothing to remove here.
64            return;
65        }
66        // Note that we must use the article id provided or it'll be lost in the ether.  The job can't
67        // load it from the title because the page row has already been deleted.
68        $title = Title::castFromPageIdentity( $page );
69        Assert::postcondition( $title !== null, '$page can be cast to a Title' );
70        $this->jobQueue->lazyPush(
71            IndexArchive::build(
72                $title,
73                $this->searchConfig->makeId( $pageID ),
74                $logEntry->getTimestamp() !== false ? MWTimestamp::convert( TS_UNIX, $logEntry->getTimestamp() ) : MWTimestamp::time()
75            )
76        );
77    }
78
79    /**
80     * When article is undeleted - check the archive for other instances of the title,
81     * if not there - drop it from the archive.
82     * @param ProperPageIdentity $page
83     * @param Authority $restorer
84     * @param string $reason
85     * @param RevisionRecord $restoredRev
86     * @param ManualLogEntry $logEntry
87     * @param int $restoredRevisionCount
88     * @param bool $created
89     * @param array $restoredPageIds
90     * @return void
91     */
92    public function onPageUndeleteComplete(
93        ProperPageIdentity $page,
94        Authority $restorer,
95        string $reason,
96        RevisionRecord $restoredRev,
97        ManualLogEntry $logEntry,
98        int $restoredRevisionCount,
99        bool $created,
100        array $restoredPageIds
101    ): void {
102        if ( !$this->isEnabled() ) {
103            // Not indexing, thus nothing to remove here.
104            return;
105        }
106        $title = Title::castFromPageIdentity( $page );
107        Assert::postcondition( $title !== null, '$page can be cast to a Title' );
108        $this->jobQueue->lazyPush(
109            new DeleteArchive( $title, [ 'docIds' => $restoredPageIds ] )
110        );
111    }
112}