Completed
Pull Request — master (#9)
by Laurens
02:02
created

ProductImageUpload::getArrayData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 7
nc 2
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LauLamanApps\IzettleApi\API\Image;
6
7
use Exception;
8
use LauLamanApps\IzettleApi\API\Image\Exceptions\FileIsNotAnImageException;
9
use LauLamanApps\IzettleApi\API\Image\Exceptions\ImageIsToSmallException;
10
use LauLamanApps\IzettleApi\API\Image\Exceptions\ImageTypeNotAllowedException;
11
use LauLamanApps\IzettleApi\API\Image\Exceptions\MaximumImageFileSizeExcededException;
12
13
final class ProductImageUpload
14
{
15
    const ALLOWED_FILE_TYPES = [
16
        IMAGETYPE_GIF => 'GIF',
17
        IMAGETYPE_JPEG => 'JPEG',
18
        IMAGETYPE_PNG => 'PNG',
19
        IMAGETYPE_BMP => 'BMP',
20
        IMAGETYPE_TIFF_II => 'TIFF',
21
        IMAGETYPE_TIFF_MM => 'TIFF'
22
    ];
23
    const MAX_FILE_SIZE_MB = 5;
24
    const MINIMAL_HEIGHT = 50;
25
    const MINIMAL_WIDTH = 50;
26
27
    private $imageFormat;
28
    private $imageData;
29
    private $imageUrl;
30
31 2
    private function __construct()
32
    {
33 2
    }
34
35 2
    public function getArrayData(): array
36
    {
37 2
        if ($this->imageUrl) {
38
            return [
39 1
                'imageUrl' => $this->imageUrl,
40
            ];
41
        }
42
43
        return [
44 1
            'imageFormat' => $this->imageFormat,
45 1
            'imageData' => $this->imageData,
46
        ];
47
    }
48
49 1
    public static function url(string $url): self
50
    {
51 1
        $image = new self();
52 1
        $image->imageUrl = $url;
53
54 1
        return $image;
55
    }
56
57 5
    public static function file(string $file)
58
    {
59 5
        self::validateFile($file);
60 1
        $image = new self();
61 1
        $image->imageFormat = self::ALLOWED_FILE_TYPES[exif_imagetype($file)];
62 1
        $image->imageData = file_get_contents($file);
63
64 1
        return $image;
65
    }
66
67 5
    private static function validateFile($file)
68
    {
69 5
        self::validateFileSize($file);
70 4
        self::validatedImageType($file);
71 2
        self::validateImageSize($file);
72 1
    }
73
74 5
    private static function validateFileSize($file)
75
    {
76 5
        $maxFileSizeBytes = (self::MAX_FILE_SIZE_MB * 1024 * 1024);
77 5
        if (filesize($file) > $maxFileSizeBytes) {
78 1
            throw new MaximumImageFileSizeExcededException(sprintf('Max file size is \'%d Mb\'', self::MAX_FILE_SIZE_MB));
79
        }
80 4
    }
81
82 4
    private static function validatedImageType(string $file)
83
    {
84 4
        $type = false;
85
86
        try {
87 4
            $type = exif_imagetype($file);
88 1
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
89
        }
90
91 4
        if ($type == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $type of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
92 1
            throw new FileIsNotAnImageException();
93
        }
94
95 3
        if (!array_key_exists($type, self::ALLOWED_FILE_TYPES)) {
96 1
            throw new ImageTypeNotAllowedException(
97 1
                sprintf('Allowed: %s', implode(', ', self::ALLOWED_FILE_TYPES))
98
            );
99
        }
100 2
    }
101
102 2
    private static function validateImageSize($file)
103
    {
104 2
        list($width, $height) = getimagesize($file);
105
106 2
        if ($width < self::MINIMAL_WIDTH or $height < self::MINIMAL_HEIGHT) {
1 ignored issue
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
107 1
            throw new ImageIsToSmallException(
108 1
                sprintf(
109 1
                    'Minimal image dimensions not met. Required: \'%dx%d\' Provided: \'%dx%d\'',
110 1
                    self::MINIMAL_HEIGHT,
111 1
                    self::MINIMAL_WIDTH,
112 1
                    $height,
113 1
                    $width
114
                )
115
            );
116
        }
117 1
    }
118
}
119