Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 5
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSandboxTitle
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 makeSandboxLink
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
72
 onSkinPreloadExistence
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 onSkinTemplateNavigation__Universal
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace MediaWiki\Extension\SandboxLink;
4
5use MediaWiki\Config\Config;
6use MediaWiki\Hook\SkinPreloadExistenceHook;
7use MediaWiki\Hook\SkinTemplateNavigation__UniversalHook;
8use MediaWiki\Title\Title;
9use Skin;
10
11/**
12 * Add a link to user's personal sandbox to personal tools menu.
13 *
14 * https://www.mediawiki.org/wiki/Extension:SandboxLink
15 *
16 * @file
17 * @license MIT
18 */
19class Hooks implements
20    SkinPreloadExistenceHook,
21    SkinTemplateNavigation__UniversalHook
22{
23    /** @var bool */
24    private $disableAnon;
25
26    /**
27     * @param Config $mainConfig
28     */
29    public function __construct( Config $mainConfig ) {
30        $this->disableAnon = $mainConfig->get( 'SandboxLinkDisableAnon' );
31    }
32
33    /**
34     * Return a Title for the page where the current user's sandbox is.
35     *
36     * @param Skin $skin For context
37     * @return Title|null
38     */
39    private function getSandboxTitle( Skin $skin ) {
40        if ( $this->disableAnon && !$skin->getUser()->isNamed() ) {
41            return null;
42        }
43
44        $subpageMsg = $skin->msg( 'sandboxlink-subpage-name' )->inContentLanguage();
45        if ( $subpageMsg->isDisabled() ) {
46            return null;
47        }
48        $username = $skin->getUser()->getName();
49        return Title::makeTitleSafe( NS_USER, $username . '/' . $subpageMsg->plain() );
50    }
51
52    /**
53     * Return a link descriptor for the page where the current user's sandbox is,
54     * relative to current title and in current language.
55     *
56     * @param Skin $skin For context
57     * @return array|null Link descriptor in a format accepted by PersonalUrls hook
58     */
59    private function makeSandboxLink( Skin $skin ) {
60        $currentTitle = $skin->getTitle();
61
62        $title = $this->getSandboxTitle( $skin );
63        if ( !$title ) {
64            return null;
65        }
66
67        if ( $title->exists() && $title->isRedirect() ) {
68            $href = $title->getLocalURL( [ 'redirect' => 'no' ] );
69        } elseif ( $title->exists() ) {
70            $href = $title->getLocalURL();
71        } else {
72            $query = [ 'action' => 'edit', 'redlink' => '1' ];
73
74            $editintroMsg = $skin->msg( 'sandboxlink-editintro-pagename' )->inContentLanguage();
75            if ( !$editintroMsg->isDisabled() ) {
76                $query['editintro'] = $editintroMsg->plain();
77            }
78
79            $preloadMsg = $skin->msg( 'sandboxlink-preload-pagename' )->inContentLanguage();
80            if ( !$preloadMsg->isDisabled() ) {
81                $query['preload'] = $preloadMsg->plain();
82            }
83
84            $href = $title->getLocalURL( $query );
85        }
86
87        return [
88            'id' => 'pt-sandbox',
89            'text' => $skin->msg( 'sandboxlink-portlet-label' )->text(),
90            'href' => $href,
91            'class' => $title->exists() ? false : 'new',
92            'icon' => 'sandbox',
93            'exists' => $title->exists(),
94            'active' => $title->equals( $currentTitle ),
95        ];
96    }
97
98    /**
99     * SkinPreloadExistence hook handler.
100     *
101     * Add the title of the page where the current user's sandbox is to link existence cache.
102     *
103     * @param Title[] &$titles
104     * @param Skin $skin
105     * @return bool true
106     */
107    public function onSkinPreloadExistence( &$titles, $skin ) {
108        $title = $this->getSandboxTitle( $skin );
109        if ( $title ) {
110            $titles[] = $title;
111        }
112        return true;
113    }
114
115    /**
116     * PersonalUrls hook handler.
117     *
118     * Possibly add a link to the page where the current user's sandbox is to personal tools menu.
119     *
120     * @param Skin $skin
121     * @param array &$links
122     * @phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
123     */
124    public function onSkinTemplateNavigation__Universal( $skin, &$links ): void {
125        // phpcs:enable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
126        // using // phpcs:ignore after docblock doesn't work, it shows
127        // MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic
128        $link = $this->makeSandboxLink( $skin );
129        if ( !$link ) {
130            return;
131        }
132
133        $newPersonalUrls = [];
134        $personalUrls = $links['user-menu'] ?? [];
135        // Insert our link before the link to user preferences.
136        // If the link to preferences is missing, insert at the end.
137        foreach ( $personalUrls as $key => $value ) {
138            if ( $key === 'preferences' ) {
139                $newPersonalUrls['sandbox'] = $link;
140            }
141            $newPersonalUrls[$key] = $value;
142        }
143        if ( !array_key_exists( 'sandbox', $newPersonalUrls ) ) {
144            $newPersonalUrls['sandbox'] = $link;
145        }
146
147        $links['user-menu'] = $newPersonalUrls;
148    }
149}