Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SectionMappingFetcher
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 3
90
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
 fetchSectionMapping
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
12
 isValidSectionMappingResponse
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2declare( strict_types = 1 );
3
4namespace ContentTranslation\Service;
5
6use MediaWiki\Json\FormatJson;
7use Psr\Log\LoggerInterface;
8
9/**
10 * Service responsible for retrieving section mapping data from the CX server.
11 *
12 * It maps sections from a source article to corresponding sections in a target article
13 * and returns the results in a structured format.
14 *
15 * @license GPL-2.0-or-later
16 * @since 2025.08
17 */
18class SectionMappingFetcher {
19
20    public function __construct(
21        private readonly CxServerClient $cxServerClient,
22        private readonly LoggerInterface $logger
23    ) {
24    }
25
26    /**
27     * Fetch section mappings from CX server for source and target articles.
28     * Returns structured data about section relationships between the articles.
29     *
30     * @param string $sourceLanguage
31     * @param string $sourceTitle
32     * @param string $targetLanguage
33     * @return array|null Array with keys: sourceSections, present, missing, or null on failure
34     */
35    public function fetchSectionMapping(
36        string $sourceLanguage,
37        string $sourceTitle,
38        string $targetLanguage
39    ): ?array {
40        $path = "/v2/suggest/sections/" . rawurlencode( $sourceTitle ) . "/$sourceLanguage/$targetLanguage";
41        $response = $this->cxServerClient->get( $path );
42
43        if ( !$response ) {
44            return null;
45        }
46
47        $json = FormatJson::decode( $response, true );
48        if ( !$this->isValidSectionMappingResponse( $json ) ) {
49            $this->logger->info(
50                'Invalid section mapping response from CX server',
51                [
52                    'sourceTitle' => $sourceTitle,
53                    'sourceLanguage' => $sourceLanguage,
54                    'targetLanguage' => $targetLanguage,
55                    'response' => $response
56                ]
57            );
58            return null;
59        }
60
61        $sectionData = $json['sections'];
62        return [
63            'sourceSections' => $sectionData['sourceSections'],
64            'present' => $sectionData['present'] ?? [],
65            'missing' => $sectionData['missing'] ?? []
66        ];
67    }
68
69    /**
70     * Validate that the CX server response has the expected structure.
71     *
72     * @param mixed $json Decoded JSON response
73     * @return bool True if response is valid
74     */
75    private function isValidSectionMappingResponse( $json ): bool {
76        return is_array( $json ) &&
77            isset( $json['sections'] ) &&
78            is_array( $json['sections'] ) &&
79            isset( $json['sections']['sourceSections'] ) &&
80            is_array( $json['sections']['sourceSections'] );
81    }
82}