Passed
Push — develop ( 33032a...666b96 )
by Henry
02:03
created

Media::createThumbnailImage()   F

Complexity

Conditions 18
Paths 720

Size

Total Lines 117
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 18
eloc 71
c 1
b 0
f 0
nc 720
nop 5
dl 0
loc 117
rs 1.0888

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the Divergence package.
4
 *
5
 * (c) Henry Paradiz <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Divergence\Models\Media;
12
13
use Exception;
14
use Divergence\App;
15
use Divergence\Models\Model;
16
17
/**
18
 * Media Model
19
 *
20
 * @author Henry Paradiz <[email protected]>
21
 * @author  Chris Alfano <[email protected]>
22
 *
23
 * {@inheritDoc}
24
 */
25
class Media extends Model
26
{
27
    public static $useCache = true;
28
    public static $singularNoun = 'media item';
29
    public static $pluralNoun = 'media items';
30
31
    // support subclassing
32
    public static $rootClass = __CLASS__;
33
    public static $defaultClass = __CLASS__;
34
    public static $subClasses = [__CLASS__, Image::class, PDF::class, Video::class, Audio::class];
35
    public static $collectionRoute = '/media';
36
37
    public static $tableName = 'media';
38
39
    public static $fields = [
40
        'ContextClass' => [
41
            'type' => 'string',
42
            'notnull' => false,
43
        ],
44
        'ContextID' => [
45
            'type' => 'integer',
46
            'notnull' => false,
47
        ],
48
        'MIMEType' => 'string',
49
        'Width' => [
50
            'type' => 'integer',
51
            'unsigned' => true,
52
            'notnull' => false,
53
        ],
54
        'Height' => [
55
            'type' => 'integer',
56
            'unsigned' => true,
57
            'notnull' => false,
58
        ],
59
        'Duration' => [
60
            'type' => 'float',
61
            'unsigned' => true,
62
            'notnull' => false,
63
            'default' => 0,
64
        ],
65
        'Caption' => [
66
            'type' => 'string',
67
            'notnull' => false,
68
        ],
69
    ];
70
71
    public static $relationships = [
72
        'Creator' => [
73
            'type' => 'one-one',
74
            'class' => 'Person',
75
            'local' => 'CreatorID',
76
        ],
77
        'Context' => [
78
            'type' => 'context-parent',
79
        ],
80
    ];
81
82
    public static $searchConditions = [
83
        'Caption' => [
84
            'qualifiers' => ['any','caption'],
85
            'points' => 2,
86
            'sql' => 'Caption LIKE "%%%s%%"',
87
        ],
88
        'CaptionLike' => [
89
            'qualifiers' => ['caption-like'],
90
            'points' => 2,
91
            'sql' => 'Caption LIKE "%s"',
92
        ],
93
        'CaptionNot' => [
94
            'qualifiers' => ['caption-not'],
95
            'points' => 2,
96
            'sql' => 'Caption NOT LIKE "%%%s%%"',
97
        ],
98
        'CaptionNotLike' => [
99
            'qualifiers' => ['caption-not-like'],
100
            'points' => 2,
101
            'sql' => 'Caption NOT LIKE "%s"',
102
        ],
103
    ];
104
105
    public static $webPathFormat = '/media/open/%u'; // 1=mediaID
106
    public static $thumbnailRequestFormat = '/thumbnail/%1$u/%2$ux%3$u%4$s'; // 1=media_id 2=width 3=height 4=fill_color
107
    public static $blankThumbnailRequestFormat = '/thumbnail/%1$s/%2$ux%3$u%4$s'; // 1=class 2=width 3=height 4=fill_color
108
    public static $thumbnailJPEGCompression = 90;
109
    public static $thumbnailPNGCompression = 9;
110
    public static $defaultFilenameFormat = 'default.%s.jpg';
111
    public static $newDirectoryPermissions = 0775;
112
    public static $newFilePermissions = 0664;
113
    public static $magicPath = null;//'/usr/share/misc/magic.mgc';
114
    public static $useFaceDetection = true;
115
    public static $faceDetectionTimeLimit = 10;
116
117
    public static $mimeHandlers = [
118
        'image/gif' => Image::class,
119
        'image/jpeg' => Image::class,
120
        'image/png' => Image::class,
121
        'image/tiff' => Image::class,
122
        'application/psd' => Image::class,
123
        'audio/mpeg' => Audio::class,
124
        'application/pdf' => PDF::class,
125
        'application/postscript' => PDF::class,
126
        'image/svg+xml' => PDF::class,
127
        'video/x-flv' => Video::class,
128
        'video/mp4' => Video::class,
129
        'video/quicktime' => Video::class,
130
    ];
131
132
    public static $mimeRewrites = [
133
        'image/photoshop'              => 'application/psd',
134
        'image/x-photoshop'            => 'application/psd',
135
        'image/psd'                    => 'application/psd',
136
        'application/photoshop'        => 'application/psd',
137
        'image/vnd.adobe.photoshop'    => 'application/psd',
138
    ];
139
140
141
    // privates
142
    protected $_webPath;
143
    protected $_filesystemPath;
144
    protected $_mediaInfo;
145
146
147
    // magic methods
148
    public function getValue($name)
149
    {
150
        switch ($name) {
151
            case 'Data':
152
            case 'SummaryData':
153
            case 'JsonTranslation':
154
                return [
155
                    'ID' => $this->ID,
156
                    'Class' => $this->Class,
157
                    'ContextClass' => $this->ContextClass,
158
                    'ContextID' => $this->ContextID,
0 ignored issues
show
Bug Best Practice introduced by
The property ContextID does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
159
                    'MIMEType' => $this->MIMEType,
160
                    'Width' => $this->Width,
161
                    'Height' => $this->Height,
162
                    'Duration' => $this->Duration,
163
                ];
164
165
            case 'Filename':
166
                return $this->getFilename();
167
168
            case 'ThumbnailMIMEType':
169
                return $this->MIMEType;
170
171
            case 'Extension':
172
                throw new Exception('Unable to find extension for mime-type: '.$this->MIMEType);
173
174
            case 'WebPath':
175
176
                if (!isset($this->_webPath)) {
177
                    $this->_webPath = sprintf(
178
                        static::$webPathFormat,
179
                        $this->ID
180
                    );
181
                }
182
183
                return $this->_webPath;
184
185
186
            case 'FilesystemPath':
187
                return $this->getFilesystemPath();
188
189
190
            case 'BlankPath':
191
192
                return static::getBlankPath($this->ContextClass);
193
194
195
            default:
196
                return parent::getValue($name);
197
        }
198
    }
199
200
201
    // public methods
202
    public static function getBlankThumbnailRequest($class, $width, $height, $fillColor = null)
203
    {
204
        return sprintf(
205
            static::$blankThumbnailRequestFormat,
206
            $class,
207
            $width,
208
            $height,
209
            (isset($fillColor) ? 'x'.$fillColor : '')
210
        );
211
    }
212
213
    public function getThumbnailRequest($width, $height = null, $fillColor = null, $cropped = false)
214
    {
215
        return sprintf(
216
            static::$thumbnailRequestFormat,
217
            $this->ID,
218
            $width,
219
            $height ?: $width,
220
            (is_string($fillColor) ? 'x'.$fillColor : '')
221
        ).($cropped ? '/cropped' : '');
222
    }
223
224
    public function getImage($sourceFile = null)
225
    {
226
        if (!isset($sourceFile)) {
227
            $sourceFile = $this->FilesystemPath ? $this->FilesystemPath : $this->BlankPath;
0 ignored issues
show
Bug Best Practice introduced by
The property BlankPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property FilesystemPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
228
        }
229
230
        switch ($this->MIMEType) {
231
            case 'application/psd':
232
            case 'image/tiff':
233
234
                //Converts PSD to PNG temporarily on the real file system.
235
                $tempFile = tempnam('/tmp', 'media_convert');
236
                exec("convert -density 100 ".$this->FilesystemPath."[0] -flatten $tempFile.png");
237
238
                return imagecreatefrompng("$tempFile.png");
239
240
            case 'application/pdf':
241
242
                return PDF::getImage($sourceFile);
0 ignored issues
show
Bug Best Practice introduced by
The method Divergence\Models\Media\PDF::getImage() is not static, but was called statically. ( Ignorable by Annotation )

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

242
                return PDF::/** @scrutinizer ignore-call */ getImage($sourceFile);
Loading history...
243
244
            case 'application/postscript':
245
246
                return imagecreatefromstring(shell_exec("gs -r150 -dEPSCrop -dNOPAUSE -dBATCH -sDEVICE=png48 -sOutputFile=- -q $this->FilesystemPath"));
247
248
            default:
249
250
                if (!$fileData = file_get_contents($sourceFile)) {
251
                    throw new Exception('Could not load media source: '.$sourceFile);
252
                }
253
254
                $image = imagecreatefromstring($fileData);
255
256
                if ($this->MIMEType == 'image/jpeg' && ($exifData = exif_read_data($sourceFile)) && !empty($exifData['Orientation'])) {
257
                    switch ($exifData['Orientation']) {
258
                        case 1: // nothing
259
                            break;
260
                        case 2: // horizontal flip
261
                            imageflip($image, IMG_FLIP_HORIZONTAL); // TODO: need PHP 5.3 compat method
262
                            break;
263
                        case 3: // 180 rotate left
264
                            $image = imagerotate($image, 180, null);
265
                            break;
266
                        case 4: // vertical flip
267
                            imageflip($image, IMG_FLIP_VERTICAL); // TODO: need PHP 5.3 compat method
268
                            break;
269
                        case 5: // vertical flip + 90 rotate right
270
                            imageflip($image, IMG_FLIP_VERTICAL); // TODO: need PHP 5.3 compat method
271
                            $image = imagerotate($image, -90, null);
272
                            break;
273
                        case 6: // 90 rotate right
274
                            $image = imagerotate($image, -90, null);
275
                            break;
276
                        case 7: // horizontal flip + 90 rotate right
277
                            imageflip($image, IMG_FLIP_HORIZONTAL); // TODO: need PHP 5.3 compat method
278
                            $image = imagerotate($image, -90, null);
279
                            break;
280
                        case 8: // 90 rotate left
281
                            $image = imagerotate($image, 90, null);
282
                            break;
283
                    }
284
                }
285
286
                return $image;
287
        }
288
    }
289
290
    public function getThumbnail($maxWidth, $maxHeight, $fillColor = false, $cropped = false)
291
    {
292
        // init thumbnail path
293
        $thumbFormat = sprintf('%ux%u', $maxWidth, $maxHeight);
294
295
        if ($fillColor) {
296
            $thumbFormat .= 'x'.strtoupper($fillColor);
297
        }
298
299
        if ($cropped) {
300
            $thumbFormat .= '.cropped';
301
        }
302
303
        $thumbPath = App::$App->ApplicationPath.'/media/'.$thumbFormat.'/'.$this->Filename;
0 ignored issues
show
Bug Best Practice introduced by
The property Filename does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
304
305
        // look for cached thumbnail
306
        if (!file_exists($thumbPath)) {
307
            // ensure directory exists
308
            $thumbDir = dirname($thumbPath);
309
            if (!is_dir($thumbDir)) {
310
                mkdir($thumbDir, static::$newDirectoryPermissions, true);
311
            }
312
313
            // create new thumbnail
314
            $this->createThumbnailImage($thumbPath, $maxWidth, $maxHeight, $fillColor, $cropped);
315
        }
316
317
318
        // return path
319
        return $thumbPath;
320
    }
321
322
    public function createThumbnailImage($thumbPath, $maxWidth, $maxHeight, $fillColor = false, $cropped = false)
323
    {
324
        $thumbWidth = $maxWidth;
325
        $thumbHeight = $maxHeight;
326
327
        // load source image
328
        $srcImage = $this->getImage();
329
        $srcWidth = imagesx($srcImage);
330
        $srcHeight = imagesy($srcImage);
331
332
        // calculate
333
        if ($srcWidth && $srcHeight) {
334
            $widthRatio = ($srcWidth > $maxWidth) ? ($maxWidth / $srcWidth) : 1;
335
            $heightRatio = ($srcHeight > $maxHeight) ? ($maxHeight / $srcHeight) : 1;
336
337
            // crop width/height to scale size if fill disabled
338
            if ($cropped) {
339
                $ratio = max($widthRatio, $heightRatio);
340
            } else {
341
                $ratio = min($widthRatio, $heightRatio);
342
            }
343
344
            $scaledWidth = round($srcWidth * $ratio);
345
            $scaledHeight = round($srcHeight * $ratio);
346
        } else {
347
            $scaledWidth = $maxWidth;
348
            $scaledHeight = $maxHeight;
349
        }
350
351
        if (!$fillColor && !$cropped) {
352
            $thumbWidth = $scaledWidth;
353
            $thumbHeight = $scaledHeight;
354
        }
355
356
        // create thumbnail images
357
        $image = imagecreatetruecolor($thumbWidth, $thumbHeight);
358
359
        // paint fill color
360
        if ($fillColor) {
361
            // extract decimal values from hex triplet
362
            $fillColor = sscanf($fillColor, '%2x%2x%2x');
363
364
            // convert to color index
365
            $fillColor = imagecolorallocate($image, $fillColor[0], $fillColor[1], $fillColor[2]);
366
367
            // fill background
368
            imagefill($image, 0, 0, $fillColor);
369
        } elseif (($this->MIMEType == 'image/gif') || ($this->MIMEType == 'image/png')) {
370
            $trans_index = imagecolortransparent($srcImage);
371
372
            // check if there is a specific transparent color
373
            if ($trans_index >= 0 && $trans_index < imagecolorstotal($srcImage)) {
374
                $trans_color = imagecolorsforindex($srcImage, $trans_index);
375
376
                // allocate in thumbnail
377
                $trans_index = imagecolorallocate($image, $trans_color['red'], $trans_color['green'], $trans_color['blue']);
378
379
                // fill background
380
                imagefill($image, 0, 0, $trans_index);
381
                imagecolortransparent($image, $trans_index);
382
            } elseif ($this->MIMEType == 'image/png') {
383
                imagealphablending($image, false);
384
                $trans_color = imagecolorallocatealpha($image, 0, 0, 0, 127);
385
                imagefill($image, 0, 0, $trans_color);
386
                imagesavealpha($image, true);
387
            }
388
        }
389
390
        // resize photo to thumbnail
391
        if ($cropped) {
392
            imagecopyresampled(
393
                $image,
394
                $srcImage,
395
                ($thumbWidth - $scaledWidth) / 2,
396
                ($thumbHeight - $scaledHeight) / 2,
397
                0,
398
                0,
399
                $scaledWidth,
400
                $scaledHeight,
401
                $srcWidth,
402
                $srcHeight
403
            );
404
        } else {
405
            imagecopyresampled(
406
                $image,
407
                $srcImage,
408
                round(($thumbWidth - $scaledWidth) / 2),
0 ignored issues
show
Bug introduced by
round($thumbWidth - $scaledWidth / 2) of type double is incompatible with the type integer expected by parameter $dst_x of imagecopyresampled(). ( Ignorable by Annotation )

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

408
                /** @scrutinizer ignore-type */ round(($thumbWidth - $scaledWidth) / 2),
Loading history...
409
                round(($thumbHeight - $scaledHeight) / 2),
0 ignored issues
show
Bug introduced by
round($thumbHeight - $scaledHeight / 2) of type double is incompatible with the type integer expected by parameter $dst_y of imagecopyresampled(). ( Ignorable by Annotation )

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

409
                /** @scrutinizer ignore-type */ round(($thumbHeight - $scaledHeight) / 2),
Loading history...
410
                0,
411
                0,
412
                $scaledWidth,
413
                $scaledHeight,
414
                $srcWidth,
415
                $srcHeight
416
            );
417
        }
418
419
        // save thumbnail to disk
420
        switch ($this->ThumbnailMIMEType) {
0 ignored issues
show
Bug Best Practice introduced by
The property ThumbnailMIMEType does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
421
            case 'image/gif':
422
                imagegif($image, $thumbPath);
423
                break;
424
425
            case 'image/jpeg':
426
                imagejpeg($image, $thumbPath, static::$thumbnailJPEGCompression);
427
                break;
428
429
            case 'image/png':
430
                imagepng($image, $thumbPath, static::$thumbnailPNGCompression);
431
                break;
432
433
            default:
434
                throw new Exception('Unhandled thumbnail format');
435
        }
436
437
        chmod($thumbPath, static::$newFilePermissions);
438
        return true;
439
    }
440
441
    /*
442
    public function delete()
443
    {
444
        // remove file
445
        @unlink($this->FilesystemPath);
446
447
        // delete record
448
        return $this->deleteRecord();
449
    }
450
    */
451
452
453
    // static methods
454
    public static function createFromUpload($uploadedFile, $fieldValues = [])
455
    {
456
        // handle recieving a field array from $_FILES
457
        if (is_array($uploadedFile)) {
458
            if (isset($uploadedFile['error']) && $uploadedFile['error'] != ERR_UPLOAD_OK) {
0 ignored issues
show
Bug introduced by
The constant Divergence\Models\Media\ERR_UPLOAD_OK was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
459
                return null;
460
            }
461
462
            if (!empty($uploadedFile['name']) && empty($fieldValues['Caption'])) {
463
                $fieldValues['Caption'] = preg_replace('/\.[^.]+$/', '', $uploadedFile['name']);
464
            }
465
466
            $uploadedFile = $uploadedFile['tmp_name'];
467
        }
468
469
        // sanity check
470
        if (!is_uploaded_file($uploadedFile)) {
471
            throw new Exception('Supplied file is not a valid upload');
472
        }
473
474
        return static::createFromFile($uploadedFile, $fieldValues);
475
    }
476
477
    public static function createFromFile($file, $fieldValues = [])
478
    {
479
        try {
480
            // handle url input
481
            if (filter_var($file, FILTER_VALIDATE_URL)) {
482
                $tempName = tempnam('/tmp', 'remote_media');
483
                copy($file, $tempName);
484
                $file = $tempName;
485
            }
486
487
            // analyze file
488
            $mediaInfo = static::analyzeFile($file);
489
490
            // create media object
491
            /**
492
             * @var static
493
             */
494
            $Media = $mediaInfo['className']::create($fieldValues);
495
496
            // init media
497
            $Media->initializeFromAnalysis($mediaInfo);
498
499
            // save media
500
            $Media->save();
501
502
            // write file
503
            $Media->writeFile($file);
504
505
            return $Media;
506
        } catch (Exception $e) {
507
            throw $e;
508
        }
509
510
        // remove photo record
511
        if ($Media) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
512
            $Media->destroy();
513
        }
514
515
        return null;
516
    }
517
518
    public function initializeFromAnalysis($mediaInfo)
519
    {
520
        $this->MIMEType = $mediaInfo['mimeType'];
0 ignored issues
show
Bug Best Practice introduced by
The property MIMEType does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
521
        $this->Width = $mediaInfo['width'];
0 ignored issues
show
Bug Best Practice introduced by
The property Width does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
522
        $this->Height = $mediaInfo['height'];
0 ignored issues
show
Bug Best Practice introduced by
The property Height does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
523
        $this->Duration = $mediaInfo['duration'];
0 ignored issues
show
Bug Best Practice introduced by
The property Duration does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
524
    }
525
526
527
    public static function analyzeFile($filename)
528
    {
529
        // DO NOT CALL FROM decendent's override, parent calls child
530
531
        // check file
532
        if (!is_readable($filename)) {
533
            throw new Exception('Unable to read media file for analysis: "'.$filename.'"');
534
        }
535
536
        // get mime type
537
        $finfo = finfo_open(FILEINFO_MIME_TYPE, static::$magicPath);
538
539
        if (!$finfo || !($mimeType = finfo_file($finfo, $filename))) {
0 ignored issues
show
introduced by
$finfo is of type resource, thus it always evaluated to false.
Loading history...
540
            throw new Exception('Unable to load media file info');
541
        }
542
543
        finfo_close($finfo);
544
545
        // dig deeper if only generic mimetype returned
546
        if ($mimeType == 'application/octet-stream') {
547
            $finfo = finfo_open(FILEINFO_NONE, static::$magicPath);
548
549
            if (!$finfo || !($fileInfo = finfo_file($finfo, $filename))) {
550
                throw new Exception('Unable to load media file info');
551
            }
552
553
            finfo_close($finfo);
554
555
            // detect EPS
556
            if (preg_match('/^DOS EPS/i', $fileInfo)) {
557
                $mimeType = 'application/postscript';
558
            }
559
        } elseif (array_key_exists($mimeType, static::$mimeRewrites)) {
560
            $mimeType = static::$mimeRewrites[$mimeType];
561
        }
562
563
        // condense
564
565
566
        // compile mime data
567
        $mediaInfo = [
568
            'mimeType' => $mimeType,
569
        ];
570
571
        // determine handler
572
        $staticClass = get_called_class();
573
        if (!isset(static::$mimeHandlers[$mediaInfo['mimeType']]) || $staticClass != __CLASS__) {
574
            // throw new Exception('No class registered for mime type "' . $mediaInfo['mimeType'] . '"');
575
576
            $mediaInfo['className'] = $staticClass;
577
        } else {
578
            $mediaInfo['className'] = static::$mimeHandlers[$mediaInfo['mimeType']];
579
580
            // call registered type's analyzer
581
            $mediaInfo = call_user_func([$mediaInfo['className'], 'analyzeFile'], $filename, $mediaInfo);
582
        }
583
584
        return $mediaInfo;
585
    }
586
587
    public static function getBlankPath($contextClass)
588
    {
589
        $path = ['site-root','img',sprintf(static::$defaultFilenameFormat, $contextClass)];
590
591
        if ($node = Site::resolvePath($path)) {
0 ignored issues
show
Bug introduced by
The type Divergence\Models\Media\Site 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...
592
            return $node->RealPath;
593
        } else {
594
            throw new Exception('Could not load '.implode('/', $path));
595
        }
596
    }
597
598
    public static function getBlank($contextClass)
599
    {
600
        // get image info
601
        $sourcePath = static::getBlankPath($contextClass);
602
        $sourceInfo = getimagesize($sourcePath);
603
604
        if (!$sourceInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sourceInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
605
            throw new Exception("Unable to load blank image for context '$contextClass' from '$sourcePath'");
606
        }
607
608
        // get mime type
609
        $mimeType = image_type_to_mime_type($sourceInfo[2]);
610
611
        // determine type
612
        if (!isset(static::$mimeHandlers[$mimeType])) {
613
            throw new Exception('No class registered for mime type "'.$mimeType.'"');
614
        }
615
616
        $className = static::$mimeHandlers[$mimeType];
617
618
619
        $blankMedia = new $className();
620
        $blankMedia->ContextClass = $contextClass;
621
        $blankMedia->MIMEType = $mimeType;
622
        $blankMedia->Width = $sourceInfo[0];
623
        $blankMedia->Height = $sourceInfo[1];
624
625
        return $blankMedia;
626
    }
627
628
    public static function getSupportedTypes()
629
    {
630
        return array_unique(array_merge(array_keys(static::$mimeHandlers), array_keys(static::$mimeRewrites)));
631
    }
632
633
    public function getFilesystemPath($variant = 'original', $filename = null)
634
    {
635
        if ($this->isPhantom) {
636
            return null;
637
        }
638
639
        return App::$App->ApplicationPath.'/media/'.$variant.'/'.($filename ?: $this->getFilename($variant));
640
    }
641
642
    public function getFilename($variant = 'original')
0 ignored issues
show
Unused Code introduced by
The parameter $variant 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

642
    public function getFilename(/** @scrutinizer ignore-unused */ $variant = 'original')

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...
643
    {
644
        if ($this->isPhantom) {
645
            return 'default.'.$this->Extension;
0 ignored issues
show
Bug Best Practice introduced by
The property Extension does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
646
        }
647
648
        return $this->ID.'.'.$this->Extension;
649
    }
650
651
    public function getMIMEType($variant = 'original')
652
    {
653
        return $this->MIMEType;
654
    }
655
656
    public function writeFile($sourceFile)
657
    {
658
        $targetDirectory = dirname($this->FilesystemPath);
0 ignored issues
show
Bug introduced by
It seems like $this->FilesystemPath can also be of type array and null; however, parameter $path of dirname() 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

658
        $targetDirectory = dirname(/** @scrutinizer ignore-type */ $this->FilesystemPath);
Loading history...
Bug Best Practice introduced by
The property FilesystemPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
659
660
        // create target directory if needed
661
        if (!is_dir($targetDirectory)) {
662
            mkdir($targetDirectory, static::$newDirectoryPermissions, true);
663
        }
664
665
        // move source file to target path
666
        if (!rename($sourceFile, $this->FilesystemPath)) {
0 ignored issues
show
Bug introduced by
It seems like $this->FilesystemPath can also be of type array and null; however, parameter $to of rename() 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

666
        if (!rename($sourceFile, /** @scrutinizer ignore-type */ $this->FilesystemPath)) {
Loading history...
667
            throw new \Exception('Failed to move source file to destination');
668
        }
669
670
        // set file permissions
671
        chmod($this->FilesystemPath, static::$newFilePermissions);
0 ignored issues
show
Bug introduced by
It seems like $this->FilesystemPath can also be of type array and null; however, parameter $filename of chmod() 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

671
        chmod(/** @scrutinizer ignore-type */ $this->FilesystemPath, static::$newFilePermissions);
Loading history...
672
    }
673
674
    public function isVariantAvailable($variant)
675
    {
676
        return false;
677
    }
678
}
679