Passed
Branch ci (cf247c)
by Florian
02:24
created

File::jsonSerialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
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 Phauthentic\Infrastructure\Storage\Processor\Exception\VariantException;
22
use RuntimeException;
23
24
/**
25
 * File
26
 */
27
class File implements FileInterface
28
{
29
    /**
30
     * @var int
31
     */
32
    protected int $id;
33
34
    /**
35
     * @var string
36
     */
37
    protected string $uuid;
38
39
    /**
40
     * @var string
41
     */
42
    protected string $filename;
43
44
    /**
45
     * @var int
46
     */
47
    protected int $filesize;
48
49
    /**
50
     * @var string
51
     */
52
    protected string $mimeType = '';
53
54
    /**
55
     * @var string|null
56
     */
57
    protected ?string $extension = null;
58
59
    /**
60
     * @var string
61
     */
62
    protected ?string $path = null;
63
64
    /**
65
     * @var string|null
66
     */
67
    protected ?string $collection = null;
68
69
    /**
70
     * @var string
71
     */
72
    protected string $storage = 'local';
73
74
    /**
75
     * @var array
76
     */
77
    protected array $metadata = [];
78
79
    /**
80
     * @var string|null
81
     */
82
    protected ?string $model = null;
83
84
    /**
85
     * @var string|null
86
     */
87
    protected ?string $modelId = null;
88
89
    /**
90
     * Source file to be stored in our system
91
     *
92
     * @var mixed
93
     */
94
    protected $sourceFile;
95
96
    /**
97
     * @var resource
98
     */
99
    protected $resource;
100
101
    /**
102
     * @var array
103
     */
104
    protected array $variants = [];
105
106
    /**
107
     * Creates a new instance
108
     *
109
     * @param string $filename Filename
110
     * @param int $filesize Filesize
111
     * @param string $mimeType Mime Type
112
     * @param string $storage Storage config name
113
     * @param string|null $collection Collection name
114
     * @param string|null $model Model name
115
     * @param string|null $modelId Model id
116
     * @param array $variants Variants
117
     * @param array $metadata Meta data
118
     * @param resource|null $resource
119
     * @return self
120
     */
121 7
    public static function create(
122
        string $filename,
123
        int $filesize,
124
        string $mimeType,
125
        string $storage,
126
        ?string $collection = null,
127
        ?string $model = null,
128
        ?string $modelId = null,
129
        array $metadata = [],
130
        array $variants = [],
131
        $resource = null
132
    ): self {
133 7
        $that = new self();
134
135 7
        $that->filename = $filename;
136 7
        $that->filesize = $filesize;
137 7
        $that->mimeType = $mimeType;
138 7
        $that->storage = $storage;
139 7
        $that->model = $model;
140 7
        $that->modelId = $modelId;
141 7
        $that->collection = $collection;
142 7
        $that->variants = $variants;
143 7
        $that->metadata = $metadata;
144
145 7
        if ($resource !== null) {
146
            $that = $that->withResource($resource);
147
        }
148
149 7
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
150 7
        $that->extension = empty($extension) ? null : (string)$extension;
151
152 7
        return $that;
153
    }
154
155
    /**
156
     * Storage name
157
     *
158
     * @return string
159
     */
160 1
    public function storage(): string
161
    {
162 1
        return $this->storage;
163
    }
164
165
    /**
166
     * UUID of the file
167
     *
168
     * @param string $uuid UUID string
169
     * @return self
170
     */
171 5
    public function withUuid(string $uuid): self
172
    {
173 5
        $that = clone $this;
174 5
        $that->uuid = $uuid;
175
176 5
        return $that;
177
    }
178
179
    /**
180
     * Stream resource that should be stored
181
     *
182
     * @return resource|null
183
     */
184 1
    public function resource()
185
    {
186 1
        return $this->resource;
187
    }
188
189
    /**
190
     * Same as withResource() but takes a file path
191
     *
192
     * @param string $file File
193
     * @return self
194
     */
195
    public function withFile(string $file): self
196
    {
197
        $resource = fopen($file, 'rb');
198
199
        return $this->withResource($resource);
200
    }
201
202
    /**
203
     * @param mixed $resource
204
     */
205 6
    protected function assertStreamResource($resource): void
206
    {
207
        if (
208 6
            !is_resource($resource)
209 6
            || get_resource_type($resource) !== 'stream'
210
        ) {
211
            throw InvalidStreamResourceException::create();
212
        }
213 6
    }
214
215
    /**
216
     * Stream resource of the file to be stored
217
     *
218
     * @param resource $resource Stream Resource
219
     * @return self
220
     */
221 6
    public function withResource($resource): self
222
    {
223 6
        $this->assertStreamResource($resource);
224
225 6
        $that = clone $this;
226 6
        $that->resource = $resource;
227
228 6
        return $that;
229
    }
230
231
    /**
232
     * Assign a model and model id to a file
233
     *
234
     * @param string $model Model
235
     * @param string|int $modelId Model ID, UUID string or integer
236
     * @return $this
237
     */
238 5
    public function belongsToModel(string $model, $modelId): self
239
    {
240 5
        $this->model = $model;
241 5
        $this->modelId = $modelId;
242
243 5
        return $this;
244
    }
245
246
    /**
247
     * Adds the file to a collection
248
     *
249
     * @param string $collection Collection
250
     * @return $this
251
     */
252 3
    public function addToCollection(string $collection): self
253
    {
254 3
        $this->collection = $collection;
255
256 3
        return $this;
257
    }
258
259
    /**
260
     * Sets the path, immutable
261
     *
262
     * @param string $path Path to the file
263
     * @return $this
264
     */
265
    public function withPath(string $path): self
266
    {
267
        $that = clone $this;
268
        $that->path = $path;
269
270
        return $that;
271
    }
272
273
    /**
274
     * Filename
275
     *
276
     * @param string $filename Filename
277
     * @return self
278
     */
279 2
    public function withFilename(string $filename): self
280
    {
281 2
        $that = clone $this;
282 2
        $that->filename = $filename;
283
284 2
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
285 2
        $that->extension = empty($extension) ? null : (string)$extension;
286
287 2
        return $that;
288
    }
289
290
    /**
291
     * The collections name this file belongs into
292
     *
293
     * @return string|null
294
     */
295 4
    public function collection(): ?string
296
    {
297 4
        return $this->collection;
298
    }
299
300
    /**
301
     * Model name
302
     *
303
     * @return string|null
304
     */
305 5
    public function model(): ?string
306
    {
307 5
        return $this->model;
308
    }
309
310
    /**
311
     * Model ID
312
     *
313
     * @return string|null
314
     */
315 4
    public function modelId(): ?string
316
    {
317 4
        return $this->modelId;
318
    }
319
320
    /**
321
     * Size of the file in bytes
322
     *
323
     * @return int
324
     */
325
    public function filesize(): int
326
    {
327
        return $this->filesize;
328
    }
329
330
    /**
331
     * Returns a human readable file size
332
     *
333
     * @return string
334
     */
335
    public function readableSize(): string
336
    {
337
        $i = floor(log($this->filesize, 1024));
338
        $round = (string)round($this->filesize / (1024 ** $i), [0, 0, 2, 2, 3][$i]);
339
340
        return $round . ['B','kB','MB','GB','TB'][$i];
341
    }
342
343
    /**
344
     * @return string|null
345
     */
346 4
    public function extension(): ?string
347
    {
348 4
        return $this->extension;
349
    }
350
351
    /**
352
     * @return string
353
     */
354 4
    public function mimeType(): string
355
    {
356 4
        return $this->mimeType;
357
    }
358
359
    /**
360
     * @return string
361
     */
362 4
    public function filename(): string
363
    {
364 4
        return $this->filename;
365
    }
366
367
    /**
368
     * @return string
369
     */
370 4
    public function uuid(): string
371
    {
372 4
        return $this->uuid;
373
    }
374
375
    /**
376
     * @return string
377
     */
378 3
    public function path(): string
379
    {
380 3
        if ($this->path === null) {
381 1
            throw new RuntimeException(
382 1
                'Path has not been set'
383
            );
384
        }
385
386 2
        return $this->path;
387
    }
388
389
    /**
390
     * Builds the path for this file
391
     *
392
     * @param \Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface $pathBuilder Path Builder
393
     * @return $this
394
     */
395 2
    public function buildPath(PathBuilderInterface $pathBuilder): self
396
    {
397 2
        $that = clone $this;
398 2
        $that->path = $pathBuilder->path($this);
399
400 2
        return $that;
401
    }
402
403
    /**
404
     * @param array $metadata Meta data
405
     * @return $this
406
     */
407 1
    public function withMetadata(array $metadata): self
408
    {
409 1
        $that = clone $this;
410 1
        $that->metadata = $metadata;
411
412 1
        return $that;
413
    }
414
415
    /**
416
     * @param string $name Name
417
     * @param mixed $data Data
418
     * @return $this
419
     */
420 2
    public function withMetadataKey(string $name, $data): self
421
    {
422 2
        $that = clone $this;
423 2
        $that->metadata[$name] = $data;
424
425 2
        return $that;
426
    }
427
428
    /**
429
     * @param string $name Name
430
     * @return $this
431
     */
432
    public function withoutMetadataKey(string $name): self
433
    {
434
        $that = clone $this;
435
        unset($that->metadata[$name]);
436
437
        return $that;
438
    }
439
440
    /**
441
     * @return $this
442
     */
443
    public function withoutMetadata(): self
444
    {
445
        $that = clone $this;
446
        $that->metadata = [];
447
448
        return $that;
449
    }
450
451
    /**
452
     * @return array
453
     */
454
    public function metadata(): array
455
    {
456
        return $this->metadata;
457
    }
458
459
    /**
460
     * @return bool
461
     */
462
    public function hasVariants(): bool
463
    {
464
        return !empty($this->variants);
465
    }
466
467
    /**
468
     * @param string $name Name
469
     * @return bool
470
     */
471
    public function hasVariant(string $name): bool
472
    {
473
        return isset($this->variants[$name]);
474
    }
475
476
    /**
477
     * @return array
478
     */
479 2
    public function variants(): array
480
    {
481 2
        return $this->variants;
482
    }
483
484
    /**
485
     * Returns a variant by name
486
     *
487
     * @param string $name Name
488
     * @return array
489
     */
490
    public function variant(string $name): array
491
    {
492
        if (!isset($this->variants[$name])) {
493
            throw new VariantException(sprintf(
494
                'Variant %s does not exist',
495
                $name
496
            ));
497
        }
498
499
        return $this->variants[$name];
500
    }
501
502
    /**
503
     * Adds a variant
504
     *
505
     * @param string $name Name
506
     * @param array $data Data
507
     * @return $this
508
     */
509
    public function withVariant(string $name, array $data): self
510
    {
511
        $that = clone $this;
512
        $that->variants[$name] = $data;
513
514
        return $that;
515
    }
516
517
    /**
518
     * Gets the paths for all variants
519
     *
520
     * @return array
521
     */
522
    public function variantPaths(): array
523
    {
524
        $paths = [];
525
        foreach ($this->variants as $variant => $data) {
526
            if (isset($data['path'])) {
527
                $paths[$variant] = $data['path'];
528
            }
529
        }
530
531
        return $paths;
532
    }
533
534
    /**
535
     * Sets many variants at once
536
     *
537
     * @param array $variants Variants
538
     * @param bool $merge Merge Variants, default is true
539
     * @return $this
540
     */
541 2
    public function withVariants(array $variants, bool $merge = true): self
542
    {
543 2
        $that = clone $this;
544 2
        $that->variants = array_merge_recursive(
545 2
            $merge ? $that->variants : [],
546
            $variants
547
        );
548
549 2
        return $that;
550
    }
551
552
    /**
553
     * @return array
554
     */
555
    public function toArray(): array
556
    {
557
        return [
558
            'uuid' => $this->uuid,
559
            'filename' => $this->filename,
560
            'filesize' => $this->filesize,
561
            'mimeType' => $this->mimeType,
562
            'extension' => $this->extension,
563
            'path' => $this->path,
564
            'model' => $this->model,
565
            'modelId' => $this->modelId,
566
            'collection' => $this->collection,
567
            'readableSize' => $this->readableSize(),
568
            'variants' => $this->variants,
569
            'metaData' => $this->metadata,
570
        ];
571
    }
572
573
    /**
574
     * @inheritDoc
575
     */
576
    public function jsonSerialize()
577
    {
578
        return $this->toArray();
579
    }
580
}
581