Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
61.54% covered (warning)
61.54%
16 / 26
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SectionPositionCalculator
61.54% covered (warning)
61.54%
16 / 26
66.67% covered (warning)
66.67%
2 / 3
15.69
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 calculateSectionPosition
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 fetchAppendixTitles
16.67% covered (danger)
16.67%
2 / 12
0.00% covered (danger)
0.00%
0 / 1
13.26
1<?php
2declare( strict_types = 1 );
3
4namespace ContentTranslation\Service;
5
6use ContentTranslation\SiteMapper;
7use MediaWiki\Http\HttpRequestFactory;
8use MediaWiki\Json\FormatJson;
9use MediaWiki\Title\Title;
10
11class SectionPositionCalculator {
12    private const APPENDIX_TITLES = [
13        "en" => [
14            "Works",
15            "Publications",
16            "Bibliography",
17            "Discography",
18            "Filmography",
19            "See also",
20            "Notes",
21            "Citations",
22            "References",
23            "Further reading",
24            "External links"
25        ],
26        "es" => [
27            "Bibliografía",
28            "Referencias",
29            "Citas",
30            "Discografía",
31            "Filmografía",
32            "Notas",
33            "Publicaciones",
34            "Obra",
35            "Enlaces externos",
36            "Otras lecturas",
37            "Lecturas relacionadas",
38            "Véase también"
39        ],
40        "bn" => [
41            "গ্রন্থপঞ্জী",
42            "গ্রন্থপঞ্জি",
43            "তথ্যাবলি",
44            "উদ্ধৃতিসমূহ",
45            "বর্ণনসমূহ",
46            "উদ্ধৃতি",
47            "উদ্ধ্বৃতি",
48            "তথ্যসূত্র",
49            "ডিস্কোগ্রাফি",
50            "বহিঃসংযোগ",
51            "চলচ্চিত্রের তালিকা",
52            "আরও পড়ুন",
53            "আরও পড়ুন",
54            "আরো পড়ুন",
55            "টীকা",
56            "নোট",
57            "প্রকাশনা",
58            "প্রকাশিত গ্রন্থ",
59            "আরও দেখুন",
60            "আরো দেখুন",
61            "কাজ",
62            "কর্মজীবন"
63        ],
64        "fr" => [
65            "Bibliographie",
66            "Références",
67            "Discographie",
68            "Filmographie",
69            "Travaux",
70            "Liens externes",
71            "Principales publications",
72            "Voir aussi"
73        ],
74        "de" => [
75            "Literatur",
76            "Bibliographie",
77            "Anmerkungen",
78            "Zitate",
79            "Belege",
80            "Diskografie",
81            "Diskographie",
82            "Weblinks",
83            "Filmografie",
84            "Literatur",
85            "Einzelnachweise",
86            "Veröffentlichungen",
87            "Einzelnachweise",
88            "Arbeit",
89            "Siehe auch"
90        ]
91    ];
92
93    private HttpRequestFactory $httpRequestFactory;
94    private SectionTitleFetcher $sectionTitleFetcher;
95
96    public function __construct( HttpRequestFactory $httpRequestFactory, SectionTitleFetcher $sectionTitleFetcher ) {
97        $this->httpRequestFactory = $httpRequestFactory;
98        $this->sectionTitleFetcher = $sectionTitleFetcher;
99    }
100
101    /**
102     * This method returns the appropriate number indicating the position in
103     * which the new section should be published inside the target page,
104     * according to the following logic:
105     *
106     * 1. If the section is being published to user's sandbox, then the section
107     * position should be "new"
108     * 2. If section is a lead section then its position should be equal to 0.
109     * 3. If the section is neither a sandbox section nor a lead section:
110     *    a. If at least one appendix section exists then it equals to the
111     *       index of the first appendix section (in order of appearance)
112     *    b. If not, it's equal to "new".
113     *
114     * @param Title $targetTitle
115     * @param string $targetLanguage
116     * @param bool $isSandbox
117     * @return int|string
118     */
119    public function calculateSectionPosition( Title $targetTitle, string $targetLanguage, bool $isSandbox ) {
120        $sectionPosition = "new";
121        if ( $isSandbox ) {
122            return $sectionPosition;
123        }
124
125        $targetSectionTitles = $this->sectionTitleFetcher->fetchSectionTitles( $targetLanguage, $targetTitle );
126
127        // if target sections are null, this page doesn't exist, and this is a lead section
128        if ( $targetSectionTitles === null ) {
129            return 0;
130        }
131
132        if ( $targetSectionTitles ) {
133            $appendixTitles = $this->fetchAppendixTitles( $targetLanguage );
134
135            $targetAppendixTitles = array_intersect( $targetSectionTitles, $appendixTitles );
136            if ( $targetAppendixTitles ) {
137                $sectionPosition = array_key_first( $targetAppendixTitles );
138            }
139        }
140        return $sectionPosition;
141    }
142
143    /**
144     * Given a target language code, this method returns an array of
145     * strings containing the appendix section titles for this language.
146     *
147     * @param string $targetLanguage
148     * @return string[]
149     */
150    public function fetchAppendixTitles( string $targetLanguage ): array {
151        if ( isset( self::APPENDIX_TITLES[$targetLanguage] ) ) {
152            return self::APPENDIX_TITLES[$targetLanguage];
153        }
154
155        $baseUrl = "/suggest/sections/titles/en/$targetLanguage";
156        $params = [ 'titles' => implode( '|', self::APPENDIX_TITLES['en'] ) ];
157        $cxServerUrl = SiteMapper::getCXServerUrl( $baseUrl, $params );
158        try {
159            $response = $this->httpRequestFactory->get( $cxServerUrl, [], __METHOD__ );
160        } catch ( \Exception $exception ) {
161            return [];
162        }
163
164        if ( !$response ) {
165            return [];
166        }
167
168        $json = FormatJson::decode( $response, true );
169        return array_merge( ...array_values( $json ) );
170    }
171}