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    /**
28     * @param HttpApiLookup $httpApiLookup
29     * @param HttpRequestExecutor $httpRequestExecutor
30     * @param LoggerInterface $logger
31     */
32    public function __construct(
33        HttpApiLookup $httpApiLookup,
34        HttpRequestExecutor $httpRequestExecutor,
35        LoggerInterface $logger
36    ) {
37        $this->httpApiLookup = $httpApiLookup;
38        $this->httpRequestExecutor = $httpRequestExecutor;
39        $this->logger = $logger;
40    }
41
42    /**
43     * @param SourceUrl $sourceUrl
44     * @param string $intendedFileName File name without the File: prefix
45     *
46     * @return bool false if a file with this name already exists
47     * @throws ImportException when the request failed
48     */
49    public function importAllowed( SourceUrl $sourceUrl, string $intendedFileName ): bool {
50        $api = $this->httpApiLookup->getApiUrl( $sourceUrl );
51        $apiParameters = $this->getParams( $intendedFileName );
52
53        try {
54            $imageInfoRequest = $this->httpRequestExecutor->execute( $api, $apiParameters );
55        } catch ( HttpRequestException $e ) {
56            $this->logger->error(
57                __METHOD__ . ' failed to check title state from: ' . $api,
58                [
59                    'url' => $e->getHttpRequest()->getFinalUrl(),
60                    'content' => $e->getHttpRequest()->getContent(),
61                    'errors' => $e->getStatusValue()->getErrors(),
62                    'apiUrl' => $api,
63                    'apiParameters' => $apiParameters,
64                ]
65            );
66            throw new ImportException(
67                'Failed to check title state from: ' . $api, self::ERROR_TITLE_STATE, $e );
68        }
69
70        $requestData = json_decode( $imageInfoRequest->getContent(), true );
71
72        if ( !isset( $requestData['query']['pages'][0] ) ) {
73            $this->logger->error( __METHOD__ . ' failed, could not find page in result.' );
74            return false;
75        }
76
77        // Possible return values in output format version 2:
78        // { "query": { "pages": [ { "pageid": 123, … when the title exists
79        // { "query": { "pages": [ { "missing": true, … otherwise
80        // Note the legacy format uses { "missing": "" }, and -1 etc. as keys for missing pages.
81        return array_key_exists( 'missing', $requestData['query']['pages'][0] );
82    }
83
84    /**
85     * @param string $titleString
86     * @return array
87     */
88    private function getParams( string $titleString ): array {
89        return [
90            'format' => 'json',
91            'action' => 'query',
92            'titles' => 'File:' . $titleString,
93            'errorformat' => 'plaintext',
94            'formatversion' => 2,
95        ];
96    }
97
98}