Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
57.97% covered (warning)
57.97%
40 / 69
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SecondaryNavComponent
57.97% covered (warning)
57.97%
40 / 69
25.00% covered (danger)
25.00%
1 / 4
62.27
0.00% covered (danger)
0.00%
0 / 1
 __construct
66.67% covered (warning)
66.67%
18 / 27
0.00% covered (danger)
0.00%
0 / 1
10.37
 getSpecialSidebar
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
6
 getPageNav
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
56
 isActiveTitle
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
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.
7 *
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.
12 *
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 *
17 * @file
18 */
19namespace MediaWiki\Skin\WikimediaApiPortal\Component;
20
21use IContextSource;
22use MediaWiki\Config\ServiceOptions;
23use MediaWiki\Page\PageProps;
24use MediaWiki\SpecialPage\SpecialPageFactory;
25use MediaWiki\Title\NamespaceInfo;
26use MediaWiki\Title\Title;
27use MediaWiki\Title\TitleFactory;
28use Wikimedia\Message\IMessageFormatterFactory;
29
30class SecondaryNavComponent extends MessageComponent {
31    public const CONSTRUCTOR_OPTIONS = [
32        'WMAPIPSidebarSpecialPages',
33    ];
34
35    /**
36     * @param ServiceOptions $options
37     * @param IMessageFormatterFactory $messageFormatterFactory
38     * @param IContextSource $contextSource
39     * @param Title $title
40     * @param NamespaceInfo $namespaceInfo
41     * @param TitleFactory $titleFactory
42     * @param SpecialPageFactory $specialPageFactory
43     * @param PageProps $pageProps
44     */
45    public function __construct(
46        ServiceOptions $options,
47        IMessageFormatterFactory $messageFormatterFactory,
48        IContextSource $contextSource,
49        Title $title,
50        NamespaceInfo $namespaceInfo,
51        TitleFactory $titleFactory,
52        SpecialPageFactory $specialPageFactory,
53        PageProps $pageProps
54    ) {
55        parent::__construct( 'SecondaryNav', $messageFormatterFactory, $contextSource );
56
57        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
58
59        if ( $title->isSpecialPage() ) {
60            $specialSidebar = $this->getSpecialSidebar(
61                $title,
62                $options->get( 'WMAPIPSidebarSpecialPages' ),
63                $titleFactory,
64                $specialPageFactory
65            );
66            if ( $specialSidebar ) {
67                $this->args = [
68                    'items' => $specialSidebar
69                ];
70            }
71            return;
72        }
73
74        if ( $title->isTalkPage() ) {
75            $subjectNS = $namespaceInfo->getSubject( $title->getNamespace() );
76            $title = $titleFactory->makeTitleSafe( $subjectNS, $title->getDBkey() );
77        }
78
79        if ( !( $title && ( $title->isSubpage() || $title->hasSubpages() ) ) ) {
80            $this->args = null;
81            return;
82        }
83
84        $root = $titleFactory->makeTitleSafe( $title->getNamespace(), $title->getRootText() );
85        if ( !$root ) {
86            $this->args = null;
87            return;
88        }
89
90        $this->args = [
91            'items' => $this->getPageNav( $title, $root, $pageProps )
92        ];
93    }
94
95    /**
96     * @param Title $currentTitle
97     * @param array $sidebarSpecialPages
98     * @param TitleFactory $titleFactory
99     * @param SpecialPageFactory $specialPageFactory
100     * @return ?array
101     */
102    private function getSpecialSidebar(
103        Title $currentTitle,
104        array $sidebarSpecialPages,
105        TitleFactory $titleFactory,
106        SpecialPageFactory $specialPageFactory
107    ): ?array {
108        $items = [];
109        $found = false;
110        foreach ( $sidebarSpecialPages as $specialPageName ) {
111            $title = $titleFactory->newFromText( $specialPageName, NS_SPECIAL );
112            $specialPageObj = $specialPageFactory->getPage( $specialPageName );
113            if ( $title && $specialPageObj ) {
114                if ( $this->isActiveTitle( $currentTitle, $title ) ) {
115                    $found = true;
116                    $isActive = true;
117                    $href = '#';
118                } else {
119                    $isActive = false;
120                    $href = $title->getLocalURL();
121                }
122                $items[] = [
123                    'text' => $specialPageObj->getDescription(),
124                    'href' => $href,
125                    'isActive' => $isActive,
126                    'subpages' => false
127                ];
128            }
129        }
130        if ( $found ) {
131            return $items;
132        }
133        return null;
134    }
135
136    /**
137     * @param Title $currentTitle
138     * @param Title $parent
139     * @param PageProps $pageProps
140     * @return array
141     */
142    private function getPageNav(
143        Title $currentTitle,
144        Title $parent,
145        PageProps $pageProps
146    ): array {
147        $subpages = $parent->getSubpages();
148        if ( !count( $subpages ) ) {
149            return [];
150        }
151        $defaultsort = $pageProps->getProperties( $subpages, 'defaultsort' );
152        $nav = [];
153        foreach ( $subpages as $page ) {
154            if ( $page->getBaseText() !== $parent->getText() ) {
155                // Not direct sub
156                continue;
157            }
158
159            if ( $defaultsort && array_key_exists( $page->getArticleID(), $defaultsort ) ) {
160                $key = $defaultsort[$page->getArticleID()];
161            } else {
162                $key = $page->getSubpageText();
163            }
164            $nav[$key] = [
165                'isActive' => $this->isActiveTitle( $currentTitle, $page ),
166                'href' => $page->getLocalURL(),
167                'text' => $page->getSubpageText(),
168                'subpages' => $this->getPageNav( $currentTitle, $page, $pageProps ) ?: false,
169            ];
170        }
171        ksort( $nav );
172        return $nav;
173    }
174
175    /**
176     * Whether the Title points to the current title (or a subpage thereof).
177     * @param Title $currentTitle
178     * @param Title $title
179     * @return bool
180     */
181    private function isActiveTitle( Title $currentTitle, Title $title ): bool {
182        $currentTitle = $currentTitle->fixSpecialName();
183        return $currentTitle->equals( $title ) || $currentTitle->isSubpageOf( $title );
184    }
185}