Passed
Push — master ( cd2df9...005de6 )
by Aleksei
02:40
created

SmartStreamFactory::withStreamFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
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 16
    public function __construct(
22
        StreamFactoryInterface $defaultFactory,
23
        ConverterMatcherInterface $converterMatcher
24
    ) {
25 16
        $this->converterMatcher = $converterMatcher;
26
27 16
        $this->addStreamFactory(static fn($data) => $data instanceof \Generator ? new GeneratorStream($data) : null);
28 16
        $this->addStreamFactory(function ($data) use ($defaultFactory) {
29
            switch (true) {
30 15
                case is_string($data):
31 2
                    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 16
        });
39 16
    }
40
41 4
    public function withDefaultBucketClass(string $bucketClass): self
42
    {
43 4
        $clone = clone $this;
44 4
        if (!is_subclass_of($bucketClass, DataBucket::class, true)) {
45 1
            throw new \InvalidArgumentException('Bucket class should be subclass of DataBucket.');
46
        }
47 4
        $clone->defaultBucketClass = $bucketClass;
48 4
        return $clone;
49
    }
50
51
    /**
52
     * Last added factory called first
53
     */
54 1
    public function withStreamFactory(Closure $factory): self
55
    {
56 1
        $clone = clone $this;
57 1
        $clone->addStreamFactory($factory);
58 1
        return $clone;
59
    }
60
61 16
    private function addStreamFactory(Closure $factory): void
62
    {
63 16
        array_unshift($this->factories, $factory);
64 16
    }
65
66 15
    public function createStream($data, ?RequestInterface $request = null): StreamInterface
67
    {
68 15
        foreach ($this->factories as $factory) {
69 15
            $result = $factory($data);
70 15
            if ($result instanceof StreamInterface) {
71 5
                return $result;
72
            }
73 12
            if ($result instanceof BucketStream) {
74
                $data = $result;
75
                break;
76
            }
77
        }
78 10
        return new BucketStream(
79 10
            $this->converterMatcher->withRequest($request),
80 10
            $data instanceof DataBucket ? $data : new $this->defaultBucketClass($data)
81
        );
82
    }
83
}
84