Passed
Push — main ( 42bd92...c698a6 )
by Yaroslav
02:35
created

AbstractImageManager::filesToDelete()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 4
rs 9.9332
1
<?php
2
3
namespace SimpleImageManager\Managers;
4
5
use Illuminate\Http\UploadedFile;
6
use Illuminate\Support\Facades\Storage;
7
use Illuminate\Support\Str;
8
use SimpleImageManager\Contracts\ImageManagerInterface;
9
use Spatie\Image\Image;
10
11
abstract class AbstractImageManager implements ImageManagerInterface
12
{
13
    /**
14
     * Use specific disk.
15
     *
16
     * @var string|null
17
     */
18
    public ?string $disk = null;
19
20
    /**
21
     * Clear empty directory after deletion files.
22
     * Warning: this function is memory and time-consuming when there can be too many files.
23
     *
24
     * @var bool
25
     */
26
    public bool $truncateDir = false;
27
28
    /**
29
     * Add prefix to files. Can be directory ot just filename prefix.
30
     *
31
     * @var string
32
     */
33
    public string $prefix = '';
34
35
    /**
36
     * Save original file.
37
     *
38
     * @var array|null
39
     */
40
    public ?array $original = null;
41
42
    /**
43
     * Formats configurations list for creation.
44
     *
45
     * @var array
46
     */
47
    public array $formats = [];
48
49
    /**
50
     * List of deleted configuration formats.
51
     * Useful if you deleted some configuration but still files exists for old created files
52
     * and you need do delete these formats on delete file.
53
     *
54
     * @var array
55
     */
56
    public array $deletedFormats = [];
57
58
    /**
59
     * Files extensions lists what should not be updated/cropped. Like svg or gif.
60
     *
61
     * @var array
62
     */
63
    public array $immutableExtensions = [];
64
65
66 18
    public function __construct(array $configs)
67
    {
68 18
        $this->setDisk($configs['disk'] ?? null);
69
70 17
        if (array_key_exists('original', $configs)) {
71 17
            $this->setOriginal($configs['original']);
72
        }
73
74 17
        if (array_key_exists('formats', $configs)) {
75 17
            $this->setFormats($configs['formats']);
76
        }
77
78 17
        if (array_key_exists('deletedFormats', $configs)) {
79 17
            $this->setDeletedFormats($configs['deletedFormats']);
80
        }
81
82 17
        if (array_key_exists('prefix', $configs)) {
83 6
            $this->setPrefix((string)$configs['prefix']);
84
        }
85
86 17
        if (array_key_exists('truncateDir', $configs)) {
87 17
            $this->truncateDir($configs['truncateDir']);
88
        }
89
90
        /** @deprecated */
91 17
        if (array_key_exists('immutable_extensions', $configs)) {
92
            $this->setImmutableExtensions($configs['immutable_extensions']);
93
        }
94
95 17
        if (array_key_exists('immutableExtensions', $configs)) {
96 17
            $this->setImmutableExtensions($configs['immutableExtensions']);
97
        }
98
    }
99
100
    /**
101
     * @param string|null $disk
102
     *
103
     * @return $this
104
     */
105 18
    public function setDisk(?string $disk = null): static
106
    {
107 18
        if (empty($disk) || !is_string($disk)) {
108 1
            throw new \InvalidArgumentException("Driver configuration has not key 'disk'");
109
        }
110
111 17
        $this->disk = $disk;
112
113 17
        return $this;
114
    }
115
116
    /**
117
     * @param array|null $original
118
     *
119
     * @return $this
120
     */
121 17
    public function setOriginal(?array $original = null): static
122
    {
123 17
        $this->original = $original;
124
125 17
        return $this;
126
    }
127
128
    /**
129
     * @param array $formats
130
     *
131
     * @return $this
132
     */
133 17
    public function setFormats(array $formats = []): static
134
    {
135 17
        $this->formats = $formats;
136
137 17
        return $this;
138
    }
139
140
    /**
141
     * @param array $formats
142
     *
143
     * @return $this
144
     */
145 17
    public function setDeletedFormats(array $formats = []): static
146
    {
147 17
        $this->deletedFormats = $formats;
148
149 17
        return $this;
150
    }
151
152
    /**
153
     * @param array $immutableExtensions
154
     *
155
     * @return $this
156
     */
157 17
    public function setImmutableExtensions(array $immutableExtensions = []): static
158
    {
159 17
        $this->immutableExtensions = $immutableExtensions;
160
161 17
        return $this;
162
    }
163
164
    /**
165
     * @param bool $truncateDir
166
     * @return $this
167
     */
168 17
    public function truncateDir(bool $truncateDir = true): static
169
    {
170 17
        $this->truncateDir = $truncateDir;
171
172 17
        return $this;
173
    }
174
175
    /**
176
     * @param ?string $prefix
177
     *
178
     * @return $this
179
     */
180 6
    public function setPrefix(?string $prefix = null): static
181
    {
182 6
        $this->prefix = (string)$prefix;
183
184 6
        return $this;
185
    }
186
187 9
    public function upload(UploadedFile $image, ?string $fileName = null, ?string $oldFile = null): string
188
    {
189 9
        if ($oldFile) {
190 1
            $this->delete($oldFile);
191
        }
192
193 9
        $newFileName = $this->makeFileName($fileName);
194 9
        if (Str::endsWith($newFileName, ".{$image->extension()}")) {
195
            $newFileName = Str::beforeLast($newFileName, ".{$image->extension()}");
196
        }
197
198 9
        $tmpFile = rtrim(dirname($newFileName), '/') . '/.tmp';
199 9
        $this->storage()->put($tmpFile, '');
200 9
        $this->storage()->delete($tmpFile);
201
202 9
        $newFileExt = '.' . $image->extension();
203
204 9
        if ($this->original) {
205 9
            $this->createOriginalFile($image, $newFileName, $newFileExt);
206
        }
207
208 9
        $this->createFormats($image, $newFileName, $newFileExt);
209
210 9
        return "{$newFileName}{$newFileExt}";
211
    }
212
213
    /**
214
     * @inheritDoc
215
     */
216 7
    public function delete(string $fileName): bool
217
    {
218 7
        $filesToDelete = $this->filesToDelete($fileName);
219
220 7
        if (empty($filesToDelete)) {
221 1
            return false;
222
        }
223
224 6
        $isDeleted = $this->storage()->delete($filesToDelete);
225
226 6
        $this->truncateDirectory($fileName);
227
228 6
        return $isDeleted;
229
    }
230
231
    /**
232
     * Get files list with all formats to delete.
233
     *
234
     * @param string $fileName
235
     * @return array
236
     */
237 7
    protected function filesToDelete(string $fileName): array
238
    {
239 7
        if (!$fileName) {
240 1
            return [];
241
        }
242
243 6
        $filesToDelete = [
244 6
            $fileName,
245 6
        ];
246
247 6
        [$name, $extension] = $this->explodeFilename($fileName);
248
249 6
        foreach (array_keys($this->formats) as $format) {
250 6
            $filesToDelete[] = "{$name}-{$format}.{$extension}";
251
        }
252
253 6
        foreach ($this->deletedFormats as $format) {
254 5
            $filesToDelete[] = "{$name}-{$format}.{$extension}";
255
        }
256
257 6
        return array_unique($filesToDelete);
258
    }
259
260
    /**
261
     * Clear empty directory if this is required.
262
     *
263
     * @param string $fileName
264
     * @return bool
265
     */
266 6
    protected function truncateDirectory(string $fileName): bool
267
    {
268 6
        if (!$this->truncateDir) {
269 2
            return false;
270
        }
271
272 4
        $directoryName = dirname($fileName);
273
274
        if (
275 4
            !$directoryName ||
276 4
            !empty($this->storage()->allFiles($directoryName))
277
        ) {
278 2
            return false;
279
        }
280
281 2
        return $this->storage()->deleteDirectory($directoryName);
282
    }
283
284
    /**
285
     * @inheritDoc
286
     */
287 1
    public function deleteSingle(string $fileName, ?string $format = null): bool
288
    {
289 1
        if (!$fileName) {
290 1
            return false;
291
        }
292 1
        if ($format) {
293 1
            [$name, $extension] = $this->explodeFilename($fileName);
294
295 1
            $fileName = "{$name}-{$format}.{$extension}";
296
        }
297
298
299 1
        return $this->storage()->delete($fileName);
300
    }
301
302
    /**
303
     * @inheritDoc
304
     */
305 10
    public function path(string $fileName, ?string $format = null): ?string
306
    {
307 10
        if (!$fileName) {
308 1
            return null;
309
        }
310 9
        if ($format) {
311 3
            [$name, $extension] = $this->explodeFilename($fileName);
312 3
            if (!in_array(".{$extension}", $this->immutableExtensions)) {
313 2
                $fileName = "{$name}-{$format}.{$extension}";
314
            }
315
        }
316
317 9
        return $this->storage()->path($fileName);
318
    }
319
320
    /**
321
     * @inheritDoc
322
     */
323 9
    public function url(string $fileName, ?string $format = null): ?string
324
    {
325 9
        if (!$fileName) {
326 1
            return null;
327
        }
328 8
        if ($format) {
329 2
            [$name, $extension] = $this->explodeFilename($fileName);
330 2
            if (!in_array(".{$extension}", $this->immutableExtensions)) {
331 1
                $fileName = "{$name}-{$format}.{$extension}";
332
            }
333
        }
334
335 8
        return $this->storage()->url($fileName);
336
    }
337
338
    /**
339
     * @inheritDoc
340
     */
341 1
    public function srcsetMap(): array
342
    {
343 1
        $map = [];
344
345 1
        if (is_array($this->original) &&
346 1
            !empty($this->original['srcset'])) {
347 1
            $map[''] = $this->original['srcset'];
348
        }
349
350 1
        foreach ($this->formats as $format => $configuration) {
351 1
            if (!empty($configuration['srcset'])) {
352 1
                $map[$format] = $configuration['srcset'];
353
            }
354
        }
355
356 1
        uasort($map, function ($a, $b) {
357 1
            return (int)$b - (int)$a;
358 1
        });
359
360 1
        return $map;
361
    }
362
363 7
    protected function explodeFilename(string $fileName)
364
    {
365 7
        $extension = pathinfo($fileName, PATHINFO_EXTENSION);
366
367 7
        $name = Str::beforeLast($fileName, ".{$extension}");
368
369 7
        return [$name, $extension];
370
    }
371
372
    /**
373
     * @return \Illuminate\Contracts\Filesystem\Filesystem
374
     */
375 12
    public function storage(): \Illuminate\Contracts\Filesystem\Filesystem
376
    {
377 12
        return Storage::disk($this->disk);
378
    }
379
380
    /**
381
     * @param string|null $fileName
382
     *
383
     * @return string
384
     */
385 9
    protected function makeFileName(?string $fileName = null): string
386
    {
387 9
        if (!$fileName) {
388 2
            return $this->prefix . Str::random(30);
389
        }
390
391 7
        return $this->prefix . $fileName;
392
    }
393
394 9
    protected function createOriginalFile(UploadedFile $image, string $newFileName, string $newFileExt)
395
    {
396 9
        $path = "{$newFileName}{$newFileExt}";
397 9
        if (!in_array($newFileExt, $this->immutableExtensions)) {
398 8
            $builder = Image::load($image->path());
399 8
            if (is_array($this->original) &&
400 8
                !empty($this->original['methods'])
401
            ) {
402 8
                foreach ($this->original['methods'] as $method => $attrs) {
403 8
                    call_user_func_array([$builder, $method], $attrs);
404
                }
405
            }
406
407 8
            $builder->save($this->storage()->path($path));
408
        } else {
409 1
            $this->storage()->put($path, $image->getContent());
410
        }
411
    }
412
413 9
    protected function createFormats(UploadedFile $image, string $newFileName, string $newFileExt)
414
    {
415 9
        if (!in_array($newFileExt, $this->immutableExtensions)) {
416 8
            foreach ($this->formats as $format => $configuration) {
417 8
                $path = "{$newFileName}-{$format}{$newFileExt}";
418
419 8
                $builder = Image::load($image->path());
420 8
                if (!empty($configuration['methods']) && is_array($configuration['methods'])) {
421 8
                    foreach ($configuration['methods'] as $method => $attrs) {
422 8
                        call_user_func_array([$builder, $method], $attrs);
423
                    }
424
                }
425 8
                $builder->save($this->storage()->path($path));
426
            }
427
        }
428
    }
429
}
430