3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
21 namespace MediaWiki\Specials
;
23 use MediaWiki\Cache\LinkBatchFactory
;
24 use MediaWiki\Content\IContentHandlerFactory
;
25 use MediaWiki\SpecialPage\QueryPage
;
26 use MediaWiki\Title\Title
;
28 use Wikimedia\Rdbms\IConnectionProvider
;
29 use Wikimedia\Rdbms\IDatabase
;
30 use Wikimedia\Rdbms\IResultWrapper
;
33 * List of redirects to non-existent pages.
35 * Editors are encouraged to fix these by editing them to redirect to
36 * an existing page instead.
38 * @ingroup SpecialPage
40 class SpecialBrokenRedirects
extends QueryPage
{
42 private IContentHandlerFactory
$contentHandlerFactory;
45 * @param IContentHandlerFactory $contentHandlerFactory
46 * @param IConnectionProvider $dbProvider
47 * @param LinkBatchFactory $linkBatchFactory
49 public function __construct(
50 IContentHandlerFactory
$contentHandlerFactory,
51 IConnectionProvider
$dbProvider,
52 LinkBatchFactory
$linkBatchFactory
54 parent
::__construct( 'BrokenRedirects' );
55 $this->contentHandlerFactory
= $contentHandlerFactory;
56 $this->setDatabaseProvider( $dbProvider );
57 $this->setLinkBatchFactory( $linkBatchFactory );
60 public function isExpensive() {
64 public function isSyndicated() {
68 protected function sortDescending() {
72 protected function getPageHeader() {
73 return $this->msg( 'brokenredirectstext' )->parseAsBlock();
76 public function getQueryInfo() {
77 $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
86 'namespace' => 'p1.page_namespace',
87 'title' => 'p1.page_title',
93 // Exclude pages that don't exist locally as wiki pages, but aren't "broken" either: special
94 // pages and interwiki links.
95 $dbr->expr( 'rd_namespace', '>=', 0 ),
97 'p2.page_namespace' => null,
101 'rd_from=p1.page_id',
103 'p2' => [ 'LEFT JOIN', [
104 'rd_namespace=p2.page_namespace',
105 'rd_title=p2.page_title'
114 protected function getOrderFields() {
115 return [ 'rd_namespace', 'rd_title', 'rd_from' ];
120 * @param \stdClass $result Result row
123 public function formatResult( $skin, $result ) {
124 $fromObj = Title
::makeTitle( $result->namespace, $result->title
);
125 if ( isset( $result->rd_title
) ) {
126 $toObj = Title
::makeTitle(
127 $result->rd_namespace
,
135 $linkRenderer = $this->getLinkRenderer();
137 // $toObj may very easily be false if the $result list is cached
138 if ( !is_object( $toObj ) ) {
139 return '<del>' . $linkRenderer->makeLink( $fromObj ) . '</del>';
142 $from = $linkRenderer->makeKnownLink(
146 [ 'redirect' => 'no' ]
149 // if the page is editable, add an edit link
151 // check user permissions
152 $this->getAuthority()->isAllowed( 'edit' ) &&
153 // check, if the content model is editable through action=edit
154 $this->contentHandlerFactory
->getContentHandler( $fromObj->getContentModel() )
155 ->supportsDirectEditing()
157 $links[] = $linkRenderer->makeKnownLink(
159 $this->msg( 'brokenredirects-edit' )->text(),
161 [ 'action' => 'edit' ]
164 $to = $linkRenderer->makeBrokenLink( $toObj, $toObj->getFullText() );
165 $arr = $this->getLanguage()->getArrow();
167 $out = $from . $this->msg( 'word-separator' )->escaped();
169 if ( $this->getAuthority()->isAllowed( 'delete' ) ) {
170 $links[] = $linkRenderer->makeKnownLink(
172 $this->msg( 'brokenredirects-delete' )->text(),
175 'action' => 'delete',
176 'wpReason' => $this->msg( 'brokenredirects-delete-reason' )
177 ->inContentLanguage()
184 $out .= $this->msg( 'parentheses' )->rawParams( $this->getLanguage()
185 ->pipeList( $links ) )->escaped();
187 $out .= " {$arr} {$to}";
192 public function execute( $par ) {
193 $this->addHelpLink( 'Help:Redirects' );
194 parent
::execute( $par );
198 * Cache page content model for performance
200 * @param IDatabase $db
201 * @param IResultWrapper $res
203 public function preprocessResults( $db, $res ) {
204 $this->executeLBFromResultWrapper( $res );
207 protected function getGroupName() {
208 return 'maintenance';
212 /** @deprecated class alias since 1.41 */
213 class_alias( SpecialBrokenRedirects
::class, 'SpecialBrokenRedirects' );