Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.84% covered (warning)
86.84%
33 / 38
83.33% covered (warning)
83.33%
15 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImageLinksTable
86.84% covered (warning)
86.84%
33 / 38
83.33% covered (warning)
83.33%
15 / 18
25.31
0.00% covered (danger)
0.00%
0 / 1
 setParserOutput
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getTableName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFromField
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getExistingFields
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNewLinkIDs
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 getExistingLinks
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getExistingLinkIDs
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isExisting
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isInNewSet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 needForcedLinkRefresh
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 insertLink
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 deleteLink
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 makePageReferenceValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 makeTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 deduplicateLinkIds
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 finishUpdate
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 invalidateImageDescriptions
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 virtualDomain
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Deferred\LinksUpdate;
4
5use MediaWiki\JobQueue\Utils\PurgeJobUtils;
6use MediaWiki\Page\PageReferenceValue;
7use MediaWiki\Parser\ParserOutput;
8use MediaWiki\Parser\ParserOutputLinkTypes;
9use MediaWiki\Title\Title;
10
11/**
12 * imagelinks
13 *
14 * Link ID format: string image name
15 *
16 * @since 1.38
17 */
18class ImageLinksTable extends TitleLinksTable {
19    public const VIRTUAL_DOMAIN = 'virtual-imagelinks';
20    /**
21     * @var array New links with the name in the key, value arbitrary
22     */
23    private $newLinks;
24
25    /**
26     * @var array Existing links with the name in the key, value arbitrary
27     */
28    private $existingLinks;
29
30    public function setParserOutput( ParserOutput $parserOutput ) {
31        // Convert the format of the local links
32        $this->newLinks = [];
33        foreach (
34            $parserOutput->getLinkList( ParserOutputLinkTypes::MEDIA )
35            as [ 'link' => $link ]
36        ) {
37            $this->newLinks[$link->getDBkey()] = 1;
38        }
39    }
40
41    /** @inheritDoc */
42    protected function getTableName() {
43        return 'imagelinks';
44    }
45
46    /** @inheritDoc */
47    protected function getFromField() {
48        return 'il_from';
49    }
50
51    /** @inheritDoc */
52    protected function getExistingFields() {
53        return [ 'il_to' ];
54    }
55
56    /** @inheritDoc */
57    protected function getNewLinkIDs() {
58        foreach ( $this->newLinks as $link => $unused ) {
59            yield (string)$link;
60        }
61    }
62
63    /**
64     * Get existing links with the name in the key, value arbitrary.
65     *
66     * @return array
67     */
68    private function getExistingLinks() {
69        if ( $this->existingLinks === null ) {
70            $this->existingLinks = [];
71            foreach ( $this->fetchExistingRows() as $row ) {
72                $this->existingLinks[$row->il_to] = true;
73            }
74        }
75        return $this->existingLinks;
76    }
77
78    /** @inheritDoc */
79    protected function getExistingLinkIDs() {
80        foreach ( $this->getExistingLinks() as $link => $unused ) {
81            yield (string)$link;
82        }
83    }
84
85    /** @inheritDoc */
86    protected function isExisting( $linkId ) {
87        return \array_key_exists( $linkId, $this->getExistingLinks() );
88    }
89
90    /** @inheritDoc */
91    protected function isInNewSet( $linkId ) {
92        return \array_key_exists( $linkId, $this->newLinks );
93    }
94
95    /** @inheritDoc */
96    protected function needForcedLinkRefresh() {
97        return $this->isCrossNamespaceMove();
98    }
99
100    /** @inheritDoc */
101    protected function insertLink( $linkId ) {
102        $this->insertRow( [
103            'il_from_namespace' => $this->getSourcePage()->getNamespace(),
104            'il_to' => $linkId
105        ] );
106    }
107
108    /** @inheritDoc */
109    protected function deleteLink( $linkId ) {
110        $this->deleteRow( [ 'il_to' => $linkId ] );
111    }
112
113    /** @inheritDoc */
114    protected function makePageReferenceValue( $linkId ): PageReferenceValue {
115        return PageReferenceValue::localReference( NS_FILE, $linkId );
116    }
117
118    /** @inheritDoc */
119    protected function makeTitle( $linkId ): Title {
120        return Title::makeTitle( NS_FILE, $linkId );
121    }
122
123    /** @inheritDoc */
124    protected function deduplicateLinkIds( $linkIds ) {
125        if ( !is_array( $linkIds ) ) {
126            $linkIds = iterator_to_array( $linkIds );
127        }
128        return array_unique( $linkIds );
129    }
130
131    protected function finishUpdate() {
132        // A update of namespace on cross namespace move is detected as insert + delete,
133        // but the updates are not needed there.
134        $allInsertedLinks = array_column( $this->insertedLinks, 0 );
135        $allDeletedLinks = array_column( $this->deletedLinks, 0 );
136        $insertedLinks = array_diff( $allInsertedLinks, $allDeletedLinks );
137        $deletedLinks = array_diff( $allDeletedLinks, $allInsertedLinks );
138
139        $this->invalidateImageDescriptions( $insertedLinks, $deletedLinks );
140    }
141
142    /**
143     * Invalidate all image description pages which had links added or removed
144     * @param array $insertedLinks
145     * @param array $deletedLinks
146     */
147    private function invalidateImageDescriptions( array $insertedLinks, array $deletedLinks ) {
148        PurgeJobUtils::invalidatePages(
149            $this->getDB(), NS_FILE,
150            array_merge( $insertedLinks, $deletedLinks ) );
151    }
152
153    /** @inheritDoc */
154    protected function virtualDomain() {
155        return self::VIRTUAL_DOMAIN;
156    }
157}