• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

plank / laravel-mediable / 8585433686

07 Apr 2024 02:04AM UTC coverage: 95.282% (-0.5%) from 95.789%
8585433686

push

github

web-flow
Merge pull request #343 from plank/v6

V6

338 of 375 new or added lines in 30 files covered. (90.13%)

1 existing line in 1 file now uncovered.

1434 of 1505 relevant lines covered (95.28%)

117.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.4
/src/ImageManipulation.php
1
<?php
2

3
namespace Plank\Mediable;
4

5
use Plank\Mediable\Exceptions\MediaUpload\ConfigurationException;
6
use Plank\Mediable\Helpers\File;
7
use Spatie\ImageOptimizer\Optimizer;
8
use Spatie\ImageOptimizer\OptimizerChain;
9

10
class ImageManipulation
11
{
12
    public const FORMAT_JPG = 'jpg';
13
    public const FORMAT_PNG = 'png';
14
    public const FORMAT_GIF = 'gif';
15
    public const FORMAT_TIFF = 'tif';
16
    public const FORMAT_BMP = 'bmp';
17
    public const FORMAT_WEBP = 'webp';
18

19
    public const VALID_IMAGE_FORMATS = [
20
        self::FORMAT_JPG,
21
        self::FORMAT_PNG,
22
        self::FORMAT_GIF,
23
        self::FORMAT_TIFF,
24
        self::FORMAT_BMP
25
    ];
26

27
    public const MIME_TYPE_MAP = [
28
        self::FORMAT_JPG => 'image/jpeg',
29
        self::FORMAT_PNG => 'image/png',
30
        self::FORMAT_GIF => 'image/gif',
31
        self::FORMAT_TIFF => 'image/tiff',
32
        self::FORMAT_BMP => 'image/bmp',
33
        self::FORMAT_WEBP => 'image/webp'
34
    ];
35

36
    public const ON_DUPLICATE_INCREMENT = 'increment';
37
    public const ON_DUPLICATE_ERROR = 'error';
38

39
    /** @var callable */
40
    private $callback;
41

42
    private ?string $outputFormat = null;
43

44
    private int $outputQuality = 90;
45

46
    private ?string $disk = null;
47

48
    private ?string $directory = null;
49

50
    private ?string $filename = null;
51

52
    private ?string $hashFilenameAlgo = null;
53

54
    private string $onDuplicateBehaviour = self::ON_DUPLICATE_INCREMENT;
55

56
    /** @var string|null */
57
    private ?string $visibility = null;
58

59
    /** @var callable|null */
60
    private $beforeSave;
61

62
    private bool $shouldOptimize;
63

64
    /** @var array<class-string<Optimizer>,string[]> */
65
    private array $optimizers;
66

67
    public function __construct(callable $callback)
68
    {
69
        $this->callback = $callback;
222✔
70
        $this->shouldOptimize = config('mediable.image_optimization.enabled', true);
222✔
71
        $this->setOptimizers(config('mediable.image_optimization.optimizers', []));
222✔
72
    }
73

74
    public static function make(callable $callback): self
75
    {
76
        return new self($callback);
156✔
77
    }
78

79
    /**
80
     * @return callable
81
     */
82
    public function getCallback(): callable
83
    {
84
        return $this->callback;
144✔
85
    }
86

87
    /**
88
     * @return int
89
     */
90
    public function getOutputQuality(): int
91
    {
92
        return $this->outputQuality;
144✔
93
    }
94

95
    /**
96
     * @param int $outputQuality
97
     * @return $this
98
     */
99
    public function setOutputQuality(int $outputQuality): self
100
    {
101
        $this->outputQuality = min(100, max(0, $outputQuality));
24✔
102

103
        return $this;
24✔
104
    }
105

106
    /**
107
     * @return string|null
108
     */
109
    public function getOutputFormat(): ?string
110
    {
111
        return $this->outputFormat;
150✔
112
    }
113

114
    /**
115
     * @param string|null $outputFormat
116
     * @return $this
117
     */
118
    public function setOutputFormat(?string $outputFormat): self
119
    {
120
        $this->outputFormat = $outputFormat;
36✔
121

122
        return $this;
36✔
123
    }
124

125
    /**
126
     * @return $this
127
     */
128
    public function outputJpegFormat(): self
129
    {
130
        $this->setOutputFormat(self::FORMAT_JPG);
12✔
131

132
        return $this;
12✔
133
    }
134

135
    /**
136
     * @return $this
137
     */
138
    public function outputPngFormat(): self
139
    {
140
        $this->setOutputFormat(self::FORMAT_PNG);
12✔
141

142
        return $this;
12✔
143
    }
144

145
    /**
146
     * @return $this
147
     */
148
    public function outputGifFormat(): self
149
    {
150
        $this->setOutputFormat(self::FORMAT_GIF);
6✔
151

152
        return $this;
6✔
153
    }
154

155
    /**
156
     * @return $this
157
     */
158
    public function outputTiffFormat(): self
159
    {
160
        $this->setOutputFormat(self::FORMAT_TIFF);
6✔
161

162
        return $this;
6✔
163
    }
164

165
    /**
166
     * @return $this
167
     */
168
    public function outputBmpFormat(): self
169
    {
170
        $this->setOutputFormat(self::FORMAT_BMP);
6✔
171

172
        return $this;
6✔
173
    }
174

175
    /**
176
     * @return $this
177
     */
178
    public function outputWebpFormat(): self
179
    {
180
        $this->setOutputFormat(self::FORMAT_WEBP);
6✔
181

182
        return $this;
6✔
183
    }
184

185
    /**
186
     * @return callable
187
     */
188
    public function getBeforeSave(): ?callable
189
    {
190
        return $this->beforeSave;
132✔
191
    }
192

193
    /**
194
     * Set the filesystem disk and relative directory where the file will be saved.
195
     *
196
     * @param  string $disk
197
     * @param  string $directory
198
     *
199
     * @return $this
200
     */
201
    public function toDestination(string $disk, string $directory): self
202
    {
203
        return $this->toDisk($disk)->toDirectory($directory);
18✔
204
    }
205

206
    /**
207
     * Set the filesystem disk on which the file will be saved.
208
     *
209
     * @param string $disk
210
     *
211
     * @return $this
212
     */
213
    public function toDisk(string $disk): self
214
    {
215
        if (!array_key_exists($disk, config('filesystems.disks', []))) {
72✔
216
            throw ConfigurationException::diskNotFound($disk);
×
217
        }
218
        $this->disk = $disk;
72✔
219

220
        return $this;
72✔
221
    }
222

223
    /**
224
     * @return string|null
225
     */
226
    public function getDisk(): ?string
227
    {
228
        return $this->disk;
138✔
229
    }
230

231
    /**
232
     * Set the directory relative to the filesystem disk at which the file will be saved.
233
     * @param string $directory
234
     * @return $this
235
     */
236
    public function toDirectory(string $directory): self
237
    {
238
        $this->directory = File::sanitizePath($directory);
24✔
239

240
        return $this;
24✔
241
    }
242

243
    /**
244
     * @return string|null
245
     */
246
    public function getDirectory(): ?string
247
    {
248
        return $this->directory;
138✔
249
    }
250

251
    /**
252
     * Specify the filename to copy to the file to.
253
     * @param string $filename
254
     * @return $this
255
     */
256
    public function useFilename(string $filename): self
257
    {
258
        $this->filename = File::sanitizeFilename($filename);
12✔
259
        $this->hashFilenameAlgo = null;
12✔
260

261
        return $this;
12✔
262
    }
263

264
    /**
265
     * Indicates to the uploader to generate a filename using the file's MD5 hash.
266
     * @return $this
267
     */
268
    public function useHashForFilename(string $algo = 'md5'): self
269
    {
270
        $this->hashFilenameAlgo = $algo;
12✔
271
        $this->filename = null;
12✔
272

273
        return $this;
12✔
274
    }
275

276
    /**
277
     * Restore the default behaviour of using the source file's filename.
278
     * @return $this
279
     */
280
    public function useOriginalFilename(): self
281
    {
282
        $this->filename = null;
6✔
283
        $this->hashFilenameAlgo = null;
6✔
284

285
        return $this;
6✔
286
    }
287

288
    public function getFilename(): ?string
289
    {
290
        return $this->filename;
138✔
291
    }
292

293
    public function isUsingHashForFilename(): bool
294
    {
295
        return $this->hashFilenameAlgo !== null;
132✔
296
    }
297

298
    public function getHashFilenameAlgo(): ?string
299
    {
300
        return $this->hashFilenameAlgo;
12✔
301
    }
302

303
    /**
304
     * @return $this
305
     */
306
    public function onDuplicateIncrement(): self
307
    {
308
        $this->onDuplicateBehaviour = self::ON_DUPLICATE_INCREMENT;
18✔
309
        return $this;
18✔
310
    }
311

312
    /**
313
     * @return $this
314
     */
315
    public function onDuplicateError(): self
316
    {
317
        $this->onDuplicateBehaviour = self::ON_DUPLICATE_ERROR;
18✔
318
        return $this;
18✔
319
    }
320

321
    /**
322
     * @return string
323
     */
324
    public function getOnDuplicateBehaviour(): string
325
    {
326
        return $this->onDuplicateBehaviour;
30✔
327
    }
328

329
    public function makePrivate(): self
330
    {
331
        $this->visibility = 'private';
6✔
332
        return $this;
6✔
333
    }
334

335
    public function makePublic(): self
336
    {
337
        $this->visibility = 'public';
6✔
338
        return $this;
6✔
339
    }
340

341
    public function matchOriginalVisibility(): self
342
    {
343
        $this->visibility = 'match';
6✔
344
        return $this;
6✔
345
    }
346

347
    public function setVisibility(?string $visibility): self
348
    {
349
        $this->visibility = $visibility;
54✔
350
        return $this;
54✔
351
    }
352

353
    public function getVisibility(): ?string
354
    {
355
        return $this->visibility;
126✔
356
    }
357

358
    /**
359
     * @param callable $beforeSave
360
     * @return $this
361
     */
362
    public function beforeSave(callable $beforeSave): self
363
    {
364
        $this->beforeSave = $beforeSave;
24✔
365

366
        return $this;
24✔
367
    }
368

369
    /**
370
     * Disable image optimization.
371
     * @return $this
372
     */
373
    public function noOptimization(): self
374
    {
375
        $this->shouldOptimize = false;
6✔
376

377
        return $this;
6✔
378
    }
379

380
    /**
381
     * Enable image optimization.
382
     * @param array<class-string<Optimizer>,string[]> $customOptimizers Override default optimizers.
383
     *     The array keys should be the fully qualified class names of the optimizers to use.
384
     *     The array values should be arrays of command line arguments to pass to the optimizer.
385
     *     DO NOT PASS UNTRUSTED USER INPUT AS COMMAND LINE ARGUMENTS
386
     * @return $this
387
     * @throws ConfigurationException
388
     */
389
    public function optimize(?array $customOptimizers = null): self
390
    {
391
        if ($customOptimizers !== null) {
12✔
392
            $this->setOptimizers($customOptimizers);
12✔
393
        }
394
        $this->shouldOptimize = true;
12✔
395

396
        return $this;
12✔
397
    }
398

399
    public function shouldOptimize(): bool
400
    {
401
        return $this->shouldOptimize && !empty($this->optimizers);
144✔
402
    }
403

404
    public function getOptimizerChain(): OptimizerChain
405
    {
406
        $chain = new OptimizerChain();
12✔
407
        foreach ($this->optimizers as $optimizerClass => $args) {
12✔
408
            $optimizer = new $optimizerClass($args);
12✔
409
            $chain->addOptimizer($optimizer);
12✔
410
        }
411
        return $chain;
12✔
412
    }
413

414
    private function setOptimizers(array $customOptimizers): void
415
    {
416
        foreach ($customOptimizers as $optimizerClass => $args) {
222✔
417
            if (!is_a($optimizerClass, Optimizer::class, true)) {
222✔
NEW
418
                throw ConfigurationException::invalidOptimizer($optimizerClass);
×
419
            }
420
        }
421
        $this->optimizers = $customOptimizers;
222✔
422
    }
423
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc