FileBehavior   F
last analyzed

Complexity

Total Complexity 118

Size/Duplication

Total Lines 679
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 118
eloc 304
c 5
b 0
f 0
dl 0
loc 679
rs 2

20 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 13 3
A getDimensionsByLongerSide() 0 9 2
A deleteFiles() 0 19 6
B getDimensionsByFitToSquare() 0 34 6
A setPath() 0 7 2
A afterDelete() 0 3 1
A getFiles() 0 3 1
A beforeMarshal() 0 12 5
A getDimensionsByNewHeight() 0 10 2
A getPath() 0 7 2
B getDimensionsByFit() 0 42 10
A getDimensionsByNewWidth() 0 10 2
A getExtension() 0 17 5
A setFile() 0 3 1
B getPosition() 0 43 10
A getDimensionsByShorterSide() 0 9 2
A afterSave() 0 20 6
F createThumbs() 0 181 50
A createName() 0 3 1
A beforeDelete() 0 12 1

How to fix   Complexity   

Complex Class

Complex classes like FileBehavior 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 FileBehavior, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace File\Model\Behavior;
3
4
use Cake\Datasource\EntityInterface;
5
use Cake\Event\Event;
6
use Cake\Event\EventInterface;
7
use Cake\ORM\Behavior;
8
use Cake\Utility\Text;
9
use File\Exception\LibraryException;
10
use File\Exception\PathException;
11
use File\Exception\ThumbsException;
12
use Laminas\Diactoros\UploadedFile;
0 ignored issues
show
Bug introduced by
The type Laminas\Diactoros\UploadedFile 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...
13
use ArrayObject;
14
use File\Exception\AccessibleException;
15
16
class FileBehavior extends Behavior
17
{
18
19
    /**
20
     * Default config.
21
     *
22
     * @var array
23
     */
24
    public $defaultConfig = [
25
        'library' => 'gd',
26
        'types' => [ // Default allowed types.
27
            'image/bmp',
28
            'image/gif',
29
            'image/jpeg',
30
            'image/jpg',
31
            'image/pjpeg',
32
            'image/pjpg',
33
            'image/png',
34
            'image/x-png',
35
            'image/webp',
36
        ],
37
        'extensions' => [ // Default allowed extensions.
38
            'bmp',
39
            'gif',
40
            'jpeg',
41
            'jpg',
42
            'pjpg',
43
            'pjpeg',
44
            'png',
45
            'webp',
46
        ],
47
        'path' => 'files',
48
        'background' => [255, 255, 255, 127],
49
        'watermark' => '',
50
        'thumbs' => [],
51
    ];
52
53
    /**
54
     * Array of files to upload.
55
     *
56
     * @var array
57
     */
58
    protected $files = [];
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function initialize(array $config): void
64
    {
65
        parent::initialize($config);
66
67
        foreach ($this->getConfig() as $file => $fileConfig) {
68
            $this->_configDelete($file);
69
70
            if (!is_array($fileConfig)) {
71
                $file = $fileConfig;
72
73
                $this->setConfig($file, $this->defaultConfig);
74
            } else {
75
                $this->setConfig($file, $config[$file] += $this->defaultConfig);
76
            }
77
        }
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     */
83
    public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

83
    public function beforeMarshal(Event $event, ArrayObject $data, /** @scrutinizer ignore-unused */ ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

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

83
    public function beforeMarshal(/** @scrutinizer ignore-unused */ Event $event, ArrayObject $data, ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
84
    {
85
        $config = $this->getConfig();
86
87
        if (!empty($config)) {
88
            foreach (array_keys($config) as $file) {
89
                if (isset($data[$file]) && !empty($data[$file]->getClientFilename())) {
90
                    $this->setFile($file, $data[$file]);
91
92
                    $data[$file] = $this->createName($data[$file]->getClientFilename());
93
                } else {
94
                    unset($data[$file]);
95
                }
96
            }
97
        }
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     */
103
    public function afterSave(EventInterface $event, EntityInterface $entity, ArrayObject $options)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

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

103
    public function afterSave(/** @scrutinizer ignore-unused */ EventInterface $event, EntityInterface $entity, ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

103
    public function afterSave(EventInterface $event, EntityInterface $entity, /** @scrutinizer ignore-unused */ ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
104
    {
105
        $files = $this->getFiles();
106
107
        if (!empty($files)) {
108
            foreach ($files as $file => $fileObject) {
109
                if ($entity->isAccessible($file)) {
110
                    if ($fileObject->getError() === 0) {
111
                        $fileConfig = $this->getConfig($file);
112
113
                        // Move original file
114
                        $fileObject->moveTo($this->getPath($fileConfig['path']) . DS . $entity->{$file});
115
116
                        // Prepare thumb files
117
                        if (!empty($fileConfig['thumbs'])) {
118
                            $this->createThumbs($entity->{$file}, $fileConfig);
119
                        }
120
                    }
121
                } else {
122
                    throw new AccessibleException(__d('file', 'Field {0} should be accessible.', $file));
123
                }
124
            }
125
        }
126
    }
127
128
    /**
129
     * {@inheritDoc}
130
     */
131
    public function beforeDelete(Event $event, EntityInterface $entity, ArrayObject $options)
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

131
    public function beforeDelete(Event $event, EntityInterface $entity, /** @scrutinizer ignore-unused */ ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

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

131
    public function beforeDelete(/** @scrutinizer ignore-unused */ Event $event, EntityInterface $entity, ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
132
    {
133
        $entity = $this->getTable()->find()->select(
134
            array_merge(
135
                [$this->getTable()->getPrimaryKey()],
136
                array_keys($this->getConfig())
137
            )
138
        )->where([
139
            $this->getTable()->getAlias() . '.' . $this->getTable()->getPrimaryKey() => $entity->{$this->getTable()->getPrimaryKey()},
0 ignored issues
show
Bug introduced by
Are you sure $this->getTable()->getPrimaryKey() of type string|string[] can be used in concatenation? ( Ignorable by Annotation )

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

139
            $this->getTable()->getAlias() . '.' . /** @scrutinizer ignore-type */ $this->getTable()->getPrimaryKey() => $entity->{$this->getTable()->getPrimaryKey()},
Loading history...
140
        ])->first();
141
142
        return $this->deleteFiles($entity);
0 ignored issues
show
Bug introduced by
It seems like $entity can also be of type array and null; however, parameter $entity of File\Model\Behavior\FileBehavior::deleteFiles() does only seem to accept Cake\Datasource\EntityInterface, 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

142
        return $this->deleteFiles(/** @scrutinizer ignore-type */ $entity);
Loading history...
143
    }
144
145
    /**
146
     * {@inheritDoc}
147
     */
148
    public function afterDelete(Event $event, EntityInterface $entity, ArrayObject $options)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

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

148
    public function afterDelete(/** @scrutinizer ignore-unused */ Event $event, EntityInterface $entity, ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

148
    public function afterDelete(Event $event, EntityInterface $entity, /** @scrutinizer ignore-unused */ ArrayObject $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
149
    {
150
        return $this->deleteFiles($entity);
151
    }
152
153
    /**
154
     * Create thumbs.
155
     *
156
     * @param string $file File name.
157
     * @param array $fileConfig File config.
158
     */
159
    protected function createThumbs(string $file, array $fileConfig): void
160
    {
161
        $filePath = $fileConfig['path'] . DS . $file;
162
163
        if (is_file($filePath)) {
164
            // Check installed image library
165
            if (!extension_loaded($fileConfig['library'])) {
166
                throw new LibraryException(__d('file', 'The library identified by {0} is not loaded!', $fileConfig['library']));
167
            }
168
169
            // Get extension from original file
170
            $fileExtension = $this->getExtension($file);
171
172
            $fileConfig['library'] = mb_strtolower($fileConfig['library']);
173
174
            switch ($fileConfig['library']) {
175
                // Get image resource
176
                case 'gd':
177
                    switch ($fileExtension) {
178
                        case 'bmp':
179
                            $sourceImage = imagecreatefrombmp($filePath);
180
181
                            break;
182
                        case 'gif':
183
                            $sourceImage = imagecreatefromgif($filePath);
184
185
                            break;
186
                        case 'png':
187
                            $sourceImage = imagecreatefrompng($filePath);
188
189
                            break;
190
                        case 'webp':
191
                            $sourceImage = imagecreatefromwebp($filePath);
192
193
                            break;
194
                        default:
195
                            ini_set('gd.jpeg_ignore_warning', 1);
196
197
                            $sourceImage = imagecreatefromjpeg($filePath);
198
199
                            break;
200
                    }
201
202
                    // Get original width and height
203
                    $originalWidth = imagesx($sourceImage);
0 ignored issues
show
Bug introduced by
It seems like $sourceImage can also be of type false; however, parameter $image of imagesx() does only seem to accept resource, 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

203
                    $originalWidth = imagesx(/** @scrutinizer ignore-type */ $sourceImage);
Loading history...
204
                    $originalHeight = imagesy($sourceImage);
0 ignored issues
show
Bug introduced by
It seems like $sourceImage can also be of type false; however, parameter $image of imagesy() does only seem to accept resource, 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

204
                    $originalHeight = imagesy(/** @scrutinizer ignore-type */ $sourceImage);
Loading history...
205
206
                    break;
207
                case 'imagick':
208
                    $sourceImage = new \Imagick($originalFile);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $originalFile does not exist. Did you maybe mean $originalWidth?
Loading history...
209
210
                    // Get original width and height
211
                    $originalWidth = $sourceImage->getimagewidth();
212
                    $originalHeight = $sourceImage->getimageheight();
213
214
                    break;
215
                default:
216
                    throw new LibraryException(__d('file', 'The library identified by {0} it is not known as image processing!', $fileConfig['library']));
217
            }
218
219
            $offsetX = 0;
220
            $offsetY = 0;
221
222
            $cropX = 0;
223
            $cropY = 0;
224
225
            foreach ($fileConfig['thumbs'] as $thumbName => $thumbConfig) {
226
                if (isset($thumbConfig['width'])) {
227
                    list($newWidth, $newHeight) = $this->getDimensionsByNewWidth($originalWidth, $originalHeight, $thumbConfig['width']);
228
                } elseif (isset($thumbConfig['height'])) {
229
                    list($newWidth, $newHeight) = $this->getDimensionsByNewHeight($originalWidth, $originalHeight, $thumbConfig['height']);
230
                } elseif (isset($thumbConfig['shorter']) && is_array($thumbConfig['shorter']) && count($thumbConfig['shorter']) === 2) {
231
                    list($newWidth, $newHeight) = $this->getDimensionsByShorterSide($originalWidth, $originalHeight, $thumbConfig['shorter'][0], $thumbConfig['shorter'][1]);
232
                } elseif (isset($thumbConfig['longer']) && is_array($thumbConfig['longer']) && count($thumbConfig['longer']) === 2) {
233
                    list($newWidth, $newHeight) = $this->getDimensionsByLongerSide($originalWidth, $originalHeight, $thumbConfig['longer'][0], $thumbConfig['longer'][1]);
234
                } elseif (isset($thumbConfig['fit']) && is_array($thumbConfig['fit']) && count($thumbConfig['fit']) === 2) {
235
                    list($newWidth, $newHeight, $offsetX, $offsetY, $cropX, $cropY) = $this->getDimensionsByFit($originalWidth, $originalHeight, $thumbConfig['fit'][0], $thumbConfig['fit'][1]);
236
                } elseif (isset($thumbConfig['fit']) && is_array($thumbConfig['fit']) && count($thumbConfig['fit']) === 3) {
237
                    list($newWidth, $newHeight, $offsetX, $offsetY, $cropX, $cropY) = $this->getDimensionsByFit($originalWidth, $originalHeight, $thumbConfig['fit'][0], $thumbConfig['fit'][1], $thumbConfig['fit'][2]);
238
                } elseif (isset($thumbConfig['square']) && is_array($thumbConfig['square']) && count($thumbConfig['square']) === 1) {
239
                    list($newWidth, $newHeight, $offsetX, $offsetY, $cropX, $cropY) = $this->getDimensionsByFitToSquare($originalWidth, $originalHeight, $thumbConfig['square'][0]);
240
                } elseif (isset($thumbConfig['square']) && is_array($thumbConfig['square']) && count($thumbConfig['square']) === 2) {
241
                    list($newWidth, $newHeight, $offsetX, $offsetY, $cropX, $cropY) = $this->getDimensionsByFitToSquare($originalWidth, $originalHeight, $thumbConfig['square'][0], $thumbConfig['square'][1]);
242
                } else {
243
                    throw new ThumbsException(__d('file', 'Unknown type or incorrect parameters of creating thumbnails!'));
244
                }
245
246
                $thumbFile = str_replace('default', $thumbName, $filePath);
247
248
                switch ($fileConfig['library']) {
249
                    // Get image resource
250
                    case 'gd':
251
                        $newImage = imagecreatetruecolor($newWidth, $newHeight);
252
253
                        if (is_array($fileConfig['background'])) {
254
                            // Set background color and transparent indicates
255
                            imagefill($newImage, 0, 0, imagecolorallocatealpha($newImage, $fileConfig['background'][0], $fileConfig['background'][1], $fileConfig['background'][2], $fileConfig['background'][3]));
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagefill() does only seem to accept resource, 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

255
                            imagefill(/** @scrutinizer ignore-type */ $newImage, 0, 0, imagecolorallocatealpha($newImage, $fileConfig['background'][0], $fileConfig['background'][1], $fileConfig['background'][2], $fileConfig['background'][3]));
Loading history...
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagecolorallocatealpha() does only seem to accept resource, 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

255
                            imagefill($newImage, 0, 0, imagecolorallocatealpha(/** @scrutinizer ignore-type */ $newImage, $fileConfig['background'][0], $fileConfig['background'][1], $fileConfig['background'][2], $fileConfig['background'][3]));
Loading history...
256
                        }
257
258
                        imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $dst_image of imagecopyresampled() does only seem to accept resource, 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

258
                        imagecopyresampled(/** @scrutinizer ignore-type */ $newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);
Loading history...
259
260
                        if ((isset($thumbConfig['square']) && is_array($thumbConfig['square'])) || (isset($thumbConfig['fit']) && is_array($thumbConfig['fit']))) {
261
                            $fitImage = imagecreatetruecolor($newWidth + (2 * $offsetX) - (2 * $cropX), $newHeight + (2 * $offsetY) - (2 * $cropY));
262
263
                            if (is_array($fileConfig['background'])) {
264
                                // Set background color and transparent indicates
265
                                imagefill($fitImage, 0, 0, imagecolorallocatealpha($fitImage, $fileConfig['background'][0], $fileConfig['background'][1], $fileConfig['background'][2], $fileConfig['background'][3]));
266
                            }
267
268
                            imagecopyresampled($fitImage, $newImage, $offsetX, $offsetY, $cropX, $cropY, $newWidth, $newHeight, $newWidth, $newHeight);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $src_image of imagecopyresampled() does only seem to accept resource, 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

268
                            imagecopyresampled($fitImage, /** @scrutinizer ignore-type */ $newImage, $offsetX, $offsetY, $cropX, $cropY, $newWidth, $newHeight, $newWidth, $newHeight);
Loading history...
269
270
                            $newImage = $fitImage;
271
                        }
272
273
                        imagealphablending($newImage, false);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagealphablending() does only seem to accept resource, 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

273
                        imagealphablending(/** @scrutinizer ignore-type */ $newImage, false);
Loading history...
274
                        imagesavealpha($newImage, true);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagesavealpha() does only seem to accept resource, 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

274
                        imagesavealpha(/** @scrutinizer ignore-type */ $newImage, true);
Loading history...
275
276
                        // Watermark
277
                        if (isset($thumbConfig['watermark']) && ($watermarkSource = file_get_contents($fileConfig['watermark'])) !== false) {
278
                            $watermarkImage = imagecreatefromstring($watermarkSource);
279
280
                            list($watermarkPositionX, $watermarkPositionY) = $this->getPosition(imagesx($newImage), imagesy($newImage), imagesx($watermarkImage), imagesy($watermarkImage), $offsetX, $offsetY, $thumbConfig['watermark']);
281
282
                            // Set transparent
283
                            imagealphablending($newImage, true);
284
                            imagecopy($newImage, $watermarkImage, $watermarkPositionX, $watermarkPositionY, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage));
0 ignored issues
show
Bug introduced by
It seems like $watermarkImage can also be of type false; however, parameter $src_im of imagecopy() does only seem to accept resource, 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

284
                            imagecopy($newImage, /** @scrutinizer ignore-type */ $watermarkImage, $watermarkPositionX, $watermarkPositionY, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage));
Loading history...
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $dst_im of imagecopy() does only seem to accept resource, 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

284
                            imagecopy(/** @scrutinizer ignore-type */ $newImage, $watermarkImage, $watermarkPositionX, $watermarkPositionY, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage));
Loading history...
285
                        }
286
287
                        // Set resource file type
288
                        switch ($fileExtension) {
289
                            case 'bmp':
290
                                imagebmp($newImage, $thumbFile);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagebmp() does only seem to accept resource, 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

290
                                imagebmp(/** @scrutinizer ignore-type */ $newImage, $thumbFile);
Loading history...
291
292
                                break;
293
                            case 'gif':
294
                                imagegif($newImage, $thumbFile);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagegif() does only seem to accept resource, 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

294
                                imagegif(/** @scrutinizer ignore-type */ $newImage, $thumbFile);
Loading history...
295
296
                                break;
297
                            case 'png':
298
                                imagepng($newImage, $thumbFile);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagepng() does only seem to accept resource, 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

298
                                imagepng(/** @scrutinizer ignore-type */ $newImage, $thumbFile);
Loading history...
299
300
                                break;
301
                            case 'webp':
302
                                imagewebp($newImage, $thumbFile);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagewebp() does only seem to accept resource, 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

302
                                imagewebp(/** @scrutinizer ignore-type */ $newImage, $thumbFile);
Loading history...
303
304
                                break;
305
                            default:
306
                                imagejpeg($newImage, $thumbFile, 100);
0 ignored issues
show
Bug introduced by
It seems like $newImage can also be of type false; however, parameter $image of imagejpeg() does only seem to accept resource, 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

306
                                imagejpeg(/** @scrutinizer ignore-type */ $newImage, $thumbFile, 100);
Loading history...
307
308
                                break;
309
                        }
310
311
                        break;
312
                    case 'imagick':
313
                        $newImage = $sourceImage->clone();
314
315
                        $newImage->scaleimage($newWidth, $newHeight);
316
                        $newImage->setimagebackgroundcolor('transparent');
317
                        $newImage->extentimage($newWidth + (2 * $offsetX), $newHeight + (2 * $offsetY), -$offsetX, -$offsetY);
318
319
                        if ((isset($thumbConfig['square']) && is_array($thumbConfig['square'])) || (isset($thumbConfig['fit']) && is_array($thumbConfig['fit']))) {
320
                            $newImage->cropimage($newWidth + (2 * $offsetX) - (2 * $cropX), $newHeight + (2 * $offsetY) - (2 * $cropY), $cropX, $cropY);
321
                        }
322
323
                        // Watermark
324
                        if (isset($thumbConfig['watermark']) && ($watermarkSource = file_get_contents($fileConfig['watermark'])) !== false) {
325
                            $watermarkImage = new \Imagick();
326
                            $watermarkImage->readimageblob($watermarkSource);
327
328
                            list($watermarkPositionX, $watermarkPositionY) = $this->getPosition($newWidth, $newHeight, $watermarkImage->getimagewidth(), $watermarkImage->getimageheight(), $offsetX, $offsetY, $thumbConfig['watermark']);
329
330
                            $newImage->compositeimage($watermarkImage, \Imagick::COMPOSITE_OVER, $watermarkPositionX, $watermarkPositionY);
331
                        }
332
333
                        // Set object file type
334
                        $newImage->setImageFormat($fileExtension);
335
336
                        $newImage->writeimage($thumbFile);
337
                        $newImage->clear();
338
339
                        break;
340
                }
341
            }
342
        }
343
    }
344
345
    /**
346
     * Delete files with created thumbs.
347
     *
348
     * @param EntityInterface $entity Entity
349
     * @return boolean True if is successful.
350
     */
351
    protected function deleteFiles(EntityInterface $entity)
352
    {
353
        $config = $this->getConfig();
354
355
        if (!empty($config)) {
356
            foreach ($config as $file => $fileConfig) {
357
                if (isset($entity[$file])) {
358
                    $path = $fileConfig['path'] . DS . substr($entity[$file], 0, 37);
359
360
                    foreach (glob($path . '*') as $file) {
0 ignored issues
show
Comprehensibility Bug introduced by
$file is overwriting a variable from outer foreach loop.
Loading history...
361
                        if (file_exists($file)) {
362
                            unlink($file);
363
                        }
364
                    }
365
                }
366
            }
367
        }
368
369
        return true;
370
    }
371
372
    /**
373
     * Get files fields with config.
374
     *
375
     * @return array Files fields with config.
376
     */
377
    protected function getFiles(): array
378
    {
379
        return $this->files;
380
    }
381
382
    /**
383
     * Set file fields config.
384
     *
385
     * @param string $file File name.
386
     * @param UploadedFile $data Uploaded data.
387
     */
388
    protected function setFile(string $file, UploadedFile $data): void
389
    {
390
        $this->files[$file] = $data;
391
    }
392
393
    /**
394
     * Get file path.
395
     *
396
     * @param string $path Path.
397
     * @return string Path.
398
     */
399
    protected function getPath(string $path): string
400
    {
401
        if (!is_dir($path)) {
402
            $this->setPath($path);
403
        }
404
405
        return $path;
406
    }
407
408
    /**
409
     * Set file path.
410
     *
411
     * @param string $path Path.
412
     * @return string Path.
413
     */
414
    protected function setPath(string $path): string
415
    {
416
        if (mkdir($path, 0777, true)) {
417
            return $path;
418
        }
419
420
        throw new PathException(__d('file', 'Could not set path'));
421
    }
422
423
    /**
424
     * Create file name.
425
     *
426
     * @param string $name Uploaded file name.
427
     * @return string Unique file name.
428
     */
429
    protected function createName(string $name): string
430
    {
431
        return Text::uuid() . '_default.' . $this->getExtension($name);
432
    }
433
434
    /**
435
     * Get extension from file name.
436
     *
437
     * @param string $name File name.
438
     * @return string Extension of uploaded file.
439
     */
440
    protected function getExtension(string $name): string
441
    {
442
        $fileExtension = pathinfo(mb_strtolower($name), PATHINFO_EXTENSION);
443
444
        switch ($fileExtension) {
445
            case 'jpg':
446
            case 'jpeg':
447
            case 'pjpg':
448
            case 'pjpeg':
449
                // Standarize JPEG image file extension
450
                return 'jpg';
451
452
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
453
            default:
454
                return $fileExtension;
455
456
                break;
457
        }
458
    }
459
460
    /**
461
     * Get position of watermark image.
462
     *
463
     * @param integer $newWidth New width of uploaded image.
464
     * @param integer $newHeight New height of uploaded image.
465
     * @param integer $watermarkWidth Original width of watermark image.
466
     * @param integer $watermarkHeight Original height of watermark image.
467
     * @param integer $offsetX Horizontal offset.
468
     * @param integer $offsetY Vertical offset.
469
     * @param integer $positionValue Value for position watermark, value between 1 and 9.
470
     * @return array Coordinates of position watermark.
471
     */
472
    protected function getPosition(int $newWidth, int $newHeight, int $watermarkWidth, int $watermarkHeight, int $offsetX = 0, int $offsetY = 0, int $positionValue = 1): array
473
    {
474
        switch ($positionValue) {
475
            case 1: // Top left
476
                return [$offsetX, $offsetY];
477
478
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
479
            case 2: // Top center
480
                return [($newWidth / 2) - ($watermarkWidth / 2), $offsetY];
481
482
                break;
483
            case 3: // Top right
484
                return [($newWidth - $watermarkWidth - $offsetX), $offsetY];
485
486
                break;
487
            case 4: // Middle left
488
                return [$offsetX, intval(($newHeight / 2) - ($watermarkHeight / 2))];
489
490
                break;
491
            case 5: // Middle center
492
                return [intval(($newWidth / 2) - ($watermarkWidth / 2)), intval(($newHeight / 2) - ($watermarkHeight / 2))];
493
494
                break;
495
            case 6: // Middle right
496
                return [($newWidth - $watermarkWidth) - $offsetX, intval(($newHeight / 2) - ($watermarkHeight / 2))];
497
498
                break;
499
            case 7: // Bottom left
500
                return [$offsetX, ($newHeight - $watermarkHeight) - $offsetY];
501
502
                break;
503
            case 8: // Bottom center
504
                return [intval(($newWidth / 2) - ($watermarkWidth / 2)), ($newHeight - $watermarkHeight) - $offsetY];
505
506
                break;
507
            case 9: // Bottom right
508
                return [($newWidth - $watermarkWidth) - $offsetX, ($newHeight - $watermarkHeight) - $offsetY];
509
510
                break;
511
            default:
512
                return [$offsetX, $offsetY];
513
514
                break;
515
        }
516
    }
517
518
    /**
519
     * Get dimension by new width.
520
     *
521
     * @param integer $originalWidth Original width of uploaded image.
522
     * @param integer $originalHeight Original height of uploaded image.
523
     * @param integer $newWidth Set new image width.
524
     * @return array New width and height.
525
     */
526
    public static function getDimensionsByNewWidth(int $originalWidth, int $originalHeight, int $newWidth): array
527
    {
528
        if ($newWidth > $originalWidth) {
529
            $newWidth = $originalWidth;
530
            $newHeight = $originalHeight;
531
        } else {
532
            $newHeight = intval($newWidth * ($originalHeight / $originalWidth));
533
        }
534
535
        return [$newWidth, $newHeight];
536
    }
537
538
    /**
539
     * Get dimension by new height.
540
     *
541
     * @param integer $originalWidth Original width of uploaded image.
542
     * @param integer $originalHeight Original height of uploaded image.
543
     * @param integer $newHeight Set new image height.
544
     * @return array New width and height.
545
     */
546
    public static function getDimensionsByNewHeight(int $originalWidth, int $originalHeight, int $newHeight): array
547
    {
548
        if ($newHeight > $originalHeight) {
549
            $newHeight = $originalHeight;
550
            $newWidth = $originalWidth;
551
        } else {
552
            $newWidth = intval($newHeight * ($originalWidth / $originalHeight));
553
        }
554
555
        return [$newWidth, $newHeight];
556
    }
557
558
    /**
559
     * Get dimension by shorter side.
560
     *
561
     * @param integer $originalWidth Original width of uploaded image.
562
     * @param integer $originalHeight Original height of uploaded image.
563
     * @param integer $newWidth Set new image min width.
564
     * @param integer $newHeight Set new image min height.
565
     * @return array New width and height.
566
     */
567
    public static function getDimensionsByShorterSide(int $originalWidth, int $originalHeight, int $newWidth, int $newHeight): array
568
    {
569
        if ($originalWidth < $originalHeight) {
570
            list($newWidth, $newHeight) = self::getDimensionsByNewWidth($originalWidth, $originalHeight, $newWidth);
571
        } else {
572
            list($newWidth, $newHeight) = self::getDimensionsByNewHeight($originalWidth, $originalHeight, $newHeight);
573
        }
574
575
        return [$newWidth, $newHeight];
576
    }
577
578
    /**
579
     * Get dimension by longer side.
580
     *
581
     * @param integer $originalWidth Original width of uploaded image.
582
     * @param integer $originalHeight Original height of uploaded image.
583
     * @param integer $newWidth Set new image max width.
584
     * @param integer $newHeight Set new image max height.
585
     * @return array New width and height.
586
     */
587
    public static function getDimensionsByLongerSide(int $originalWidth, int $originalHeight, int $newWidth, int $newHeight): array
588
    {
589
        if ($originalWidth > $originalHeight) {
590
            list($newWidth, $newHeight) = self::getDimensionsByNewWidth($originalWidth, $originalHeight, $newWidth);
591
        } else {
592
            list($newWidth, $newHeight) = self::getDimensionsByNewHeight($originalWidth, $originalHeight, $newHeight);
593
        }
594
595
        return [$newWidth, $newHeight];
596
    }
597
598
    /**
599
     * Get dimension by fit.
600
     *
601
     * @param integer $originalWidth Original width of uploaded image.
602
     * @param integer $originalHeight Original height of uploaded image.
603
     * @param integer $newWidth Set new image width.
604
     * @param integer $newHeight Set new image height.
605
     * @param boolean $originalKeep Save original shape.
606
     * @return array New width and height and offsets of position with keeping original shape.
607
     */
608
    public static function getDimensionsByFit(int $originalWidth, int $originalHeight, int $newWidth, int $newHeight, bool $originalKeep = false): array
609
    {
610
        $offsetX = 0;
611
        $offsetY = 0;
612
        $cropX = 0;
613
        $cropY = 0;
614
615
        if ($originalKeep === true) {
616
            if ($originalWidth == $originalHeight) {
617
                $newSizes = self::getDimensionsByLongerSide($originalWidth, $originalHeight, min($newWidth, $newHeight), min($newWidth, $newHeight));
618
            } else {
619
                $newSizes = self::getDimensionsByLongerSide($originalWidth, $originalHeight, $newWidth, $newHeight);
620
621
                if ($newWidth < $newSizes[0] || $newHeight < $newSizes[1]) {
622
                    $newSizes = self::getDimensionsByShorterSide($originalWidth, $originalHeight, $newWidth, $newHeight);
623
                }
624
            }
625
        } else {
626
            if ($originalWidth == $originalHeight) {
627
                $newSizes = self::getDimensionsByShorterSide($originalWidth, $originalHeight, max($newWidth, $newHeight), max($newWidth, $newHeight));
628
            } else {
629
                $newSizes = self::getDimensionsByShorterSide($originalWidth, $originalHeight, $newWidth, $newHeight);
630
631
                if ($newWidth > $newSizes[0] || $newHeight > $newSizes[1]) {
632
                    $newSizes = self::getDimensionsByLongerSide($originalWidth, $originalHeight, $newWidth, $newHeight);
633
                }
634
            }
635
        }
636
637
        if ($newWidth < $newSizes[0]) {
638
            $cropX = ($newSizes[0] - $newWidth) / 2;
639
        } else {
640
            $offsetX = ($newWidth - $newSizes[0]) / 2;
641
        }
642
643
        if ($newHeight < $newSizes[1]) {
644
            $cropY = ($newSizes[1] - $newHeight) / 2;
645
        } else {
646
            $offsetY = ($newHeight - $newSizes[1]) / 2;
647
        }
648
649
        return [$newSizes[0], $newSizes[1], intval($offsetX), intval($offsetY), intval($cropX), intval($cropY)];
650
    }
651
652
    /**
653
     * Get dimension to square.
654
     *
655
     * @param integer $originalWidth Original width of uploaded image.
656
     * @param integer $originalHeight Original height of uploaded image.
657
     * @param integer $newSide Set new image side.
658
     * @param boolean $originalKeep Save original shape.
659
     * @return array New width and height with coordinates of crop or offsets of position.
660
     */
661
    public static function getDimensionsByFitToSquare(int $originalWidth, int $originalHeight, int $newSide, bool $originalKeep = false): array
662
    {
663
        $offsetX = 0;
664
        $offsetY = 0;
665
        $cropX = 0;
666
        $cropY = 0;
667
668
        if ($originalKeep === true) {
669
            list($newWidth, $newHeight) = self::getDimensionsByLongerSide($originalWidth, $originalHeight, $newSide, $newSide);
670
671
            if ($newSide > $newWidth) {
672
                $offsetX = ($newSide - $newWidth) / 2;
673
            }
674
675
            if ($newSide > $newHeight) {
676
                $offsetY = ($newSide - $newHeight) / 2;
677
            }
678
        } else {
679
            list($newWidth, $newHeight) = self::getDimensionsByShorterSide($originalWidth, $originalHeight, $newSide, $newSide);
680
681
            if ($newSide < $newWidth) {
682
                $cropX = ($newWidth - $newSide) / 2;
683
            } else {
684
                $offsetX = ($newSide - $newWidth) / 2;
685
            }
686
687
            if ($newSide < $newHeight) {
688
                $cropY = ($newHeight - $newSide) / 2;
689
            } else {
690
                $offsetY = ($newSide - $newHeight) / 2;
691
            }
692
        }
693
694
        return [$newWidth, $newHeight, intval($offsetX), intval($offsetY), intval($cropX), intval($cropY)];
695
    }
696
}