Passed
Push — master ( ff4a21...7076d2 )
by Aimeos
06:11
created

Standard   F

Complexity

Total Complexity 68

Size/Duplication

Total Lines 613
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 68
eloc 158
c 1
b 0
f 0
dl 0
loc 613
rs 2.96

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A addImages() 0 16 3
B checkFileUpload() 0 21 9
A scale() 0 26 6
A add() 0 26 6
A delete() 0 20 4
A copy() 0 32 5
A addPreview() 0 11 2
A getFilePath() 0 26 4
A deletePreviews() 0 18 6
A getMediaFile() 0 26 1
A store() 0 4 1
A getMimeType() 0 49 6
A createPreviews() 0 95 5
A getMimeIcon() 0 29 3
A context() 0 3 1
A getFileContent() 0 23 5

How to fix   Complexity   

Complex Class

Complex classes like Standard often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Standard, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2022
6
 * @package Controller
7
 * @subpackage Common
8
 */
9
10
11
namespace Aimeos\Controller\Common\Media;
12
13
14
/**
15
 * Common media controller methods
16
 *
17
 * @package Controller
18
 * @subpackage Common
19
 */
20
class Standard
21
	implements \Aimeos\Controller\Common\Media\Iface
22
{
23
	private $context;
24
25
26
	/**
27
	 * Initializes the object
28
	 *
29
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
30
	 */
31
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
32
	{
33
		$this->context = $context;
34
	}
35
36
37
	/**
38
	 * Stores the uploaded file and adds the references to the media item
39
	 *
40
	 * {inheritDoc}
41
	 *
42
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item to add the file references to
43
	 * @param \Psr\Http\Message\UploadedFileInterface $file Uploaded file
44
	 * @return \Aimeos\MShop\Media\Item\Iface Added media item
45
	 */
46
	public function add( \Aimeos\MShop\Media\Item\Iface $item, \Psr\Http\Message\UploadedFileInterface $file ) : \Aimeos\MShop\Media\Item\Iface
47
	{
48
		$this->checkFileUpload( $file );
49
50
		$media = $this->getMediaFile( $file->getStream() );
51
		$mimetype = $this->getMimeType( $media, 'files' );
52
		$filepath = $this->getFilePath( $file->getClientFilename() ?: rand(), 'files', $mimetype );
53
54
		$path = $item->getUrl();
55
		$fsname = $item->getFileSystem();
56
		$fs = $this->context->fs( $fsname );
57
58
		if( $path && $fs->has( $path ) ) {
59
			$fs->rm( $path );
60
		}
61
62
		$this->store( $filepath, $media->save(), $fsname );
0 ignored issues
show
Bug introduced by
It seems like $media->save() can also be of type null; however, parameter $content of Aimeos\Controller\Common\Media\Standard::store() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

62
		$this->store( $filepath, /** @scrutinizer ignore-type */ $media->save(), $fsname );
Loading history...
63
64
		if( $media instanceof \Aimeos\MW\Media\Image\Iface ) {
65
			$item = $this->addImages( $item, $media, $file->getClientFilename(), $fsname );
66
		} else {
67
			$item->setPreviews( [1 => $this->getMimeIcon( $mimetype, $fsname )] )->setMimeType( $mimetype );
68
		}
69
70
		return $item->setUrl( $filepath )->setMimeType( $media->getMimeType() )
71
			->setLabel( $item->getLabel() ?: $file->getClientFilename() );
72
	}
73
74
75
	/**
76
	 * Stores the uploaded preview and adds the references to the media item
77
	 *
78
	 * {inheritDoc}
79
	 *
80
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item to add the file references to
81
	 * @param \Psr\Http\Message\UploadedFileInterface $file Uploaded file
82
	 * @return \Aimeos\MShop\Media\Item\Iface Added media item
83
	 */
84
	public function addPreview( \Aimeos\MShop\Media\Item\Iface $item, \Psr\Http\Message\UploadedFileInterface $file ) : \Aimeos\MShop\Media\Item\Iface
85
	{
86
		$this->checkFileUpload( $file );
87
88
		$media = $this->getMediaFile( $file->getStream() );
89
90
		if( $media instanceof \Aimeos\MW\Media\Image\Iface ) {
91
			$item = $this->addImages( $item, $media, $file->getClientFilename(), $item->getFileSystem() );
92
		}
93
94
		return $item;
95
	}
96
97
98
	/**
99
	 * Copies the media item and the referenced files
100
	 *
101
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item whose files should be copied
102
	 * @return \Aimeos\MShop\Media\Item\Iface Copied media item with new files
103
	 */
104
	public function copy( \Aimeos\MShop\Media\Item\Iface $item ) : \Aimeos\MShop\Media\Item\Iface
105
	{
106
		$manager = \Aimeos\MShop::create( $this->context, 'media' );
107
108
		$search = $manager->filter()->slice( 0, 1 );
109
		$search->setConditions( $search->compare( '==', 'media.url', $item->getUrl() ) );
110
111
		$item = $manager->search( $search )->first( $item )->setId( null );
112
113
		$path = $item->getUrl();
114
		$previews = $item->getPreviews();
115
		$fsname = $item->getFileSystem();
116
		$fs = $this->context->fs( $fsname );
117
118
		if( $fs->has( $path ) )
119
		{
120
			$newPath = $this->getFilePath( $path, 'files', $item->getMimeType() );
121
			$fs->copy( $path, $newPath );
122
			$item->setUrl( $newPath );
123
		}
124
125
		foreach( $previews as $size => $preview )
126
		{
127
			if( $fsname !== 'fs-mimeicon' && $fs->has( $preview ) )
128
			{
129
				$newPath = $this->getFilePath( $preview, 'preview', pathinfo( $preview, PATHINFO_EXTENSION ) );
0 ignored issues
show
Bug introduced by
It seems like pathinfo($preview, Aimeo...dia\PATHINFO_EXTENSION) can also be of type array; however, parameter $mimeext of Aimeos\Controller\Common...Standard::getFilePath() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
				$newPath = $this->getFilePath( $preview, 'preview', /** @scrutinizer ignore-type */ pathinfo( $preview, PATHINFO_EXTENSION ) );
Loading history...
130
				$fs->copy( $preview, $newPath );
131
				$previews[$size] = $newPath;
132
			}
133
		}
134
135
		return $item->setPreviews( $previews );
136
	}
137
138
139
	/**
140
	 * Deletes the files of the media item
141
	 *
142
	 * {inheritDoc}
143
	 *
144
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item whose files should be deleted
145
	 * @return \Aimeos\MShop\Media\Item\Iface Media item with deleted files
146
	 */
147
	public function delete( \Aimeos\MShop\Media\Item\Iface $item ) : \Aimeos\MShop\Media\Item\Iface
148
	{
149
		$manager = \Aimeos\MShop::create( $this->context, 'media' );
150
		$search = $manager->filter()->slice( 0, 2 );
151
		$search->setConditions( $search->compare( '==', 'media.url', $item->getUrl() ) );
152
153
		if( count( $manager->search( $search ) ) > 1 ) {
154
			return $item->setUrl( '' )->setPreview( '' );
155
		}
156
157
		$path = $item->getUrl();
158
		$fsname = $item->getFileSystem();
159
		$fs = $this->context->fs( $fsname );
160
161
		if( $path && $fs->has( $path ) ) {
162
			$fs->rm( $path );
163
		}
164
165
		return $this->deletePreviews( $item, $fsname )->setUrl( '' )
166
			->deletePropertyItems( $item->getPropertyItems()->toArray() );
167
	}
168
169
170
	/**
171
	 * Rescales the files (original and preview) referenced by the media item
172
	 *
173
	 * The height/width configuration for scaling and which one should be scaled is used from
174
	 * - controller/common/media/<files|preview>/maxheight
175
	 * - controller/common/media/<files|preview>/maxwidth
176
	 * - controller/common/media/<files|preview>/scale
177
	 *
178
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item whose files should be scaled
179
	 * @param bool $force True to enforce creating new preview images
180
	 * @return \Aimeos\MShop\Media\Item\Iface Rescaled media item
181
	 */
182
	public function scale( \Aimeos\MShop\Media\Item\Iface $item, bool $force = false ) : \Aimeos\MShop\Media\Item\Iface
183
	{
184
		$fsname = $item->getFileSystem();
185
		$fs = $this->context->fs( $fsname );
186
		$is = ( $fs instanceof \Aimeos\Base\Filesystem\MetaIface ? true : false );
187
188
		if( !$force && !( $is && date( 'Y-m-d H:i:s', $fs->time( $item->getUrl() ) ) < $item->getTimeModified() ) ) {
189
			return $item;
190
		}
191
192
		$name = basename( $item->getUrl() );
193
		$media = $this->getMediaFile( $this->getFileContent( $item->getUrl(), $fsname ) );
194
195
		if( $media instanceof \Aimeos\MW\Media\Image\Iface )
196
		{
197
			$item = $this->deletePreviews( $item, $fsname );
198
			$item = $this->addImages( $item, $media, $name, $fsname );
199
		}
200
		else
201
		{
202
			$mimetype = $this->getMimeType( $media, 'files' );
203
			$item = $item->setPreviews( [1 => $this->getMimeIcon( $mimetype, $fsname )] )
204
				->setMimeType( $mimetype )->setFileSystem( 'fs-mimeicon' );
205
		}
206
207
		return $item;
208
	}
209
210
211
	/**
212
	 * Adds original image and preview images to the media item
213
	 *
214
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item which will contain the image URLs afterwards
215
	 * @param \Aimeos\MW\Media\Image\Iface $media Image object to scale
216
	 * @param string|null $name Name of the file, NULL for random name
217
	 * @param string $fsname File system name the file is located at
218
	 * @return \Aimeos\MShop\Media\Item\Iface Updated media item with URLs
219
	 */
220
	protected function addImages( \Aimeos\MShop\Media\Item\Iface $item, \Aimeos\MW\Media\Image\Iface $media, ?string $name, string $fsname ) : \Aimeos\MShop\Media\Item\Iface
221
	{
222
		$previews = [];
223
		$item = $this->deletePreviews( $item, $fsname );
224
225
		foreach( $this->createPreviews( $media, $item->getDomain(), $item->getType() ) as $type => $mediaFile )
0 ignored issues
show
Bug introduced by
It seems like $item->getType() can also be of type null; however, parameter $type of Aimeos\Controller\Common...ndard::createPreviews() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

225
		foreach( $this->createPreviews( $media, $item->getDomain(), /** @scrutinizer ignore-type */ $item->getType() ) as $type => $mediaFile )
Loading history...
226
		{
227
			$mime = $this->getMimeType( $mediaFile, 'preview' );
228
			$filepath = $this->getFilePath( $name ?: rand(), 'preview', $mime );
229
			$this->store( $filepath, $mediaFile->save( null, $mime ), $fsname );
0 ignored issues
show
Bug introduced by
It seems like $mediaFile->save(null, $mime) can also be of type null; however, parameter $content of Aimeos\Controller\Common\Media\Standard::store() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

229
			$this->store( $filepath, /** @scrutinizer ignore-type */ $mediaFile->save( null, $mime ), $fsname );
Loading history...
230
231
			$previews[$mediaFile->getWidth()] = $filepath;
0 ignored issues
show
Bug introduced by
The method getWidth() does not exist on Aimeos\MW\Media\Iface. It seems like you code against a sub-type of Aimeos\MW\Media\Iface such as Aimeos\MW\Media\Image\Iface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

231
			$previews[$mediaFile->/** @scrutinizer ignore-call */ getWidth()] = $filepath;
Loading history...
232
			unset( $mediaFile );
233
		}
234
235
		return $item->setPreviews( $previews );
236
	}
237
238
239
	/**
240
	 * Checks if an error during upload occured
241
	 *
242
	 * @param \Psr\Http\Message\UploadedFileInterface $file Uploaded file
243
	 * @throws \Aimeos\Controller\Common\Exception If an error occured during upload
244
	 */
245
	protected function checkFileUpload( \Psr\Http\Message\UploadedFileInterface $file )
246
	{
247
		if( $file->getError() !== UPLOAD_ERR_OK )
248
		{
249
			switch( $file->getError() )
250
			{
251
				case UPLOAD_ERR_INI_SIZE:
252
				case UPLOAD_ERR_FORM_SIZE:
253
					throw new \Aimeos\Controller\Common\Exception( 'The uploaded file exceeds the max. allowed filesize' );
254
				case UPLOAD_ERR_PARTIAL:
255
					throw new \Aimeos\Controller\Common\Exception( 'The uploaded file was only partially uploaded' );
256
				case UPLOAD_ERR_NO_FILE:
257
					throw new \Aimeos\Controller\Common\Exception( 'No file was uploaded' );
258
				case UPLOAD_ERR_NO_TMP_DIR:
259
					throw new \Aimeos\Controller\Common\Exception( 'Temporary folder is missing' );
260
				case UPLOAD_ERR_CANT_WRITE:
261
					throw new \Aimeos\Controller\Common\Exception( 'Failed to write file to disk' );
262
				case UPLOAD_ERR_EXTENSION:
263
					throw new \Aimeos\Controller\Common\Exception( 'File upload stopped by extension' );
264
				default:
265
					throw new \Aimeos\Controller\Common\Exception( 'Unknown upload error' );
266
			}
267
		}
268
	}
269
270
271
	/**
272
	 * Creates scaled images according to the configuration settings
273
	 *
274
	 * @param \Aimeos\MW\Media\Image\Iface $media Media object
275
	 * @param string $domain Domain the item is from, e.g. product, catalog, etc.
276
	 * @param string $type Type of the item within the given domain, e.g. default, stage, etc.
277
	 * @return \Aimeos\MW\Media\Image\Iface[] Associative list of image width as keys and scaled media object as values
278
	 */
279
	protected function createPreviews( \Aimeos\MW\Media\Image\Iface $media, string $domain, string $type ) : array
280
	{
281
		$list = [];
282
		$config = $this->context->config();
283
284
		/** controller/common/media/previews
285
		 * Scaling options for preview images
286
		 *
287
		 * For responsive images, several preview images of different sizes are
288
		 * generated. This setting controls how many preview images are generated,
289
		 * what's their maximum width and height and if the given width/height is
290
		 * enforced by cropping images that doesn't fit.
291
		 *
292
		 * The setting must consist of a list image size definitions like:
293
		 *
294
		 *  [
295
		 *    ['maxwidth' => 240, 'maxheight' => 320, 'force-size' => true],
296
		 *    ['maxwidth' => 720, 'maxheight' => 960, 'force-size' => false],
297
		 *    ['maxwidth' => 2160, 'maxheight' => 2880, 'force-size' => false],
298
		 *  ]
299
		 *
300
		 * "maxwidth" sets the maximum allowed width of the image whereas
301
		 * "maxheight" does the same for the maximum allowed height. If both
302
		 * values are given, the image is scaled proportionally so it fits into
303
		 * the box defined by both values. In case the image has different
304
		 * proportions than the specified ones and "force-size" is false, the
305
		 * image is resized to fit entirely into the specified box. One side of
306
		 * the image will be shorter than it would be possible by the specified
307
		 * box.
308
		 *
309
		 * If "force-size" is true, scaled images that doesn't fit into the
310
		 * given maximum width/height are centered and then cropped. By default,
311
		 * images aren't cropped.
312
		 *
313
		 * The values for "maxwidth" and "maxheight" can also be null or not
314
		 * used. In that case, the width or height or both is unbound. If none
315
		 * of the values are given, the image won't be scaled at all. If only
316
		 * one value is set, the image will be scaled exactly to the given width
317
		 * or height and the other side is scaled proportionally.
318
		 *
319
		 * You can also define different preview sizes for different domains (e.g.
320
		 * for catalog images) and for different types (e.g. catalog stage images).
321
		 * Use configuration settings like
322
		 *
323
		 *  controller/common/media/<domain>/previews
324
		 *  controller/common/media/<domain>/<type>/previews
325
		 *
326
		 * for example:
327
		 *
328
		 *  controller/common/media/catalog/previews => [
329
		 *    ['maxwidth' => 240, 'maxheight' => 320, 'force-size' => true],
330
		 *  ]
331
		 *  controller/common/media/catalog/previews => [
332
		 *    ['maxwidth' => 400, 'maxheight' => 300, 'force-size' => false]
333
		 *  ]
334
		 *  controller/common/media/catalog/stage/previews => [
335
		 *    ['maxwidth' => 360, 'maxheight' => 320, 'force-size' => true],
336
		 *    ['maxwidth' => 720, 'maxheight' => 480, 'force-size' => true]
337
		 *  ]
338
		 *
339
		 * These settings will create two preview images for catalog stage images,
340
		 * one with a different size for all other catalog images and all images
341
		 * from other domains will be sized to 240x320px. The available domains
342
		 * which can have images are:
343
		 *
344
		 * * attribute
345
		 * * catalog
346
		 * * product
347
		 * * service
348
		 * * supplier
349
		 *
350
		 * There are a few image types included per domain ("default" is always
351
		 * available). You can also add your own types in the admin backend and
352
		 * extend the frontend to display them where you need them.
353
		 *
354
		 * @param array List of image size definitions
355
		 * @category Developer
356
		 * @category User
357
		 * @since 2019.07
358
		 */
359
		$previews = $config->get( 'controller/common/media/previews', [] );
360
		$previews = $config->get( 'controller/common/media/' . $domain . '/previews', $previews );
361
		$previews = $config->get( 'controller/common/media/' . $domain . '/' . $type . '/previews', $previews );
362
363
		foreach( $previews as $entry )
364
		{
365
			$maxwidth = ( isset( $entry['maxwidth'] ) ? (int) $entry['maxwidth'] : null );
366
			$maxheight = ( isset( $entry['maxheight'] ) ? (int) $entry['maxheight'] : null );
367
			$fit = ( isset( $entry['force-size'] ) ? (int) $entry['force-size'] : 0 );
368
369
			$image = $media->scale( $maxwidth, $maxheight, $fit );
370
			$list[$image->getWidth()] = $image;
371
		}
372
373
		return $list;
374
	}
375
376
377
	/**
378
	 * Removes the previes images from the storage
379
	 *
380
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item which will contains the image URLs afterwards
381
	 * @param string $fsname File system name the file is located at
382
	 * @return \Aimeos\MShop\Media\Item\Iface Media item with preview images removed
383
	 */
384
	protected function deletePreviews( \Aimeos\MShop\Media\Item\Iface $item, string $fsname )
385
	{
386
		$fs = $this->context->fs( $fsname );
387
		$previews = $item->getPreviews();
388
389
		// don't delete first (smallest) image because it's referenced in past orders
390
		if( 'product' === $item->getDomain() ) {
391
			$previews = array_slice( $previews, 1 );
392
		}
393
394
		foreach( $previews as $preview )
395
		{
396
			if( $fsname !== 'fs-mimeicon' && $preview && $fs->has( $preview ) ) {
397
				$fs->rm( $preview );
398
			}
399
		}
400
401
		return $item->setPreviews( [] );
402
	}
403
404
405
	/**
406
	 * Returns the context item
407
	 *
408
	 * @return \Aimeos\MShop\Context\Item\Iface Context item
409
	 */
410
	protected function context() : \Aimeos\MShop\Context\Item\Iface
411
	{
412
		return $this->context;
413
	}
414
415
416
	/**
417
	 * Returns the file content of the file or URL
418
	 *
419
	 * @param string $path Path to the file or URL
420
	 * @param string $fsname File system name the file is located at
421
	 * @return string File content
422
	 * @throws \Aimeos\Controller\Common\Exception If no file is found
423
	 */
424
	protected function getFileContent( string $path, string $fsname ) : string
425
	{
426
		if( $path !== '' )
427
		{
428
			if( preg_match( '#^[a-zA-Z]{1,10}://#', $path ) === 1 )
429
			{
430
				if( ( $content = @file_get_contents( $path ) ) === false )
431
				{
432
					$msg = sprintf( 'Downloading file "%1$s" failed', $path );
433
					throw new \Aimeos\Controller\Common\Exception( $msg );
434
				}
435
436
				return $content;
437
			}
438
439
			$fs = $this->context->fs( $fsname );
440
441
			if( $fs->has( $path ) !== false ) {
442
				return $fs->read( $path );
443
			}
444
		}
445
446
		throw new \Aimeos\Controller\Common\Exception( sprintf( 'File "%1$s" not found', $path ) );
447
	}
448
449
450
	/**
451
	 * Creates a new file path from the given arguments and random values
452
	 *
453
	 * @param string $filename Original file name, can contain the path as well
454
	 * @param string $type File type, i.e. "files" or "preview"
455
	 * @param string $mimeext Mime type or extension of the file
456
	 * @return string New file name including the file path
457
	 */
458
	protected function getFilePath( string $filename, string $type, string $mimeext ) : string
459
	{
460
		/** controller/common/media/extensions
461
		 * Available files extensions for mime types of uploaded files
462
		 *
463
		 * Uploaded files should have the right file extension (e.g. ".jpg" for
464
		 * JPEG images) so files are recognized correctly if downloaded by users.
465
		 * The extension of the uploaded file can't be trusted and only its mime
466
		 * type can be determined automatically. This configuration setting
467
		 * provides the file extensions for the configured mime types. You can
468
		 * add more mime type / file extension combinations if required.
469
		 *
470
		 * @param array Associative list of mime types as keys and file extensions as values
471
		 * @since 2018.04
472
		 * @category Developer
473
		 */
474
		$list = $this->context->config()->get( 'controller/common/media/extensions', [] );
475
476
		$filename = \Aimeos\Base\Str::slug( substr( $filename, 0, strrpos( $filename, '.' ) ?: null ) );
477
		$filename = substr( md5( $filename . getmypid() . microtime( true ) ), -8 ) . '_' . $filename;
478
479
		$ext = isset( $list[$mimeext] ) ? '.' . $list[$mimeext] : ( ctype_alpha( $mimeext ) ? '.' . $mimeext : '' );
480
		$siteId = $this->context->locale()->getSiteId();
481
482
		// the "d" after {siteid} is the required extension for Windows (no dots at the and allowed)
483
		return "${siteId}d/${type}/${filename[0]}/${filename[1]}/${filename}${ext}";
484
	}
485
486
487
	/**
488
	 * Returns the media object for the given file name
489
	 *
490
	 * @param string $file Path to the file or file content
491
	 * @return \Aimeos\MW\Media\Iface Media object
492
	 */
493
	protected function getMediaFile( string $file ) : \Aimeos\MW\Media\Iface
494
	{
495
		/** controller/common/media/options
496
		 * Options used for processing the uploaded media files
497
		 *
498
		 * When uploading a file, a preview image for that file is generated if
499
		 * possible (especially for images). You can configure certain options
500
		 * for the generated images, namely the implementation of the scaling
501
		 * algorithm and the quality of the resulting images with
502
		 *
503
		 *  array(
504
		 *  	'image' => array(
505
		 *  		'name' => 'Imagick',
506
		 *  		'quality' => 75,
507
		 * 			'background' => '#f8f8f8' // only if "force-size" is true
508
		 *  	)
509
		 *  )
510
		 *
511
		 * @param array Multi-dimendional list of configuration options
512
		 * @since 2016.01
513
		 * @category Developer
514
		 * @category User
515
		 */
516
		$options = $this->context->config()->get( 'controller/common/media/options', [] );
517
518
		return \Aimeos\MW\Media\Factory::get( $file, $options );
519
	}
520
521
522
	/**
523
	 * Returns the relative path to the mime icon for the given mime type.
524
	 *
525
	 * @param string $mimetype Mime type like "image/png"
526
	 * @param string $fsname File system name the icon should be stored at
527
	 * @return string Relative path to the mime icon
528
	 */
529
	protected function getMimeIcon( string $mimetype, string $fsname ) : string
530
	{
531
		$config = $this->context->config();
532
533
		/** controller/common/media/mimeicon/extension
534
		 * File extension of the mime icon images
535
		 *
536
		 * If you would like to use different mime icons that are available in
537
		 * another file format, you have to change the file extension for the
538
		 * mime icons to the actual ones.
539
		 *
540
		 * Note: The configured file extension needs a leading dot!
541
		 *
542
		 * @param string File extension including a leading dot, e.g ".jpg"
543
		 * @since 2016.01
544
		 * @category Developer
545
		 */
546
		$ext = $config->get( 'controller/common/media/mimeicon/extension', '.png' );
547
548
		$filepath = '';
549
		$fsmime = $this->context->fs( 'fs-mimeicon' );
550
551
		if( $fsmime->has( $filename = $mimetype . $ext ) || $fsmime->has( $filename = 'unknown' . $ext ) )
552
		{
553
			$filepath = $this->getFilePath( $filename, 'preview', ltrim( $ext, '.' ) );
554
			$this->context->fs( $fsname )->write( $filepath, $fsmime->read( $filename ) );
555
		}
556
557
		return $filepath;
558
	}
559
560
561
	/**
562
	 * Returns the mime type for the new image
563
	 *
564
	 * @param \Aimeos\MW\Media\Iface $media Media object
565
	 * @param string $type Type of the image like "preview" or "files"
566
	 * @return string New mime type
567
	 * @throws \Aimeos\Controller\Common\Exception If no mime types are configured
568
	 */
569
	protected function getMimeType( \Aimeos\MW\Media\Iface $media, string $type ) : string
570
	{
571
		$mimetype = $media->getMimetype();
572
		$config = $this->context->config();
573
574
		/** controller/common/media/files/allowedtypes
575
		 * A list of image mime types that are allowed for uploaded image files
576
		 *
577
		 * The list of allowed image types must be explicitly configured for the
578
		 * uploaded image files. Trying to upload and store an image file not
579
		 * available in the list of allowed mime types will result in an exception.
580
		 *
581
		 * @param array List of image mime types
582
		 * @since 2016.01
583
		 * @category Developer
584
		 * @category User
585
		 */
586
587
		/** controller/common/media/preview/allowedtypes
588
		 * A list of image mime types that are allowed for preview image files
589
		 *
590
		 * The list of allowed image types must be explicitly configured for the
591
		 * preview image files. Trying to create a preview image whose mime type
592
		 * is not available in the list of allowed mime types will result in an
593
		 * exception.
594
		 *
595
		 * @param array List of image mime types
596
		 * @since 2016.01
597
		 * @category Developer
598
		 * @category User
599
		 */
600
		$default = [
601
			'image/webp', 'image/jpeg', 'image/png', 'image/gif', 'image/svg+xml',
602
			'application/pdf', 'application/zip',
603
			'video/mp4', 'video/webm'
604
		];
605
		$allowed = $config->get( 'controller/common/media/' . $type . '/allowedtypes', $default );
606
607
		if( $type === 'preview' && in_array( $mimetype, ['image/jpeg', 'image/png'] )
608
			&& !empty( $supported = $media::supports( $allowed ) ) && ( $imgtype = reset( $supported ) ) !== false
0 ignored issues
show
Bug introduced by
The method supports() does not exist on Aimeos\MW\Media\Iface. It seems like you code against a sub-type of Aimeos\MW\Media\Iface such as Aimeos\MW\Media\Image\Iface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

608
			&& !empty( $supported = $media::/** @scrutinizer ignore-call */ supports( $allowed ) ) && ( $imgtype = reset( $supported ) ) !== false
Loading history...
609
		) {
610
			return $imgtype;
611
		}
612
613
		if( in_array( $mimetype, $allowed ) === false ) {
614
			throw new \Aimeos\Controller\Common\Exception( sprintf( 'File type "%1$s" is not allowed', $mimetype ) );
615
		}
616
617
		return $mimetype;
618
	}
619
620
621
	/**
622
	 * Stores the file content
623
	 *
624
	 * @param string $filepath Path of the new file
625
	 * @param string $content File content
626
	 * @param string $fsname Name of the file system to store the files at
627
	 * @return \Aimeos\Controller\Common\Media\Iface Self object for fluent interface
628
	 */
629
	protected function store( string $filepath, string $content, string $fsname ) : Iface
630
	{
631
		$this->context->fs( $fsname )->write( $filepath, $content );
632
		return $this;
633
	}
634
}
635