Passed
Push — master ( b27b0a...6db573 )
by Aimeos
04:19
created

Preview   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 18
eloc 44
c 1
b 0
f 0
dl 0
loc 148
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A createPreviews() 0 24 3
A image() 0 32 6
A removePreviews() 0 10 3
A filterPreviews() 0 3 1
A deletePreviews() 0 15 5
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2023
6
 * @package MShop
7
 * @subpackage Media
8
 */
9
10
11
namespace Aimeos\MShop\Media\Manager;
12
13
use \Intervention\Image\Interfaces\ImageInterface;
0 ignored issues
show
Bug introduced by
The type \Intervention\Image\Interfaces\ImageInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
15
16
/**
17
 * Media preview trait
18
 *
19
 * @package MShop
20
 * @subpackage Media
21
 */
22
trait Preview
23
{
24
	use \Aimeos\Macro\Macroable;
25
26
27
	private ?\Intervention\Image\ImageManager $driver = null;
28
29
30
	/**
31
	 * Returns the context object.
32
	 *
33
	 * @return \Aimeos\MShop\ContextIface Context object
34
	 */
35
	abstract protected function context() : \Aimeos\MShop\ContextIface;
36
37
38
	/**
39
	 * Creates scaled images according to the configuration settings
40
	 *
41
	 * @param \Intervention\Image\Interfaces\ImageInterface $image Media object
42
	 * @param array $sizes List of entries with "maxwidth" (int or null), "maxheight" (int or null), "force-size" (0: scale, 1: pad, 2: cover) and "background" (hex color) values
43
	 * @return \Intervention\Image\Interfaces\ImageInterface[] Associative list of image width as keys and scaled media object as values
44
	 */
45
	protected function createPreviews( ImageInterface $image, array $sizes ) : array
46
	{
47
		$list = [];
48
49
		foreach( $sizes as $entry )
50
		{
51
			$force = $entry['force-size'] ?? 0;
52
			$maxwidth = $entry['maxwidth'] ?? null;
53
			$maxheight = $entry['maxheight'] ?? null;
54
			$bg = ltrim( $entry['background'] ?? 'ffffff00', '#' );
55
56
			if( $this->call( 'filterPreviews', $image, $maxwidth, $maxheight, $force ) )
57
			{
58
				$file = match( $force ) {
59
					0 => $image->scaleDown( $maxwidth, $maxheight ),
60
					1 => $image->pad( $maxwidth, $maxheight, $bg, 'center' ),
61
					2 => $image->cover( $maxwidth, $maxheight )
62
				};
63
64
				$list[$file->width()] = $file;
65
			}
66
		}
67
68
		return $list;
69
	}
70
71
72
	/**
73
	 * Removes the previes images from the storage
74
	 *
75
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item which will contains the image URLs afterwards
76
	 * @param array List of preview paths to remove
77
	 * @return \Aimeos\MShop\Media\Item\Iface Media item with preview images removed
78
	 */
79
	protected function deletePreviews( \Aimeos\MShop\Media\Item\Iface $item, array $paths ) : \Aimeos\MShop\Media\Item\Iface
80
	{
81
		if( !empty( $paths = $this->call( 'removePreviews', $item, $paths ) ) )
82
		{
83
			$fs = $this->context()->fs( $item->getFileSystem() );
84
85
			foreach( $paths as $preview )
86
			{
87
				if( $preview && $fs->has( $preview ) ) {
88
					$fs->rm( $preview );
89
				}
90
			}
91
		}
92
93
		return $item;
94
	}
95
96
97
	/**
98
	 * Tests if the preview image should be created
99
	 *
100
	 * @param \Intervention\Image\Interfaces\ImageInterface $image Media object
101
	 * @param int|null $width New width of the image or null for automatic calculation
102
	 * @param int|null $height New height of the image or null for automatic calculation
103
	 * @param int $fit "0" keeps image ratio, "1" adds padding while "2" crops image to enforce image size
104
	 */
105
	protected function filterPreviews( ImageInterface $image, ?int $maxwidth, ?int $maxheight, int $force ) : bool
106
	{
107
		return true;
108
	}
109
110
111
	/**
112
	 * Returns the image object for the given file name
113
	 *
114
	 * @param string $file URL or relative path to the file
115
	 * @param string $fsname File system name where the file is stored
116
	 * @return \Intervention\Image\Interfaces\ImageInterface Image object
117
	 */
118
	protected function image( string $file, string $fsname = 'fs-media' ) : ImageInterface
119
	{
120
		if( !isset( $this->driver ) )
121
		{
122
			if( class_exists( '\Intervention\Image\Vips\Driver' ) ) {
123
				$driver = new \Intervention\Image\Vips\Driver();
0 ignored issues
show
Bug introduced by
The type Intervention\Image\Vips\Driver was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
124
			} elseif( class_exists( '\Imagick' ) ) {
125
				$driver = new \Intervention\Image\Drivers\Imagick\Driver();
126
			} else {
127
				$driver = new \Intervention\Image\Drivers\Gd\Driver();
128
			}
129
130
			$this->driver = new \Intervention\Image\ImageManager( $driver );
131
		}
132
133
		if( preg_match( '#^[a-zA-Z]{1,10}://#', $file ) === 1 )
134
		{
135
			if( ( $fh = fopen( $file, 'r' ) ) === false )
136
			{
137
				$msg = $this->context()->translate( 'mshop', 'Unable to open file "%1$s"' );
138
				throw new \RuntimeException( sprintf( $msg, $file ) );
139
			}
140
		}
141
		else
142
		{
143
			$fh = $this->context()->fs( $fsname )->reads( $file );
144
		}
145
146
		$image = $this->driver->read( $fh );
0 ignored issues
show
Bug introduced by
The method read() does not exist on null. ( Ignorable by Annotation )

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

146
		/** @scrutinizer ignore-call */ 
147
  $image = $this->driver->read( $fh );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
147
		fclose( $fh );
148
149
		return $image;
150
	}
151
152
153
	/**
154
	 * Returns the preview images to be deleted
155
	 *
156
	 * @param \Aimeos\MShop\Media\Item\Iface $item Media item with new preview URLs
157
	 * @param array List of preview paths to remove
158
	 * @return iterable List of preview URLs to remove
159
	 */
160
	protected function removePreviews( \Aimeos\MShop\Media\Item\Iface $item, array $paths ) : iterable
161
	{
162
		$previews = $item->getPreviews();
163
164
		// don't delete first (smallest) image because it may be referenced in past orders
165
		if( $item->getDomain() === 'product' && in_array( key( $previews ), $paths ) ) {
166
			return array_slice( $paths, 1 );
167
		}
168
169
		return $paths;
170
	}
171
}
172