Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
MediaTransformOutput
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 15
1482
0.00% covered (danger)
0.00%
0 / 1
 getWidth
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHeight
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getExtension
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getUrl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStoragePath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setStoragePath
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 toHtml
n/a
0 / 0
n/a
0 / 0
0
 isError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
12
 fileIsSource
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getLocalCopyPath
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 streamFileWithStatus
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 streamFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 linkWrap
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getDescLinkAttribs
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3/**
4 * Base class for the output of file transformation methods.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 * @file
22 * @ingroup Media
23 */
24
25use MediaWiki\MainConfigNames;
26use MediaWiki\MediaWikiServices;
27use MediaWiki\Output\StreamFile;
28use MediaWiki\Status\Status;
29
30/**
31 * Base class for the output of MediaHandler::doTransform() and File::transform().
32 *
33 * @stable to extend
34 * @ingroup Media
35 */
36abstract class MediaTransformOutput {
37    /** @var array Associative array mapping optional supplementary image files
38     *  from pixel density (eg 1.5 or 2) to additional URLs.
39     */
40    public $responsiveUrls = [];
41
42    /** @var File */
43    protected $file;
44
45    /** @var int Image width */
46    protected $width;
47
48    /** @var int Image height */
49    protected $height;
50
51    /** @var string|false URL path to the thumb */
52    protected $url;
53
54    /** @var string|false */
55    protected $page;
56
57    /** @var string|null|false Filesystem path to the thumb */
58    protected $path;
59
60    /** @var string|false Language code, false if not set */
61    protected $lang;
62
63    /** @var string|false Permanent storage path */
64    protected $storagePath = false;
65
66    /**
67     * @return int Width of the output box
68     */
69    public function getWidth() {
70        return $this->width;
71    }
72
73    /**
74     * @return int Height of the output box
75     */
76    public function getHeight() {
77        return $this->height;
78    }
79
80    /**
81     * @return File
82     */
83    public function getFile() {
84        return $this->file;
85    }
86
87    /**
88     * Get the final extension of the thumbnail.
89     * Returns false for scripted transformations.
90     * @stable to override
91     *
92     * @return string|false
93     */
94    public function getExtension() {
95        return $this->path ? FileBackend::extensionFromPath( $this->path ) : false;
96    }
97
98    /**
99     * @stable to override
100     *
101     * @return string|false The thumbnail URL
102     */
103    public function getUrl() {
104        return $this->url;
105    }
106
107    /**
108     * @stable to override
109     *
110     * @return string|false The permanent thumbnail storage path
111     */
112    public function getStoragePath() {
113        return $this->storagePath;
114    }
115
116    /**
117     * @stable to override
118     *
119     * @param string $storagePath The permanent storage path
120     * @return void
121     */
122    public function setStoragePath( $storagePath ) {
123        $this->storagePath = $storagePath;
124        if ( $this->path === false ) {
125            $this->path = $storagePath;
126        }
127    }
128
129    /**
130     * Fetch HTML for this transform output
131     *
132     * @param array $options Associative array of options. Boolean options
133     *     should be indicated with a value of true for true, and false or
134     *     absent for false.
135     *
136     *     alt          Alternate text or caption
137     *     desc-link    Boolean, show a description link
138     *     file-link    Boolean, show a file download link
139     *     custom-url-link    Custom URL to link to
140     *     custom-title-link  Custom Title object to link to
141     *     valign       vertical-align property, if the output is an inline element
142     *     img-class    Class applied to the "<img>" tag, if there is such a tag
143     *
144     * For images, desc-link and file-link are implemented as a click-through. For
145     * sounds and videos, they may be displayed in other ways.
146     *
147     * @return string
148     */
149    abstract public function toHtml( $options = [] );
150
151    /**
152     * This will be overridden to return true in error classes
153     * @return bool
154     */
155    public function isError() {
156        return false;
157    }
158
159    /**
160     * Check if an output thumbnail file actually exists.
161     *
162     * This will return false if there was an error, the
163     * thumbnail is to be handled client-side only, or if
164     * transformation was deferred via TRANSFORM_LATER.
165     * This file may exist as a new file in /tmp, a file
166     * in permanent storage, or even refer to the original.
167     *
168     * @return bool
169     */
170    public function hasFile() {
171        // If TRANSFORM_LATER, $this->path will be false.
172        // Note: a null path means "use the source file".
173        return ( !$this->isError() && ( $this->path || $this->path === null ) );
174    }
175
176    /**
177     * Check if the output thumbnail is the same as the source.
178     * This can occur if the requested width was bigger than the source.
179     *
180     * @return bool
181     */
182    public function fileIsSource() {
183        return ( !$this->isError() && $this->path === null );
184    }
185
186    /**
187     * Get the path of a file system copy of the thumbnail.
188     * Callers should never write to this path.
189     *
190     * @return string|false Returns false if there isn't one
191     */
192    public function getLocalCopyPath() {
193        if ( $this->isError() ) {
194            return false;
195        }
196
197        if ( $this->path === null ) {
198            return $this->file->getLocalRefPath(); // assume thumb was not scaled
199        }
200        if ( FileBackend::isStoragePath( $this->path ) ) {
201            $be = $this->file->getRepo()->getBackend();
202            // The temp file will be process cached by FileBackend
203            $fsFile = $be->getLocalReference( [ 'src' => $this->path ] );
204
205            return $fsFile ? $fsFile->getPath() : false;
206        }
207        return $this->path; // may return false
208    }
209
210    /**
211     * Stream the file if there were no errors
212     *
213     * @param array $headers Additional HTTP headers to send on success
214     * @return Status
215     * @since 1.27
216     */
217    public function streamFileWithStatus( $headers = [] ) {
218        if ( !$this->path ) {
219            return Status::newFatal( 'backend-fail-stream', '<no path>' );
220        }
221        if ( FileBackend::isStoragePath( $this->path ) ) {
222            $be = $this->file->getRepo()->getBackend();
223            return Status::wrap(
224                $be->streamFile( [ 'src' => $this->path, 'headers' => $headers ] ) );
225        }
226        // FS-file
227        $success = StreamFile::stream( $this->getLocalCopyPath(), $headers );
228        return $success ? Status::newGood() : Status::newFatal( 'backend-fail-stream', $this->path );
229    }
230
231    /**
232     * Stream the file if there were no errors
233     *
234     * @deprecated since 1.26, use streamFileWithStatus
235     * @param array $headers Additional HTTP headers to send on success
236     * @return bool Success
237     */
238    public function streamFile( $headers = [] ) {
239        return $this->streamFileWithStatus( $headers )->isOK();
240    }
241
242    /**
243     * Wrap some XHTML text in an anchor tag with the given attributes
244     * or, fallback to a span in the absence thereof.
245     *
246     * @param array $linkAttribs
247     * @param string $contents
248     * @return string
249     */
250    protected function linkWrap( $linkAttribs, $contents ) {
251        if ( isset( $linkAttribs['href'] ) ) {
252            return Xml::tags( 'a', $linkAttribs, $contents );
253        }
254        $parserEnableLegacyMediaDOM = MediaWikiServices::getInstance()
255            ->getMainConfig()->get( MainConfigNames::ParserEnableLegacyMediaDOM );
256        if ( $parserEnableLegacyMediaDOM ) {
257            return $contents;
258        }
259        return Xml::tags( 'span', $linkAttribs ?: null, $contents );
260    }
261
262    /**
263     * @param string|null $title
264     * @param string|array $params Query parameters to add
265     * @return array
266     */
267    public function getDescLinkAttribs( $title = null, $params = [] ) {
268        if ( is_array( $params ) ) {
269            $query = $params;
270        } else {
271            $query = [];
272        }
273        if ( $this->page && $this->page !== 1 ) {
274            $query['page'] = $this->page;
275        }
276        if ( $this->lang ) {
277            $query['lang'] = $this->lang;
278        }
279
280        if ( is_string( $params ) && $params !== '' ) {
281            $query = $params . '&' . wfArrayToCgi( $query );
282        }
283
284        $attribs = [
285            'href' => $this->file->getTitle()->getLocalURL( $query ),
286        ];
287
288        $parserEnableLegacyMediaDOM = MediaWikiServices::getInstance()
289            ->getMainConfig()->get( MainConfigNames::ParserEnableLegacyMediaDOM );
290        if ( $parserEnableLegacyMediaDOM ) {
291            $attribs['class'] = 'image';
292        } else {
293            $attribs['class'] = 'mw-file-description';
294        }
295
296        if ( $title ) {
297            $attribs['title'] = $title;
298        }
299
300        return $attribs;
301    }
302}