Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 14
702
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
 onGetDoubleUnderscoreIDs
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onWgQueryPages
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 excludeDisambiguationPages
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 onAncientPagesQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onLonelyPagesQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onShortPagesQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onRandomPageQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onGetLinkColours
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 onListDefinedTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onChangeTagsListActive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onLinksUpdateComplete
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 onEditPage__showEditForm_initial
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
30
 onRecentChange_save
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Hooks for Disambiguator extension
4 *
5 * @file
6 * @ingroup Extensions
7 */
8
9namespace MediaWiki\Extension\Disambiguator;
10
11use ExtensionRegistry;
12use MediaWiki\ChangeTags\Hook\ChangeTagsListActiveHook;
13use MediaWiki\ChangeTags\Hook\ListDefinedTagsHook;
14use MediaWiki\Config\Config;
15use MediaWiki\Deferred\LinksUpdate\LinksUpdate;
16use MediaWiki\EditPage\EditPage;
17use MediaWiki\Extension\Disambiguator\Specials\SpecialDisambiguationPageLinks;
18use MediaWiki\Extension\Disambiguator\Specials\SpecialDisambiguationPages;
19use MediaWiki\Hook\AncientPagesQueryHook;
20use MediaWiki\Hook\EditPage__showEditForm_initialHook;
21use MediaWiki\Hook\GetDoubleUnderscoreIDsHook;
22use MediaWiki\Hook\GetLinkColoursHook;
23use MediaWiki\Hook\LonelyPagesQueryHook;
24use MediaWiki\Hook\RandomPageQueryHook;
25use MediaWiki\Hook\RecentChange_saveHook;
26use MediaWiki\Hook\ShortPagesQueryHook;
27use MediaWiki\MediaWikiServices;
28use MediaWiki\Output\OutputPage;
29use MediaWiki\SpecialPage\Hook\WgQueryPagesHook;
30use MediaWiki\Title\Title;
31
32// phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
33class Hooks implements
34    ListDefinedTagsHook,
35    ChangeTagsListActiveHook,
36    RecentChange_saveHook,
37    EditPage__showEditForm_initialHook,
38    GetDoubleUnderscoreIDsHook,
39    WgQueryPagesHook,
40    AncientPagesQueryHook,
41    LonelyPagesQueryHook,
42    ShortPagesQueryHook,
43    RandomPageQueryHook,
44    GetLinkColoursHook
45{
46
47    private const TAGS = [
48        'disambiguator-link-added'
49    ];
50
51    /** @var Lookup */
52    private $lookup;
53
54    /** @var bool */
55    private $showNotifications;
56
57    /** @var bool[] Rev IDs are used as keys */
58    private static $revsToTag = [];
59
60    /**
61     * @param Lookup $lookup
62     * @param Config $options
63     */
64    public function __construct( Lookup $lookup, Config $options ) {
65        $this->lookup = $lookup;
66        $this->showNotifications = $options->get( 'DisambiguatorNotifications' );
67    }
68
69    /**
70     * @param array &$doubleUnderscoreIDs
71     */
72    public function onGetDoubleUnderscoreIDs( &$doubleUnderscoreIDs ) {
73        $doubleUnderscoreIDs[] = 'disambiguation';
74    }
75
76    /**
77     * Add the Disambiguator special pages to the list of QueryPages. This
78     * allows direct access via the API.
79     * @param array &$queryPages
80     */
81    public function onWgQueryPages( &$queryPages ) {
82        $queryPages[] = [ SpecialDisambiguationPages::class, 'DisambiguationPages' ];
83        $queryPages[] = [ SpecialDisambiguationPageLinks::class, 'DisambiguationPageLinks' ];
84    }
85
86    /**
87     * Modify query parameters to ignore disambiguation pages
88     * @param array &$tables
89     * @param array &$conds
90     * @param array &$joinConds
91     */
92    private static function excludeDisambiguationPages( &$tables, &$conds, &$joinConds ) {
93        $tables['disambig_props'] = 'page_props';
94        $conds['disambig_props.pp_page'] = null;
95        $joinConds['disambig_props'] = [
96            'LEFT JOIN', [
97                'page_id = disambig_props.pp_page',
98                'disambig_props.pp_propname' => 'disambiguation'
99            ]
100        ];
101    }
102
103    /**
104     * Modify the Special:AncientPages query to ignore disambiguation pages
105     * @param array &$tables
106     * @param array &$conds
107     * @param array &$joinConds
108     */
109    public function onAncientPagesQuery( &$tables, &$conds, &$joinConds ) {
110        self::excludeDisambiguationPages( $tables, $conds, $joinConds );
111    }
112
113    /**
114     * Modify the Special:LonelyPages query to ignore disambiguation pages
115     * @param array &$tables
116     * @param array &$conds
117     * @param array &$joinConds
118     */
119    public function onLonelyPagesQuery( &$tables, &$conds, &$joinConds ) {
120        self::excludeDisambiguationPages( $tables, $conds, $joinConds );
121    }
122
123    /**
124     * Modify the Special:ShortPages query to ignore disambiguation pages
125     * @param array &$tables
126     * @param array &$conds
127     * @param array &$joinConds
128     * @param array &$options
129     */
130    public function onShortPagesQuery( &$tables, &$conds, &$joinConds, &$options ) {
131        self::excludeDisambiguationPages( $tables, $conds, $joinConds );
132    }
133
134    /**
135     * Modify the Special:Random query to ignore disambiguation pages
136     * @param array &$tables
137     * @param array &$conds
138     * @param array &$joinConds
139     */
140    public function onRandomPageQuery( &$tables, &$conds, &$joinConds ) {
141        self::excludeDisambiguationPages( $tables, $conds, $joinConds );
142    }
143
144    /**
145     * Add 'mw-disambig' CSS class to links to disambiguation pages.
146     * @param array $pageIdToDbKey Prefixed DB keys of the pages linked to, indexed by page_id
147     * @param array &$colours CSS classes, indexed by prefixed DB keys
148     * @param Title $title
149     */
150    public function onGetLinkColours( $pageIdToDbKey, &$colours, $title ) {
151        global $wgDisambiguatorIndicateLinks;
152        if ( !$wgDisambiguatorIndicateLinks ) {
153            return;
154        }
155
156        $pageIds = $this->lookup->filterDisambiguationPageIds(
157            array_keys( $pageIdToDbKey )
158        );
159
160        foreach ( $pageIds as $pageId ) {
161            if ( isset( $colours[ $pageIdToDbKey[$pageId] ] ) ) {
162                $colours[ $pageIdToDbKey[$pageId] ] .= ' mw-disambig';
163            } else {
164                $colours[ $pageIdToDbKey[$pageId] ] = 'mw-disambig';
165            }
166        }
167    }
168
169    /**
170     * Implements the ListDefinedTags hook, to populate core
171     * Special:Tags with the change tags used by Disambiguator.
172     *
173     * @param string[] &$tags List of all active tags. Append to this array.
174     */
175    public function onListDefinedTags( &$tags ) {
176        $tags = array_merge( $tags, static::TAGS );
177    }
178
179    /**
180     * Implements the ChangeTagsListActive hook, to mark the
181     * Disambiguator change tag as active.
182     *
183     * @param array &$tags Available change tags.
184     */
185    public function onChangeTagsListActive( &$tags ) {
186        $tags = array_merge( $tags, static::TAGS );
187    }
188
189    /**
190     * Add a change tag to edits that introduce links to disambiguation pages.
191     *
192     * @param LinksUpdate $linksUpdate
193     */
194    public function onLinksUpdateComplete( LinksUpdate $linksUpdate ) {
195        $addedLinks = $linksUpdate->getAddedLinks();
196
197        if ( !$addedLinks ) {
198            return;
199        }
200
201        $pageIds = array_map( static function ( Title $title ) {
202            return $title->getId();
203        }, $addedLinks );
204
205        $disambigs = $this->lookup->filterDisambiguationPageIds( $pageIds, true );
206        $rev = $linksUpdate->getRevisionRecord();
207
208        if ( $disambigs && $rev ) {
209            self::$revsToTag[$rev->getId()] = true;
210        }
211    }
212
213    /**
214     * Add the modules to the edit form.
215     *
216     * @param EditPage $editor
217     * @param OutputPage $out
218     */
219    public function onEditPage__showEditForm_initial( $editor, $out ) {
220        if ( $editor->contentModel !== CONTENT_MODEL_WIKITEXT || !$this->showNotifications ) {
221            return;
222        }
223
224        // Add modules.
225        $services = MediaWikiServices::getInstance();
226        $isMobileView = ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) &&
227            $services->getService( 'MobileFrontend.Context' )->shouldDisplayMobileView();
228        if ( !$isMobileView ) {
229            $out->addModules( 'ext.disambiguator' );
230        }
231    }
232
233    /**
234     * @inheritDoc
235     */
236    // phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
237    public function onRecentChange_save( $recentChange ) {
238        $revId = $recentChange->getAttribute( 'rc_this_oldid' );
239        if ( $recentChange->getAttribute( 'rc_log_type' ) ) {
240            return;
241        }
242        if ( isset( self::$revsToTag[$revId] ) ) {
243            $recentChange->addTags( self::TAGS );
244            unset( self::$revsToTag[$revId] );
245        }
246    }
247}