Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
58.06% covered (warning)
58.06%
18 / 31
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
RemoteApiImportTitleChecker
58.06% covered (warning)
58.06%
18 / 31
66.67% covered (warning)
66.67%
2 / 3
6.84
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 importAllowed
38.10% covered (danger)
38.10%
8 / 21
0.00% covered (danger)
0.00%
0 / 1
5.14
 getParams
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace FileImporter\Remote\MediaWiki;
4
5use FileImporter\Data\SourceUrl;
6use FileImporter\Exceptions\HttpRequestException;
7use FileImporter\Exceptions\ImportException;
8use FileImporter\Interfaces\ImportTitleChecker;
9use FileImporter\Services\Http\HttpRequestExecutor;
10use Psr\Log\LoggerInterface;
11
12/**
13 * @license GPL-2.0-or-later
14 * @author Addshore
15 */
16class RemoteApiImportTitleChecker implements ImportTitleChecker {
17
18    private const ERROR_TITLE_STATE = 'noTitleStateFetched';
19
20    /** @var HttpApiLookup */
21    private $httpApiLookup;
22    /** @var HttpRequestExecutor */
23    private $httpRequestExecutor;
24    /** @var LoggerInterface */
25    private $logger;
26
27    public function __construct(
28        HttpApiLookup $httpApiLookup,
29        HttpRequestExecutor $httpRequestExecutor,
30        LoggerInterface $logger
31    ) {
32        $this->httpApiLookup = $httpApiLookup;
33        $this->httpRequestExecutor = $httpRequestExecutor;
34        $this->logger = $logger;
35    }
36
37    /**
38     * @param SourceUrl $sourceUrl
39     * @param string $intendedFileName File name without the File: prefix
40     *
41     * @return bool false if a file with this name already exists
42     * @throws ImportException when the request failed
43     */
44    public function importAllowed( SourceUrl $sourceUrl, string $intendedFileName ): bool {
45        $api = $this->httpApiLookup->getApiUrl( $sourceUrl );
46        $apiParameters = $this->getParams( $intendedFileName );
47
48        try {
49            $imageInfoRequest = $this->httpRequestExecutor->execute( $api, $apiParameters );
50        } catch ( HttpRequestException $e ) {
51            $this->logger->error(
52                __METHOD__ . ' failed to check title state from: ' . $api,
53                [
54                    'url' => $e->getHttpRequest()->getFinalUrl(),
55                    'content' => $e->getHttpRequest()->getContent(),
56                    'errors' => $e->getStatusValue()->getErrors(),
57                    'apiUrl' => $api,
58                    'apiParameters' => $apiParameters,
59                ]
60            );
61            throw new ImportException(
62                'Failed to check title state from: ' . $api, self::ERROR_TITLE_STATE, $e );
63        }
64
65        $requestData = json_decode( $imageInfoRequest->getContent(), true );
66
67        if ( !isset( $requestData['query']['pages'][0] ) ) {
68            $this->logger->error( __METHOD__ . ' failed, could not find page in result.' );
69            return false;
70        }
71
72        // Possible return values in output format version 2:
73        // { "query": { "pages": [ { "pageid": 123, … when the title exists
74        // { "query": { "pages": [ { "missing": true, … otherwise
75        // Note the legacy format uses { "missing": "" }, and -1 etc. as keys for missing pages.
76        return array_key_exists( 'missing', $requestData['query']['pages'][0] );
77    }
78
79    private function getParams( string $titleString ): array {
80        return [
81            'format' => 'json',
82            'action' => 'query',
83            'titles' => 'File:' . $titleString,
84            'errorformat' => 'plaintext',
85            'formatversion' => 2,
86        ];
87    }
88
89}