Passed
Branch ci (542cc6)
by Florian
02:33
created

File::variants()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
/**
4
 * Copyright (c) Florian Krämer (https://florian-kraemer.net)
5
 * Licensed under The MIT License
6
 * For full copyright and license information, please see the LICENSE.txt
7
 * Redistributions of files must retain the above copyright notice.
8
 *
9
 * @copyright Copyright (c) Florian Krämer (https://florian-kraemer.net)
10
 * @author    Florian Krämer
11
 * @link      https://github.com/Phauthentic
12
 * @license   https://opensource.org/licenses/MIT MIT License
13
 */
14
15
declare(strict_types=1);
16
17
namespace Phauthentic\Infrastructure\Storage;
18
19
use Phauthentic\Infrastructure\Storage\Exception\InvalidStreamResourceException;
20
use Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface;
21
use RuntimeException;
22
23
use function pathinfo;
24
25
/**
26
 * File
27
 */
28
class File implements FileInterface
29
{
30
    /**
31
     * @var int
32
     */
33
    protected int $id;
34
35
    /**
36
     * @var string
37
     */
38
    protected string $uuid;
39
40
    /**
41
     * @var string
42
     */
43
    protected string $filename;
44
45
    /**
46
     * @var int
47
     */
48
    protected int $filesize;
49
50
    /**
51
     * @var string
52
     */
53
    protected string $mimeType = '';
54
55
    /**
56
     * @var string|null
57
     */
58
    protected ?string $extension = null;
59
60
    /**
61
     * @var string
62
     */
63
    protected ?string $path = null;
64
65
    /**
66
     * @var string|null
67
     */
68
    protected ?string $collection = null;
69
70
    /**
71
     * @var string
72
     */
73
    protected string $storage = 'local';
74
75
    /**
76
     * @var array
77
     */
78
    protected array $metadata = [];
79
80
    /**
81
     * @var string|null
82
     */
83
    protected ?string $model = null;
84
85
    /**
86
     * @var string|null
87
     */
88
    protected ?string $modelId = null;
89
90
    /**
91
     * Source file to be stored in our system
92
     *
93
     * @var mixed
94
     */
95
    protected $sourceFile;
96
97
    /**
98
     * @var resource
99
     */
100
    protected $resource;
101
102
    /**
103
     * @var array
104
     */
105
    protected array $variants = [];
106
107
    /**
108
     * Creates a new instance
109
     *
110
     * @param string $filename Filename
111
     * @param int $filesize Filesize
112
     * @param string $mimeType Mime Type
113
     * @param string $storage Storage config name
114
     * @param string|null $collection Collection name
115
     * @param string|null $model Model name
116
     * @param string|null $modelId Model id
117
     * @param array $variants Variants
118
     * @param array $metadata Meta data
119
     * @param resource|null $resource
120
     * @return self
121
     */
122 7
    public static function create(
123
        string $filename,
124
        int $filesize,
125
        string $mimeType,
126
        string $storage,
127
        ?string $collection = null,
128
        ?string $model = null,
129
        ?string $modelId = null,
130
        array $metadata = [],
131
        array $variants = [],
132
        $resource = null
133
    ): self {
134 7
        $that = new self();
135
136 7
        $that->filename = $filename;
137 7
        $that->filesize = $filesize;
138 7
        $that->mimeType = $mimeType;
139 7
        $that->storage = $storage;
140 7
        $that->model = $model;
141 7
        $that->modelId = $modelId;
142 7
        $that->collection = $collection;
143 7
        $that->variants = $variants;
144 7
        $that->metadata = $metadata;
145
146 7
        if ($resource !== null) {
147
            $that = $that->withResource($resource);
148
        }
149
150 7
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
151 7
        $that->extension = empty($extension) ? null : (string)$extension;
152
153 7
        return $that;
154
    }
155
156
    /**
157
     * Storage name
158
     *
159
     * @return string
160
     */
161 1
    public function storage(): string
162
    {
163 1
        return $this->storage;
164
    }
165
166
    /**
167
     * UUID of the file
168
     *
169
     * @param string $uuid UUID string
170
     * @return self
171
     */
172 5
    public function withUuid(string $uuid): self
173
    {
174 5
        $that = clone $this;
175 5
        $that->uuid = $uuid;
176
177 5
        return $that;
178
    }
179
180
    /**
181
     * Stream resource that should be stored
182
     *
183
     * @return resource|null
184
     */
185 1
    public function resource()
186
    {
187 1
        return $this->resource;
188
    }
189
190
    /**
191
     * Same as withResource() but takes a file path
192
     *
193
     * @param string $file File
194
     * @return self
195
     */
196
    public function withFile(string $file): self
197
    {
198
        $result = fopen($file, 'rb');
199
        if ($result === false) {
200
            throw new RuntimeException(sprintf(
201
                'Failed to open file `%s for reading`',
202
                $file
203
            ));
204
        }
205
206
        return $this->withResource(fopen($file, 'rb'));
0 ignored issues
show
Bug introduced by
It seems like fopen($file, 'rb') can also be of type false; however, parameter $resource of Phauthentic\Infrastructu...ge\File::withResource() does only seem to accept 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

206
        return $this->withResource(/** @scrutinizer ignore-type */ fopen($file, 'rb'));
Loading history...
207
    }
208
209
    /**
210
     * @param mixed $resource
211
     */
212 6
    protected function assertStreamResource($resource): void
213
    {
214
        if (
215 6
            !is_resource($resource)
216 6
            || get_resource_type($resource) !== 'stream'
217
        ) {
218
            throw InvalidStreamResourceException::create();
219
        }
220 6
    }
221
222
    /**
223
     * Stream resource of the file to be stored
224
     *
225
     * @param resource  $resource
226
     * @return self
227
     */
228 6
    public function withResource($resource): self
229
    {
230 6
        $this->assertStreamResource($resource);
231
232 6
        $that = clone $this;
233 6
        $that->resource = $resource;
234
235 6
        return $that;
236
    }
237
238
    /**
239
     * Assign a model and model id to a file
240
     *
241
     * @param string $model Model
242
     * @param string|int $modelId Model ID, UUID string or integer
243
     * @return $this
244
     */
245 5
    public function belongsToModel(string $model, $modelId): self
246
    {
247 5
        $this->model = $model;
248 5
        $this->modelId = $modelId;
249
250 5
        return $this;
251
    }
252
253
    /**
254
     * Adds the file to a collection
255
     *
256
     * @param string $collection Collection
257
     * @return $this
258
     */
259 3
    public function addToCollection(string $collection): self
260
    {
261 3
        $this->collection = $collection;
262
263 3
        return $this;
264
    }
265
266
    /**
267
     * Sets the path, immutable
268
     *
269
     * @param string $path Path to the file
270
     * @return $this
271
     */
272
    public function withPath(string $path): self
273
    {
274
        $that = clone $this;
275
        $that->path = $path;
276
277
        return $that;
278
    }
279
280
    /**
281
     * Filename
282
     *
283
     * @param string $filename Filename
284
     * @return self
285
     */
286 2
    public function withFilename(string $filename): self
287
    {
288 2
        $that = clone $this;
289 2
        $that->filename = $filename;
290
291 2
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
292 2
        $that->extension = empty($extension) ? null : (string)$extension;
293
294 2
        return $that;
295
    }
296
297
    /**
298
     * The collections name this file belongs into
299
     *
300
     * @return string|null
301
     */
302 4
    public function collection(): ?string
303
    {
304 4
        return $this->collection;
305
    }
306
307
    /**
308
     * Model name
309
     *
310
     * @return string|null
311
     */
312 5
    public function model(): ?string
313
    {
314 5
        return $this->model;
315
    }
316
317
    /**
318
     * Model ID
319
     *
320
     * @return string|null
321
     */
322 4
    public function modelId(): ?string
323
    {
324 4
        return $this->modelId;
325
    }
326
327
    /**
328
     * Size of the file in bytes
329
     *
330
     * @return int
331
     */
332
    public function filesize(): int
333
    {
334
        return $this->filesize;
335
    }
336
337
    /**
338
     * Returns a human readable file size
339
     *
340
     * @return string
341
     */
342
    public function readableSize(): string
343
    {
344
        $i = floor(log($this->filesize, 1024));
345
        $round = (string)round($this->filesize / (1024 ** $i), [0, 0, 2, 2, 3][$i]);
346
347
        return $round . ['B','kB','MB','GB','TB'][$i];
348
    }
349
350
    /**
351
     * @return string|null
352
     */
353 4
    public function extension(): ?string
354
    {
355 4
        return $this->extension;
356
    }
357
358
    /**
359
     * @return string
360
     */
361 4
    public function mimeType(): string
362
    {
363 4
        return $this->mimeType;
364
    }
365
366
    /**
367
     * @return string
368
     */
369 4
    public function filename(): string
370
    {
371 4
        return $this->filename;
372
    }
373
374
    /**
375
     * @return string
376
     */
377 4
    public function uuid(): string
378
    {
379 4
        return $this->uuid;
380
    }
381
382
    /**
383
     * @return string
384
     */
385 3
    public function path(): string
386
    {
387 3
        if ($this->path === null) {
388 1
            throw new RuntimeException(
389 1
                'Path has not been set'
390
            );
391
        }
392
393 2
        return $this->path;
394
    }
395
396
    /**
397
     * Builds the path for this file
398
     *
399
     * @param \Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface $pathBuilder Path Builder
400
     * @return $this
401
     */
402 2
    public function buildPath(PathBuilderInterface $pathBuilder): self
403
    {
404 2
        $that = clone $this;
405 2
        $that->path = $pathBuilder->path($this);
406
407 2
        return $that;
408
    }
409
410
    /**
411
     * @param array $metadata Meta data
412
     * @return $this
413
     */
414 1
    public function withMetadata(array $metadata): self
415
    {
416 1
        $that = clone $this;
417 1
        $that->metadata = $metadata;
418
419 1
        return $that;
420
    }
421
422
    /**
423
     * @param string $name Name
424
     * @param mixed $data Data
425
     * @return $this
426
     */
427 2
    public function withMetadataKey(string $name, $data): self
428
    {
429 2
        $that = clone $this;
430 2
        $that->metadata[$name] = $data;
431
432 2
        return $that;
433
    }
434
435
    /**
436
     * @param string $name Name
437
     * @return $this
438
     */
439
    public function withoutMetadataKey(string $name): self
440
    {
441
        $that = clone $this;
442
        unset($that->metadata[$name]);
443
444
        return $that;
445
    }
446
447
    /**
448
     * @return $this
449
     */
450
    public function withoutMetadata(): self
451
    {
452
        $that = clone $this;
453
        $that->metadata = [];
454
455
        return $that;
456
    }
457
458
    /**
459
     * @return array
460
     */
461
    public function metadata(): array
462
    {
463
        return $this->metadata;
464
    }
465
466
    /**
467
     * @return bool
468
     */
469
    public function hasVariants(): bool
470
    {
471
        return !empty($this->variants);
472
    }
473
474
    /**
475
     * @param string $name Name
476
     * @return bool
477
     */
478
    public function hasVariant(string $name): bool
479
    {
480
        return isset($this->variants[$name]);
481
    }
482
483
    /**
484
     * @return array
485
     */
486 2
    public function variants(): array
487
    {
488 2
        return $this->variants;
489
    }
490
491
    /**
492
     * Returns a variant by name
493
     *
494
     * @param string $name Name
495
     * @return array
496
     */
497
    public function variant(string $name): array
498
    {
499
        if (!isset($this->variants[$name])) {
500
            throw new RuntimeException(
501
                'Manipulation does not exist'
502
            );
503
        }
504
505
        return $this->variants[$name];
506
    }
507
508
    /**
509
     * Adds a variant
510
     *
511
     * @param string $name Name
512
     * @param array $data Data
513
     * @return $this
514
     */
515
    public function withVariant(string $name, array $data): self
516
    {
517
        $that = clone $this;
518
        $that->variants[$name] = $data;
519
520
        return $that;
521
    }
522
523
    /**
524
     * Gets the paths for all variants
525
     *
526
     * @return array
527
     */
528
    public function variantPaths(): array
529
    {
530
        $paths = [];
531
        foreach ($this->variants as $variant => $data) {
532
            if (isset($data['path'])) {
533
                $paths[$variant] = $data['path'];
534
            }
535
        }
536
537
        return $paths;
538
    }
539
540
    /**
541
     * Sets many variants at once
542
     *
543
     * @param array $variants Variants
544
     * @param bool $merge Merge Variants, default is true
545
     * @return $this
546
     */
547 2
    public function withVariants(array $variants, bool $merge = true): self
548
    {
549 2
        $that = clone $this;
550 2
        $that->variants = array_merge_recursive(
551 2
            $merge ? $that->variants : [],
552
            $variants
553
        );
554
555 2
        return $that;
556
    }
557
558
    /**
559
     * @return array
560
     */
561
    public function toArray(): array
562
    {
563
        return [
564
            'uuid' => $this->uuid,
565
            'filename' => $this->filename,
566
            'filesize' => $this->filesize,
567
            'mimeType' => $this->mimeType,
568
            'extension' => $this->extension,
569
            'path' => $this->path,
570
            'model' => $this->model,
571
            'modelId' => $this->modelId,
572
            'collection' => $this->collection,
573
            'readableSize' => $this->readableSize(),
574
            'variants' => $this->variants,
575
            'metaData' => $this->metadata,
576
        ];
577
    }
578
579
    /**
580
     * @inheritDoc
581
     */
582
    public function jsonSerialize()
583
    {
584
        return $this->toArray();
585
    }
586
}
587