File::create()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 15
c 1
b 0
f 0
nc 4
nop 10
dl 0
loc 32
rs 9.7666

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\VariantDoesNotExistException;
22
use Phauthentic\Infrastructure\Storage\UrlBuilder\UrlBuilderInterface;
23
use RuntimeException;
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|null
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<string, mixed>
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 string
104
     */
105
    protected string $url = '';
106
107
    /**
108
     * @var array<string, array<string, mixed>>
109
     */
110
    protected array $variants = [];
111
112
    /**
113
     * Creates a new instance
114
     *
115
     * @param string $filename Filename
116
     * @param int $filesize Filesize
117
     * @param string $mimeType Mime Type
118
     * @param string $storage Storage config name
119
     * @param string|null $collection Collection name
120
     * @param string|null $model Model name
121
     * @param string|null $modelId Model id
122
     * @param array<string, mixed> $variants Variants
123
     * @param array<string, mixed> $metadata Meta data
124
     * @param resource|null $resource
125
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
126
     */
127
    public static function create(
128
        string $filename,
129
        int $filesize,
130
        string $mimeType,
131
        string $storage,
132
        ?string $collection = null,
133
        ?string $model = null,
134
        ?string $modelId = null,
135
        array $metadata = [],
136
        array $variants = [],
137
        $resource = null
138
    ): FileInterface {
139
        $that = new self();
140
141
        $that->filename = $filename;
142
        $that->filesize = $filesize;
143
        $that->mimeType = $mimeType;
144
        $that->storage = $storage;
145
        $that->model = $model;
146
        $that->modelId = $modelId;
147
        $that->collection = $collection;
148
        $that->variants = $variants;
149
        $that->metadata = $metadata;
150
151
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
152
        $that->extension = empty($extension) ? null : (string)$extension;
153
154
        if ($resource !== null) {
155
            $that = $that->withResource($resource);
156
        }
157
158
        return $that;
159
    }
160
161
    /**
162
     * Storage name
163
     *
164
     * @return string
165
     */
166
    public function storage(): string
167
    {
168
        return $this->storage;
169
    }
170
171
    /**
172
     * UUID of the file
173
     *
174
     * @param string $uuid UUID string
175
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
176
     */
177
    public function withUuid(string $uuid): FileInterface
178
    {
179
        $that = clone $this;
180
        $that->uuid = $uuid;
181
182
        return $that;
183
    }
184
185
    /**
186
     * Stream resource that should be stored
187
     *
188
     * @return resource|null
189
     */
190
    public function resource()
191
    {
192
        return $this->resource;
193
    }
194
195
    /**
196
     * Same as withResource() but takes a file path
197
     *
198
     * @param string $file File
199
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
200
     */
201
    public function withFile(string $file): FileInterface
202
    {
203
        $resource = fopen($file, 'rb');
204
205
        return $this->withResource($resource);
206
    }
207
208
    /**
209
     * @param mixed $resource
210
     * @return void
211
     */
212
    protected function assertStreamResource($resource): void
213
    {
214
        if (
215
            !is_resource($resource)
216
            || get_resource_type($resource) !== 'stream'
217
        ) {
218
            throw InvalidStreamResourceException::create();
219
        }
220
    }
221
222
    /**
223
     * Stream resource of the file to be stored
224
     *
225
     * @param resource $resource Stream Resource
226
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
227
     */
228
    public function withResource($resource): FileInterface
229
    {
230
        $this->assertStreamResource($resource);
231
232
        $that = clone $this;
233
        $that->resource = $resource;
234
235
        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 \Phauthentic\Infrastructure\Storage\FileInterface
244
     */
245
    public function belongsToModel(string $model, $modelId): FileInterface
246
    {
247
        $this->model = $model;
248
        $this->modelId = (string)$modelId;
249
250
        return $this;
251
    }
252
253
    /**
254
     * Adds the file to a collection
255
     *
256
     * @param string $collection Collection
257
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
258
     */
259
    public function addToCollection(string $collection): FileInterface
260
    {
261
        $this->collection = $collection;
262
263
        return $this;
264
    }
265
266
    /**
267
     * Sets the path, immutable
268
     *
269
     * @param string $path Path to the file
270
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
271
     */
272
    public function withPath(string $path): FileInterface
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
    public function withFilename(string $filename): self
287
    {
288
        $that = clone $this;
289
        $that->filename = $filename;
290
291
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
292
        $that->extension = empty($extension) ? null : (string)$extension;
293
294
        return $that;
295
    }
296
297
    /**
298
     * The collections name this file belongs into
299
     *
300
     * @return string|null
301
     */
302
    public function collection(): ?string
303
    {
304
        return $this->collection;
305
    }
306
307
    /**
308
     * Model name
309
     *
310
     * @return string|null
311
     */
312
    public function model(): ?string
313
    {
314
        return $this->model;
315
    }
316
317
    /**
318
     * Model ID
319
     *
320
     * @return string|null
321
     */
322
    public function modelId(): ?string
323
    {
324
        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 = (int)floor(log($this->filesize, 1024));
345
        $rounds = [0, 0, 2, 2, 3];
346
        $units = ['B','kB','MB','GB','TB'];
347
348
        if ($i < 0 || $i >= count($rounds)) {
349
            $i = 0;
350
        }
351
352
        $round = (string)round($this->filesize / (1024 ** $i), $rounds[$i]);
353
354
        return $round . $units[$i];
355
    }
356
357
    /**
358
     * @return string|null
359
     */
360
    public function extension(): ?string
361
    {
362
        return $this->extension;
363
    }
364
365
    /**
366
     * @return string
367
     */
368
    public function mimeType(): string
369
    {
370
        return $this->mimeType;
371
    }
372
373
    /**
374
     * @return string
375
     */
376
    public function filename(): string
377
    {
378
        return $this->filename;
379
    }
380
381
    /**
382
     * @return string
383
     */
384
    public function uuid(): string
385
    {
386
        return $this->uuid;
387
    }
388
389
    /**
390
     * @return string
391
     */
392
    public function path(): string
393
    {
394
        if ($this->path === null) {
395
            throw new RuntimeException(
396
                'Path has not been set'
397
            );
398
        }
399
400
        return $this->path;
401
    }
402
403
    /**
404
     * Builds the path for this file
405
     *
406
     * @param \Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface $pathBuilder Path Builder
407
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
408
     */
409
    public function buildPath(PathBuilderInterface $pathBuilder): FileInterface
410
    {
411
        $that = clone $this;
412
        $that->path = $pathBuilder->path($this);
413
414
        return $that;
415
    }
416
417
    /**
418
     * @param array<string, mixed> $metadata Meta data
419
     * @param bool $overwrite Overwrite whole metadata instead of assoc merging.
420
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
421
     */
422
    public function withMetadata(array $metadata, bool $overwrite = false): FileInterface
423
    {
424
        $that = clone $this;
425
        if ($overwrite) {
426
            $that->metadata = $metadata;
427
        } else {
428
            $that->metadata = $metadata + $that->metadata;
429
        }
430
431
        return $that;
432
    }
433
434
    /**
435
     * @inheritDoc
436
     */
437
    public function withMetadataByKey(string $name, $data): FileInterface
438
    {
439
        $that = clone $this;
440
        $that->metadata[$name] = $data;
441
442
        return $that;
443
    }
444
445
    /**
446
     * @inheritDoc
447
     */
448
    public function withoutMetadataByKey(string $name): FileInterface
449
    {
450
        $that = clone $this;
451
        unset($that->metadata[$name]);
452
453
        return $that;
454
    }
455
456
    /**
457
     * @inheritDoc
458
     */
459
    public function withoutMetadata(): self
460
    {
461
        $that = clone $this;
462
        $that->metadata = [];
463
464
        return $that;
465
    }
466
467
    /**
468
     * @inheritDoc
469
     */
470
    public function metadata(): array
471
    {
472
        return $this->metadata;
473
    }
474
475
    /**
476
     * @return bool
477
     */
478
    public function hasVariants(): bool
479
    {
480
        return !empty($this->variants);
481
    }
482
483
    /**
484
     * @param string $name Name
485
     * @return bool
486
     */
487
    public function hasVariant(string $name): bool
488
    {
489
        return isset($this->variants[$name]);
490
    }
491
492
    /**
493
     * @return array<string, array<string, mixed>>
494
     */
495
    public function variants(): array
496
    {
497
        return $this->variants;
498
    }
499
500
    /**
501
     * Returns a variant by name
502
     *
503
     * @param string $name Name
504
     * @return array<string, mixed>
505
     */
506
    public function variant(string $name): array
507
    {
508
        if (!isset($this->variants[$name])) {
509
            throw VariantDoesNotExistException::withName($name);
510
        }
511
512
        return $this->variants[$name];
513
    }
514
515
    /**
516
     * Adds a variant
517
     *
518
     * @param string $name Name
519
     * @param array<string, mixed> $data Data
520
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
521
     */
522
    public function withVariant(string $name, array $data): FileInterface
523
    {
524
        $that = clone $this;
525
        $that->variants[$name] = $data;
526
527
        return $that;
528
    }
529
530
    /**
531
     * Gets the paths for all variants
532
     *
533
     * @return array<string, string>
534
     */
535
    public function variantPaths(): array
536
    {
537
        $paths = [];
538
        foreach ($this->variants as $variant => $data) {
539
            if (!empty($data['path'])) {
540
                $paths[$variant] = $data['path'];
541
            }
542
        }
543
544
        return $paths;
545
    }
546
547
    /**
548
     * @param string $key
549
     * @param mixed $data;
550
     */
551
    public function withMetadataKey(string $key, $data): FileInterface
552
    {
553
        $that = clone $this;
554
        $that->metadata[$key] = $data;
555
556
        return $that;
557
    }
558
559
    /**
560
     * @inheritDoc
561
     */
562
    public function withoutMetadataKey(string $key): FileInterface
563
    {
564
        $that = clone $this;
565
        unset($that->metadata[$key]);
566
567
        return $that;
568
    }
569
570
    /**
571
     * Sets many variants at once
572
     *
573
     * @param array<string, array<string, mixed>> $variants Variants
574
     * @param bool $merge Merge Variants, default is true
575
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
576
     */
577
    public function withVariants(array $variants, bool $merge = true): FileInterface
578
    {
579
        $that = clone $this;
580
        $that->variants = array_merge_recursive(
581
            $merge ? $that->variants : [],
582
            $variants
583
        );
584
585
        return $that;
586
    }
587
588
    /**
589
     * @inheritDoc
590
     */
591
    public function buildUrl(UrlBuilderInterface $urlBuilder): FileInterface
592
    {
593
        $this->url = $urlBuilder->url($this);
594
595
        return $this;
596
    }
597
598
    /**
599
     * @inheritDoc
600
     */
601
    public function url(): string
602
    {
603
        return $this->url;
604
    }
605
606
    /**
607
     * @inheritDoc
608
     */
609
    public function withUrl(string $url): FileInterface
610
    {
611
        $that = clone $this;
612
        $that->url = $url;
613
614
        return $that;
615
    }
616
617
    /**
618
     * @return array<string, mixed>
619
     */
620
    public function toArray(): array
621
    {
622
        return [
623
            'uuid' => $this->uuid,
624
            'filename' => $this->filename,
625
            'filesize' => $this->filesize,
626
            'mimeType' => $this->mimeType,
627
            'extension' => $this->extension,
628
            'path' => $this->path,
629
            'model' => $this->model,
630
            'modelId' => $this->modelId,
631
            'collection' => $this->collection,
632
            'readableSize' => $this->readableSize(),
633
            'variants' => $this->variants,
634
            'metadata' => $this->metadata,
635
            'url' => $this->url
636
        ];
637
    }
638
639
    /**
640
     * @inheritDoc
641
     * @return array<string, mixed>
642
     */
643
    public function jsonSerialize(): array
644
    {
645
        return $this->toArray();
646
    }
647
}
648