Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImageRecommendationMetadataService
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 4
132
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getExtendedMetadata
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getFileMetadata
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 getApiMetadata
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace GrowthExperiments\NewcomerTasks\AddImage;
4
5use FormatMetadata;
6use GrowthExperiments\Util;
7use MediaTransformError;
8use MediaWiki\Http\HttpRequestFactory;
9use MediaWiki\Language\RawMessage;
10use RepoGroup;
11use StatusValue;
12
13/**
14 * Fetch and process metadata for image recommendation
15 */
16class ImageRecommendationMetadataService {
17
18    /** @var int */
19    private const THUMB_WIDTH = 120;
20
21    /** @var HttpRequestFactory */
22    private $httpRequestFactory;
23
24    /** @var RepoGroup */
25    private $repoGroup;
26
27    /** @var string[] */
28    private $mediaInfoRepos;
29
30    /** @var string */
31    private $contentLanguage;
32
33    /**
34     * @param HttpRequestFactory $httpRequestFactory
35     * @param RepoGroup $repoGroup
36     * @param string[] $mediaInfoRepos List of repo names which provide WikibaseMediaInfo data.
37     * @param string $contentLanguage Language code of wiki content language
38     */
39    public function __construct(
40        HttpRequestFactory $httpRequestFactory,
41        RepoGroup $repoGroup,
42        array $mediaInfoRepos,
43        $contentLanguage
44    ) {
45        $this->httpRequestFactory = $httpRequestFactory;
46        $this->repoGroup = $repoGroup;
47        $this->mediaInfoRepos = $mediaInfoRepos;
48        $this->contentLanguage = $contentLanguage;
49    }
50
51    /**
52     * Fetch extended metadata for the current file
53     *
54     * @param string $fileName Image file name for which to fetch extended metadata.
55     * @return array|StatusValue On success, the extended metadata, as returned by
56     *    FormatMetadata::fetchExtendedMetadata()
57     */
58    public function getExtendedMetadata( string $fileName ) {
59        $file = $this->repoGroup->findFile( $fileName );
60        if ( $file ) {
61            return ( new FormatMetadata )->fetchExtendedMetadata( $file );
62        }
63        return StatusValue::newFatal( new RawMessage( 'Image file not found: $1', [ $fileName ] ) );
64    }
65
66    /**
67     * Get metadata for the specified image file name
68     *
69     * @param string $fileName
70     * @return array|StatusValue On success, an array of file metadata. See
71     *   {@see ImageRecommendationMetadataProvider::getMetadata()} for details.
72     */
73    public function getFileMetadata( string $fileName ) {
74        $file = $this->repoGroup->findFile( $fileName );
75        if ( !$file ) {
76            return StatusValue::newFatal( new RawMessage( 'Image file not found: $1', [ $fileName ] ) );
77        } else {
78            $thumb = $file->transform( [ 'width' => self::THUMB_WIDTH ] );
79            if ( !$thumb ) {
80                return StatusValue::newFatal( 'rawmessage', 'Thumbnailing error' );
81            } elseif ( $thumb instanceof MediaTransformError ) {
82                return StatusValue::newFatal( new RawMessage( 'Thumbnailing error: $1', [ $thumb->toText() ] ) );
83            }
84        }
85        return [
86            'descriptionUrl' => $file->getDescriptionUrl(),
87            'thumbUrl' => $thumb->getUrl(),
88            'fullUrl' => $file->getUrl(),
89            'originalWidth' => $file->getWidth(),
90            'originalHeight' => $file->getHeight(),
91            'mustRender' => $file->mustRender(),
92            'isVectorized' => $file->isVectorized(),
93            'mediaType' => $file->getMediaType()
94        ];
95    }
96
97    /**
98     * Get action=query API metadata for the specified image file name:
99     * - category data
100     * - pageterms (WikibaseMediaInfo) data (e.g. structured data on Commons)
101     * @param string $fileName
102     * @return array|StatusValue On success, an array of file metadata. See
103     *   {@see ImageRecommendationMetadataProvider::getMetadata()} for details.
104     */
105    public function getApiMetadata( string $fileName ) {
106        $file = $this->repoGroup->findFile( $fileName );
107        if ( !$file ) {
108            return StatusValue::newFatal( new RawMessage( 'Image file not found: $1', [ $fileName ] ) );
109        }
110        $repoName = $file->getRepoName();
111        if ( !in_array( $repoName, $this->mediaInfoRepos, true ) ) {
112            return [];
113        }
114        $apiUrl = $file->getRepo()->makeUrl( '', 'api' );
115        $status = Util::getApiUrl( $this->httpRequestFactory, $apiUrl, [
116            'action' => 'query',
117            // The File namespace name might be in a different language locally than on the
118            // repo wiki; in theory, even the canonical namespace name might be different as
119            // it's configurable. Just hardcode the standard name.
120            'titles' => 'File:' . $file->getTitle()->getDBkey(),
121            'prop' => 'categories|pageterms',
122            'clshow' => '!hidden',
123            'cllimit' => 'max',
124            'wbptterms' => 'label',
125            'wbptlanguage' => $this->contentLanguage,
126        ], true );
127        if ( !$status->isOK() ) {
128            return $status;
129        }
130        $data = $status->getValue();
131
132        return [
133            'caption' => $data['query']['pages'][0]['terms']['label'][0] ?? null,
134            'categories' => array_map( static function ( $categoryData ) {
135                $title = $categoryData['title'];
136                // strip namespace prefix
137                return explode( ':', $title, 2 )[1];
138            }, $data['query']['pages'][0]['categories'] ?? [] ),
139        ];
140    }
141
142}