SmartStreamFactory::__construct()   A
last analyzed

Complexity

Conditions 5
Paths 1

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 11
nc 1
nop 2
dl 0
loc 17
ccs 11
cts 11
cp 1
crap 5
rs 9.6111
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace roxblnfk\SmartStream;
6
7
use Closure;
8
use Psr\Http\Message\RequestInterface;
9
use Psr\Http\Message\StreamFactoryInterface;
10
use Psr\Http\Message\StreamInterface;
11
use roxblnfk\SmartStream\Data\DataBucket;
12
use roxblnfk\SmartStream\Stream\BucketStream;
13
use roxblnfk\SmartStream\Stream\GeneratorStream;
14
15
final class SmartStreamFactory
16
{
17
    private ConverterMatcherInterface $converterMatcher;
18
    private string $defaultBucketClass = DataBucket::class;
19
    private array $factories = [];
20
21 18
    public function __construct(
22
        StreamFactoryInterface $defaultFactory,
23
        ConverterMatcherInterface $converterMatcher
24
    ) {
25 18
        $this->converterMatcher = $converterMatcher;
26
27 18
        $this->addStreamFactory(static fn($data) => $data instanceof \Generator ? new GeneratorStream($data) : null);
28 18
        $this->addStreamFactory(function ($data) use ($defaultFactory) {
29
            switch (true) {
30 16
                case is_string($data):
31 3
                    return $defaultFactory->createStream($data);
32 13
                case is_resource($data):
33 1
                    return $defaultFactory->createStreamFromResource($data);
34 12
                case $data instanceof \SplFileInfo:
35 1
                    return $defaultFactory->createStreamFromFile($data->getPathname());
36
            }
37 11
            return null;
38 18
        });
39 18
    }
40
41 5
    public function withDefaultBucketClass(string $bucketClass): self
42
    {
43 5
        $clone = clone $this;
44 5
        if (!is_subclass_of($bucketClass, DataBucket::class, true)) {
45 1
            throw new \InvalidArgumentException('Bucket class should be subclass of DataBucket.');
46
        }
47 5
        $clone->defaultBucketClass = $bucketClass;
48 5
        return $clone;
49
    }
50
51
    /**
52
     * Last added factory called first
53
     */
54 2
    public function withStreamFactory(Closure $factory): self
55
    {
56 2
        $clone = clone $this;
57 2
        $clone->addStreamFactory($factory);
58 2
        return $clone;
59
    }
60
61 1
    public function withoutStreamFactories(): self
62
    {
63 1
        $clone = clone $this;
64 1
        $clone->factories = [];
65 1
        return $clone;
66
    }
67
68 18
    private function addStreamFactory(Closure $factory): void
69
    {
70 18
        array_unshift($this->factories, $factory);
71 18
    }
72
73 17
    public function createStream($data, ?RequestInterface $request = null): StreamInterface
74
    {
75 17
        foreach ($this->factories as $factory) {
76 17
            $result = $factory($data);
77 17
            if ($result instanceof StreamInterface) {
78 6
                return $result;
79
            }
80 13
            if ($result instanceof DataBucket) {
81 1
                $data = $result;
82 1
                break;
83
            }
84
        }
85 12
        return new BucketStream(
86 12
            $this->converterMatcher->withRequest($request),
87 12
            $data instanceof DataBucket ? $data : new $this->defaultBucketClass($data)
88
        );
89
    }
90
}
91