Completed
Branch ci (403ea4)
by Florian
02:31
created

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