ImageValidator   B
last analyzed

Complexity

Total Complexity 46

Size/Duplication

Total Lines 196
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 3
Bugs 1 Features 1
Metric Value
eloc 110
c 3
b 1
f 1
dl 0
loc 196
ccs 0
cts 115
cp 0
rs 8.72
wmc 46

4 Methods

Rating   Name   Duplication   Size   Complexity  
C contraintNeedsValidation() 0 15 13
A validateCorruptedFile() 0 21 4
B validateOrientation() 0 23 7
F doValidation() 0 114 22

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace ByTIC\MediaLibrary\Validation\Validators;
4
5
use ByTIC\MediaLibrary\Validation\Constraints\ImageConstraint;
6
use Nip\Logger\Exception;
7
8
/**
9
 * Class ImageValidator.
10
 */
11
class ImageValidator extends AbstractValidator
12
{
13
    /**
14
     * @return bool
15
     */
16
    protected function contraintNeedsValidation(): bool
17
    {
18
        $constraint = $this->getConstraint();
19
20
        if (null === $constraint->minWidth && null === $constraint->maxWidth
21
            && null === $constraint->minHeight && null === $constraint->maxHeight
22
            && null === $constraint->minPixels && null === $constraint->maxPixels
23
            && null === $constraint->minRatio && null === $constraint->maxRatio
24
            && $constraint->allowSquare && $constraint->allowLandscape && $constraint->allowPortrait
25
            && !$constraint->detectCorrupted
26
        ) {
27
            return false;
28
        }
29
30
        return true;
31
    }
32
33
    /**
34
     * @throws Exception
35
     */
36
    protected function doValidation()
37
    {
38
        $size = @getimagesize($this->getValue());
39
        $constraint = $this->getConstraint();
40
41
        if (empty($size) || ($size[0] === 0) || ($size[1] === 0)) {
42
            $this->addViolation($constraint, ImageConstraint::SIZE_NOT_DETECTED_ERROR, []);
43
44
            return;
45
        }
46
47
        $width = $size[0];
48
        $height = $size[1];
49
50
        if ($constraint->minWidth) {
51
            if (!ctype_digit((string) $constraint->minWidth)) {
52
                throw new Exception(sprintf(
53
                    '"%s" is not a valid minimum width',
54
                    $constraint->minWidth
55
                ));
56
            }
57
            if ($width < $constraint->minWidth) {
58
                $this->addViolation(
59
                    $constraint,
60
                    ImageConstraint::TOO_NARROW_ERROR,
61
                    ['width' => $width, 'min_width' => $constraint->minWidth]
62
                );
63
64
                return;
65
            }
66
        }
67
68
        if ($constraint->maxWidth) {
69
            if (!ctype_digit((string) $constraint->maxWidth)) {
70
                throw new Exception(sprintf(
71
                    '"%s" is not a valid maximum width',
72
                    $constraint->maxWidth
73
                ));
74
            }
75
            if ($width > $constraint->maxWidth) {
76
                $this->addViolation(
77
                    $constraint,
78
                    ImageConstraint::TOO_WIDE_ERROR,
79
                    ['width' => $width, 'max_width' => $constraint->maxWidth]
80
                );
81
82
                return;
83
            }
84
        }
85
        if ($constraint->minHeight) {
86
            if (!ctype_digit((string) $constraint->minHeight)) {
87
                throw new Exception(sprintf(
88
                    '"%s" is not a valid minimum height',
89
                    $constraint->minHeight
90
                ));
91
            }
92
            if ($height < $constraint->minHeight) {
93
                $this->addViolation(
94
                    $constraint,
95
                    ImageConstraint::TOO_LOW_ERROR,
96
                    ['height' => $height, 'min_height' => $constraint->minHeight]
97
                );
98
99
                return;
100
            }
101
        }
102
        if ($constraint->maxHeight) {
103
            if (!ctype_digit((string) $constraint->maxHeight)) {
104
                throw new Exception(sprintf(
105
                    '"%s" is not a valid maximum height',
106
                    $constraint->maxHeight
107
                ));
108
            }
109
            if ($height > $constraint->maxHeight) {
110
                $this->addViolation(
111
                    $constraint,
112
                    ImageConstraint::TOO_HIGH_ERROR,
113
                    ['height' => $height, 'max_height' => $constraint->maxHeight]
114
                );
115
            }
116
        }
117
        $ratio = round($width / $height, 2);
118
        if (null !== $constraint->minRatio) {
119
            if (!is_numeric((string) $constraint->minRatio)) {
120
                throw new Exception(sprintf(
121
                    '"%s" is not a valid minimum ratio',
122
                    $constraint->minRatio
123
                ));
124
            }
125
            if ($ratio < $constraint->minRatio) {
126
                $this->addViolation(
127
                    $constraint,
128
                    ImageConstraint::RATIO_TOO_SMALL_ERROR,
129
                    ['ratio' => $ratio, 'minRatio' => $constraint->minRatio]
130
                );
131
            }
132
        }
133
        if (null !== $constraint->maxRatio) {
134
            if (!is_numeric((string) $constraint->maxRatio)) {
135
                throw new Exception(sprintf(
136
                    '"%s" is not a valid maximum ratio',
137
                    $constraint->maxRatio
138
                ));
139
            }
140
            if ($ratio > $constraint->maxRatio) {
141
                $this->addViolation(
142
                    $constraint,
143
                    ImageConstraint::RATIO_TOO_BIG_ERROR,
144
                    ['ratio' => $ratio, 'max_ratio' => $constraint->maxRatio]
145
                );
146
            }
147
        }
148
149
        $this->validateCorruptedFile();
150
    }
151
152
    /**
153
     * @throws Exception
154
     *
155
     * @return bool
156
     */
157
    protected function validateCorruptedFile()
158
    {
159
        $constraint = $this->getConstraint();
160
        $value = $this->getValue();
161
162
        if ($constraint->detectCorrupted) {
163
            if (!function_exists('imagecreatefromstring')) {
164
                throw new Exception('Corrupted images detection requires installed and enabled GD extension');
165
            }
166
            $resource = @imagecreatefromstring(file_get_contents($value));
167
            if (false === $resource) {
168
                $this->addViolation(
169
                    $constraint,
170
                    ImageConstraint::CORRUPTED_IMAGE_ERROR,
171
                    []
172
                );
173
            }
174
            imagedestroy($resource);
0 ignored issues
show
Bug introduced by
It seems like $resource can also be of type false; however, parameter $image of imagedestroy() does only seem to accept GdImage|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

174
            imagedestroy(/** @scrutinizer ignore-type */ $resource);
Loading history...
175
        }
176
177
        return true;
178
    }
179
180
    /**
181
     * @param $width
182
     * @param $height
183
     */
184
    protected function validateOrientation($width, $height)
185
    {
186
        $constraint = $this->getConstraint();
187
188
        if (!$constraint->allowSquare && $width == $height) {
189
            $this->addViolation(
190
                $constraint,
191
                ImageConstraint::SQUARE_NOT_ALLOWED_ERROR,
192
                ['width' => $width, 'height' => $height]
193
            );
194
        }
195
        if (!$constraint->allowLandscape && $width > $height) {
196
            $this->addViolation(
197
                $constraint,
198
                ImageConstraint::LANDSCAPE_NOT_ALLOWED_ERROR,
199
                ['width' => $width, 'height' => $height]
200
            );
201
        }
202
        if (!$constraint->allowPortrait && $width < $height) {
203
            $this->addViolation(
204
                $constraint,
205
                ImageConstraint::PORTRAIT_NOT_ALLOWED_ERROR,
206
                ['width' => $width, 'height' => $height]
207
            );
208
        }
209
    }
210
}
211