Completed
Push — master ( 2ef199...b6cd70 )
by Yaro
03:16
created

Image::storeFile()   B

Complexity

Conditions 10
Paths 96

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 0
cts 26
cp 0
rs 7.6666
c 0
b 0
f 0
cc 10
nc 96
nop 8
crap 110

How to fix   Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Yaro\Jarboe\Table\Fields;
4
5
use Illuminate\Http\Request;
6
use Illuminate\Http\UploadedFile;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Str;
9
use Yaro\Jarboe\Table\Fields\Traits\Filename;
10
use Yaro\Jarboe\Table\Fields\Traits\Nullable;
11
use Yaro\Jarboe\Table\Fields\Traits\Placeholder;
12
use Yaro\Jarboe\Table\Fields\Traits\Storage;
13
use Illuminate\Support\Facades\Storage as IlluminateStorage;
14
use Intervention\Image\ImageManagerStatic as InterventionImage;
15
16
class Image extends AbstractField
17
{
18
    use Storage;
19
    use Placeholder;
20
    use Nullable;
21
    use Filename;
22
23
    protected $encode = false;
24
    protected $crop = false;
25
    protected $shouldAutoOpen = null;
26
    protected $ratio = [
27
        'width'  => false,
28
        'height' => false,
29
    ];
30
    private $originalImageData;
31
    private $defaultImageDataStructure =  [
32
        'storage' => [
33
            'disk' => null,
34
            'is_encoded' => false,
35
        ],
36
        'crop' => [
37
            'width' => null,
38
            'height' => null,
39
            'x' => null,
40
            'y' => null,
41
            'rotate' => null,
42
            'rotate_background' => null,
43
        ],
44
        'sources' => [
45
            'original' => null,
46
            'cropped' => null,
47
        ],
48
    ];
49
50
    public function __construct()
51
    {
52
        $this->disk = config('filesystems.default');
53
    }
54
55
    public function isEncode()
56
    {
57
        return $this->encode;
58
    }
59
60
    /**
61
     * Encode image as data-url.
62
     *
63
     * @param bool $encode
64
     * @return $this
65
     */
66
    public function encode(bool $encode = true)
67
    {
68
        $this->encode = $encode;
69
70
        return $this;
71
    }
72
73
    protected function storeFile($filepath, $filename, $width = null, $height = null, $x = null, $y = null, $rotate = null, $rotateBackgroundColor = null)
74
    {
75
        $image = InterventionImage::make($filepath);
76
        $rotateBackgroundColor = $rotateBackgroundColor ?: 'rgba(255, 255, 255, 0)';
77
78
        if ($rotate) {
79
            // because js plugin and php library rotating in different directions.
80
            $angle = $rotate * -1;
81
            $image->rotate($angle, $rotateBackgroundColor);
82
        }
83
        $hasCropProperties = !is_null($width) && !is_null($height) && !is_null($x) && !is_null($y);
84
        if ($this->isCrop() && $hasCropProperties) {
85
            $image->crop(round($width), round($height), round($x), round($y));
86
        }
87
88
        if ($this->isEncode()) {
89
            return (string) $image->encode('data-url');
90
        }
91
92
        $format = '';
93
        if ($this->isTransparentColor($rotateBackgroundColor)) {
94
            $format = 'png';
95
        }
96
        $path = trim($this->getPath() .'/'. $filename, '/');
97
        IlluminateStorage::disk($this->getDisk())->put(
98
            $path,
99
            (string) $image->encode($format)
100
        );
101
102
        return $path;
103
    }
104
105
    public function value(Request $request)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
106
    {
107
        $images = $request->all($this->name());
108
        $images = $images[$this->name()];
109
110
        $data = [];
111
        foreach ($images as $image) {
112
            $imageData = $this->defaultImageDataStructure;
113
            $imageData['storage'] = [
114
                'disk' => $this->getDisk(),
115
                'is_encoded' => $this->isEncode(),
116
            ];
117
118
            $imageData['crop'] = $image['crop'];
119
            $imageData['sources'] = $image['sources'];
120
            /** @var UploadedFile|null $file */
121
            $file = $image['file'] ?? null;
122
            if ($file) {
123
                $imageData['sources']['original'] = $this->storeFile(
124
                    $file->getRealPath(),
125
                    $this->generateFilename(
126
                        $request,
127
                        $file,
128
                        $image,
129
                        $this->isTransparentColor((string) $image['crop']['rotate_background']),
130
                        true
131
                    )
132
                );
133
                $imageData['sources']['cropped'] = $this->storeFile(
134
                    $file->getRealPath(),
135
                    $this->generateFilename(
136
                        $request,
137
                        $file,
138
                        $image,
139
                        $this->isTransparentColor((string) $image['crop']['rotate_background']),
140
                        false
141
                    ),
142
                    $image['crop']['width'],
143
                    $image['crop']['height'],
144
                    $image['crop']['x'],
145
                    $image['crop']['y'],
146
                    $image['crop']['rotate'],
147
                    $image['crop']['rotate_background']
148
                );
149
            } elseif (!$image['sources']['original']) {
150
                continue;
151
            } elseif ($this->isCrop() && !$image['sources']['cropped']) {
152
                $imageData['sources']['cropped'] = $this->storeFile(
153
                    IlluminateStorage::disk($this->getDisk())->path($imageData['sources']['original']),
154
                    $this->generateFilename(
155
                        $request,
156
                        null,
157
                        $image,
158
                        $this->isTransparentColor((string) $image['crop']['rotate_background']),
159
                        false
160
                    ),
161
                    $image['crop']['width'],
162
                    $image['crop']['height'],
163
                    $image['crop']['x'],
164
                    $image['crop']['y'],
165
                    $image['crop']['rotate'],
166
                    $image['crop']['rotate_background']
167
                );
168
            }
169
170
            $data[] = $imageData;
171
        }
172
173
        if (!$this->isMultiple()) {
174
            $data = array_pop($data);
175
        }
176
177
        $data = $data ?: [];
178
        if ($this->isNullable()) {
179
            $data = $data ?: null;
180
        }
181
182
        return $data;
183
    }
184
185
    public function crop(bool $enabled = true)
186
    {
187
        $this->crop = $enabled;
188
189
        return $this;
190
    }
191
192
    public function ratio(int $width, int $height)
193
    {
194
        $this->ratio['width'] = $width;
195
        $this->ratio['height'] = $height;
196
197
        return $this;
198
    }
199
200
    public function isCrop()
201
    {
202
        return $this->crop;
203
    }
204
205 View Code Duplication
    public function getRatio(string $type)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
206
    {
207
        $type = strtolower($type);
208
209
        switch ($type) {
210
            case 'width':
211
            case 'height':
212
                return $this->ratio[$type];
213
            default:
214
                return false;
215
        }
216
    }
217
218
    public function getListView($model)
219
    {
220
        return view('jarboe::crud.fields.image.list', [
221
            'model' => $model,
222
            'field' => $this,
223
        ]);
224
    }
225
226
    public function getEditFormView($model)
227
    {
228
        $template = $this->isReadonly() ? 'readonly' : 'edit';
229
230
        return view('jarboe::crud.fields.image.'. $template, [
231
            'model' => $model,
232
            'field' => $this,
233
        ]);
234
    }
235
236
    public function getCreateFormView()
237
    {
238
        return view('jarboe::crud.fields.image.create', [
239
            'model' => null,
240
            'field' => $this,
241
        ]);
242
    }
243
244
    public function getImage($data = []): \Yaro\Jarboe\Pack\Image
245
    {
246
        return new \Yaro\Jarboe\Pack\Image($data);
247
    }
248
249
    private function isTransparentColor(string $rgbaColor)
250
    {
251
        $segmentsString = preg_replace('~rgba\(|\)~', '', $rgbaColor);
252
        $segments = explode(',', $segmentsString);
253
254
        $opacity = $segments[3] ?? 0;
255
256
        return $opacity < 1;
257
    }
258
259
    /**
260
     * @param Request $request
261
     * @param UploadedFile|null $file
262
     * @param array $imageData
263
     * @param bool $hasTransparentColor
264
     * @param bool $isOriginalImage
265
     * @return string
266
     */
267
    private function generateFilename(Request $request, UploadedFile $file = null, array $imageData, bool $hasTransparentColor, bool $isOriginalImage): string
268
    {
269
        $isRecropFromOriginal = !$file && !$isOriginalImage;
270
        $extension = $isRecropFromOriginal ? pathinfo($imageData['sources']['original'], PATHINFO_EXTENSION) : $file->extension();
0 ignored issues
show
Bug introduced by
It seems like $file is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
271
        $filename = Str::random(40) .'.'. $extension;
272
273
        $closure = $this->filenameClosure;
274
        if (is_callable($closure)) {
275
            $filename = $closure($file, $request, $imageData, $isOriginalImage);
276
        }
277
278
        if ($hasTransparentColor) {
279
            $regexp = '~'. preg_quote(pathinfo($filename, PATHINFO_EXTENSION)) .'$~';
280
            $filename = preg_replace($regexp, 'png', $filename);
281
        }
282
283
        return (string) $filename;
284
    }
285
286
    public function getImagesPack($model): array
287
    {
288
        $defaultImage = $this->getImage();
289
        if (!$model) {
290
            return [$defaultImage];
291
        }
292
293
        $imagesData = $this->getAttribute($model);
294
        if (!is_array($imagesData)) {
295
            $imagesData = [];
296
        }
297
298
        if (!$this->isMultiple()) {
299
            $imagesData = [$imagesData];
300
        }
301
302
303
        $pack = [];
304
        foreach ($imagesData as $imageData) {
305
            $pack[] = $this->getImage($imageData);
306
        }
307
308
        return $pack ?: [$defaultImage];
309
    }
310
311
    public function autoOpen(bool $shouldAutoOpen = true)
312
    {
313
        $this->shouldAutoOpen = $shouldAutoOpen;
314
315
        return $this;
316
    }
317
318
    public function shouldAutoOpenModal(): bool
319
    {
320
        if (!is_null($this->shouldAutoOpen)) {
321
            return $this->shouldAutoOpen;
322
        }
323
324
        return $this->isCrop();
325
    }
326
}
327