Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
77.78% |
21 / 27 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
SectionTitleFetcher | |
77.78% |
21 / 27 |
|
50.00% |
1 / 2 |
11.10 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
fetchSectionTitles | |
76.92% |
20 / 26 |
|
0.00% |
0 / 1 |
10.00 |
1 | <?php |
2 | |
3 | declare( strict_types=1 ); |
4 | |
5 | namespace ContentTranslation\Service; |
6 | |
7 | use ContentTranslation\SiteMapper; |
8 | use InvalidArgumentException; |
9 | use MediaWiki\Http\HttpRequestFactory; |
10 | use MediaWiki\Json\FormatJson; |
11 | use MediaWiki\Title\Title; |
12 | |
13 | class SectionTitleFetcher { |
14 | |
15 | private HttpRequestFactory $httpRequestFactory; |
16 | |
17 | public function __construct( HttpRequestFactory $httpRequestFactory ) { |
18 | $this->httpRequestFactory = $httpRequestFactory; |
19 | } |
20 | |
21 | /** |
22 | * Given a target language code and a page title or a revision id (at least one of them |
23 | * should be provided), this method fetches the target page sections using the MediaWiki |
24 | * Action Api and returns an array containing the titles for all the first-level page sections, |
25 | * indexed by their section numbers. |
26 | * |
27 | * If the HTTP request for fetching the section titles fails, the method returns an |
28 | * empty array. |
29 | * |
30 | * If the sections cannot be successfully retrieved from the API (i.e. when the request is |
31 | * completed but the requested page doesn't exist), the method returns null. |
32 | * |
33 | * If both page title and page revision are provided, the page revision is ignored and only |
34 | * the page title is used. |
35 | * |
36 | * @param string $targetLanguage |
37 | * @param Title|null $pageTitle The title of the page |
38 | * @param int|null $revision |
39 | * @return string[]|null e.g. [ 1 => "Section 1", 2 => "Section 2" ] |
40 | */ |
41 | public function fetchSectionTitles( string $targetLanguage, ?Title $pageTitle, ?int $revision = null ): ?array { |
42 | if ( !$pageTitle && !$revision ) { |
43 | throw new InvalidArgumentException( 'Either page title or page revision should be provided' ); |
44 | } |
45 | |
46 | $params = [ |
47 | 'action' => 'parse', |
48 | 'prop' => 'sections', |
49 | 'format' => 'json', |
50 | 'formatversion' => 2 |
51 | ]; |
52 | |
53 | if ( $pageTitle ) { |
54 | $params['page'] = $pageTitle->getPrefixedDBKey(); |
55 | } else { |
56 | $params['oldid'] = $revision; |
57 | } |
58 | // Example URLs: |
59 | // https://en.wikipedia.org/w/api.php?action=parse&format=json&prop=sections&formatversion=2&page=Football |
60 | // https://en.wikipedia.org/w/api.php?action=parse&format=json&prop=sections&formatversion=2&oldid=1161269327 |
61 | $url = SiteMapper::getApiURL( $targetLanguage, $params ); |
62 | |
63 | try { |
64 | $response = $this->httpRequestFactory->get( $url, [], __METHOD__ ); |
65 | } catch ( \Exception $exception ) { |
66 | return []; |
67 | } |
68 | |
69 | if ( !$response ) { |
70 | return null; |
71 | } |
72 | $json = FormatJson::decode( $response, true ); |
73 | |
74 | // if an invalid title is provided the response is a json containing an error |
75 | // (e.g. { error: { code "missingtitle" } } |
76 | // successful responses are json objects with "parse.sections" property set |
77 | if ( !isset( $json['parse']['sections'] ) ) { |
78 | return null; |
79 | } |
80 | |
81 | $sections = $json['parse']['sections']; |
82 | |
83 | $out = []; |
84 | foreach ( $sections as $section ) { |
85 | if ( $section['toclevel'] === 1 ) { |
86 | $out[(int)$section['index']] = $section['line']; |
87 | } |
88 | } |
89 | |
90 | return $out; |
91 | } |
92 | } |