Completed
Branch ci (542cc6)
by Florian
05:01 queued 02:34
created

File::create()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3.0021

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
ccs 15
cts 16
cp 0.9375
crap 3.0021
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 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