Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.56% covered (warning)
80.56%
29 / 36
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
MainSlotRoleHandler
80.56% covered (warning)
80.56%
29 / 36
75.00% covered (warning)
75.00%
3 / 4
22.94
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 supportsArticleCount
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isAllowedModel
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultModel
74.07% covered (warning)
74.07%
20 / 27
0.00% covered (danger)
0.00%
0 / 1
22.04
1<?php
2/**
3 * This file is part of MediaWiki.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 */
22
23namespace MediaWiki\Revision;
24
25use MediaWiki\Content\IContentHandlerFactory;
26use MediaWiki\HookContainer\HookContainer;
27use MediaWiki\HookContainer\HookRunner;
28use MediaWiki\Linker\LinkTarget;
29use MediaWiki\Page\PageIdentity;
30use MediaWiki\Title\TitleFactory;
31use MWUnknownContentModelException;
32
33/**
34 * A SlotRoleHandler for the main slot. While most slot roles serve a specific purpose and
35 * thus typically exhibit the same behaviour on all pages, the main slot is used for different
36 * things in different pages, typically depending on the namespace, a "file extension" in
37 * the page name, or the content model of the slot's content.
38 *
39 * MainSlotRoleHandler implements some of the per-namespace and per-model behavior that was
40 * supported prior to MediaWiki Version 1.33.
41 *
42 * @since 1.33
43 */
44class MainSlotRoleHandler extends SlotRoleHandler {
45
46    /**
47     * @var string[] A mapping of namespaces to content models.
48     * @see $wgNamespaceContentModels
49     */
50    private $namespaceContentModels;
51
52    /** @var IContentHandlerFactory */
53    private $contentHandlerFactory;
54
55    /** @var HookRunner */
56    private $hookRunner;
57
58    /** @var TitleFactory */
59    private $titleFactory;
60
61    /**
62     * @param string[] $namespaceContentModels A mapping of namespaces to content models,
63     *        typically from $wgNamespaceContentModels.
64     * @param IContentHandlerFactory $contentHandlerFactory
65     * @param HookContainer $hookContainer
66     * @param TitleFactory $titleFactory
67     */
68    public function __construct(
69        array $namespaceContentModels,
70        IContentHandlerFactory $contentHandlerFactory,
71        HookContainer $hookContainer,
72        TitleFactory $titleFactory
73    ) {
74        parent::__construct( SlotRecord::MAIN, CONTENT_MODEL_WIKITEXT );
75        $this->namespaceContentModels = $namespaceContentModels;
76        $this->contentHandlerFactory = $contentHandlerFactory;
77        $this->hookRunner = new HookRunner( $hookContainer );
78        $this->titleFactory = $titleFactory;
79    }
80
81    public function supportsArticleCount() {
82        return true;
83    }
84
85    /**
86     * @param string $model
87     * @param PageIdentity $page
88     *
89     * @return bool
90     * @throws MWUnknownContentModelException
91     */
92    public function isAllowedModel( $model, PageIdentity $page ) {
93        $title = $this->titleFactory->newFromPageIdentity( $page );
94        $handler = $this->contentHandlerFactory->getContentHandler( $model );
95
96        return $handler->canBeUsedOn( $title );
97    }
98
99    /**
100     * @param LinkTarget|PageIdentity $page
101     *
102     * @return string
103     */
104    public function getDefaultModel( $page ) {
105        // NOTE: this method must not rely on $title->getContentModel() directly or indirectly,
106        //       because it is used to initialize the mContentModel member.
107
108        $ext = '';
109        $ns = $page->getNamespace();
110        $model = $this->namespaceContentModels[$ns] ?? null;
111
112        // Hook can determine default model
113        if ( $page instanceof PageIdentity ) {
114            $title = $this->titleFactory->newFromPageIdentity( $page );
115        } else {
116            $title = $this->titleFactory->newFromLinkTarget( $page );
117        }
118        // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
119        if ( !$this->hookRunner->onContentHandlerDefaultModelFor( $title, $model ) && $model !== null ) {
120            return $model;
121        }
122
123        // Could this page contain code based on the title?
124        $isCodePage = $ns === NS_MEDIAWIKI && preg_match( '!\.(css|js|json)$!u', $title->getText(), $m );
125        if ( $isCodePage ) {
126            $ext = $m[1];
127        }
128
129        // Is this a user subpage containing code?
130        $isCodeSubpage = $ns === NS_USER
131            && !$isCodePage
132            && preg_match( "/\\/.*\\.(js|css|json)$/", $title->getText(), $m );
133
134        if ( $isCodeSubpage ) {
135            $ext = $m[1];
136        }
137
138        // Is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook?
139        $isWikitext = $model === null || $model == CONTENT_MODEL_WIKITEXT;
140        $isWikitext = $isWikitext && !$isCodePage && !$isCodeSubpage;
141
142        if ( !$isWikitext ) {
143            switch ( $ext ) {
144                case 'js':
145                    return CONTENT_MODEL_JAVASCRIPT;
146                case 'css':
147                    return CONTENT_MODEL_CSS;
148                case 'json':
149                    return CONTENT_MODEL_JSON;
150                default:
151                    return $model ?? CONTENT_MODEL_TEXT;
152            }
153        }
154
155        // We established that it must be wikitext
156
157        return CONTENT_MODEL_WIKITEXT;
158    }
159
160}