Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialUnwatchedPages
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 10
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 isExpensive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isSyndicated
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 preprocessResults
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getQueryInfo
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
2
 sortDescending
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOrderFields
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 formatResult
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Copyright © 2005 Ævar Arnfjörð Bjarmason
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace MediaWiki\Specials;
10
11use MediaWiki\Html\Html;
12use MediaWiki\Language\ILanguageConverter;
13use MediaWiki\Languages\LanguageConverterFactory;
14use MediaWiki\Linker\Linker;
15use MediaWiki\Page\LinkBatchFactory;
16use MediaWiki\Skin\Skin;
17use MediaWiki\SpecialPage\QueryPage;
18use MediaWiki\Title\Title;
19use stdClass;
20use Wikimedia\HtmlArmor\HtmlArmor;
21use Wikimedia\Rdbms\IConnectionProvider;
22use Wikimedia\Rdbms\IReadableDatabase;
23use Wikimedia\Rdbms\IResultWrapper;
24
25/**
26 * List of pages that are not on anyone's watchlist.
27 *
28 * @ingroup SpecialPage
29 * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
30 */
31class SpecialUnwatchedPages extends QueryPage {
32
33    private LinkBatchFactory $linkBatchFactory;
34    private ILanguageConverter $languageConverter;
35
36    public function __construct(
37        LinkBatchFactory $linkBatchFactory,
38        IConnectionProvider $dbProvider,
39        LanguageConverterFactory $languageConverterFactory
40    ) {
41        parent::__construct( 'Unwatchedpages', 'unwatchedpages' );
42        $this->linkBatchFactory = $linkBatchFactory;
43        $this->setDatabaseProvider( $dbProvider );
44        $this->languageConverter = $languageConverterFactory->getLanguageConverter( $this->getContentLanguage() );
45    }
46
47    /** @inheritDoc */
48    public function isExpensive() {
49        return true;
50    }
51
52    /** @inheritDoc */
53    public function isSyndicated() {
54        return false;
55    }
56
57    /**
58     * Pre-cache page existence to speed up link generation
59     *
60     * @param IReadableDatabase $db
61     * @param IResultWrapper $res
62     */
63    public function preprocessResults( $db, $res ) {
64        if ( !$res->numRows() ) {
65            return;
66        }
67
68        $batch = $this->linkBatchFactory->newLinkBatch()->setCaller( __METHOD__ );
69        foreach ( $res as $row ) {
70            $batch->add( $row->namespace, $row->title );
71        }
72        $batch->execute();
73
74        $res->seek( 0 );
75    }
76
77    /** @inheritDoc */
78    public function getQueryInfo() {
79        $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
80        return [
81            'tables' => [ 'page', 'watchlist' ],
82            'fields' => [
83                'namespace' => 'page_namespace',
84                'title' => 'page_title',
85                'value' => 'page_namespace'
86            ],
87            'conds' => [
88                'wl_title' => null,
89                'page_is_redirect' => 0,
90                $dbr->expr( 'page_namespace', '!=', NS_MEDIAWIKI ),
91            ],
92            'join_conds' => [ 'watchlist' => [
93                'LEFT JOIN', [ 'wl_title = page_title',
94                    'wl_namespace = page_namespace' ] ] ]
95        ];
96    }
97
98    /** @inheritDoc */
99    protected function sortDescending() {
100        return false;
101    }
102
103    /** @inheritDoc */
104    protected function getOrderFields() {
105        return [ 'page_namespace', 'page_title' ];
106    }
107
108    /**
109     * Add the JS
110     * @param string|null $par
111     */
112    public function execute( $par ) {
113        parent::execute( $par );
114        $this->getOutput()->addModules( 'mediawiki.special.unwatchedPages' );
115        $this->addHelpLink( 'Help:Watchlist' );
116    }
117
118    /**
119     * @param Skin $skin
120     * @param stdClass $result Result row
121     * @return string
122     */
123    public function formatResult( $skin, $result ) {
124        $nt = Title::makeTitleSafe( $result->namespace, $result->title );
125        if ( !$nt ) {
126            return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ],
127                Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
128        }
129
130        $text = $this->languageConverter->convertHtml( $nt->getPrefixedText() );
131
132        $linkRenderer = $this->getLinkRenderer();
133
134        $plink = $linkRenderer->makeKnownLink( $nt, new HtmlArmor( $text ) );
135        $wlink = $linkRenderer->makeKnownLink(
136            $nt,
137            $this->msg( 'watch' )->text(),
138            [ 'class' => 'mw-watch-link' ],
139            [ 'action' => 'watch' ]
140        );
141
142        return $this->getLanguage()->specialList( $plink, $wlink );
143    }
144
145    /** @inheritDoc */
146    protected function getGroupName() {
147        return 'maintenance';
148    }
149}
150
151/**
152 * Retain the old class name for backwards compatibility.
153 * @deprecated since 1.41
154 */
155class_alias( SpecialUnwatchedPages::class, 'SpecialUnwatchedPages' );