Completed
Pull Request — 1.x (#9)
by Akihito
04:16 queued 03:14
created

StreamRenderer   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 2
dl 0
loc 149
ccs 0
cts 48
cp 0
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A render() 0 10 2
A toStream() 0 10 2
A pushStream() 0 9 1
A mergeStream() 0 19 3
A collect() 0 9 2
A pushScalarBody() 0 8 3
A pushArrayBody() 0 8 4
1
<?php
2
/**
3
 * This file is part of the BEAR.Middleware package.
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Middleware\Module;
8
9
use BEAR\Resource\RenderInterface;
10
use BEAR\Resource\ResourceObject;
11
use Ray\Di\Di\Named;
12
13
class StreamRenderer implements RenderInterface
14
{
15
    /**
16
     * @var RenderInterface
17
     */
18
    private $renderer;
19
20
    /**
21
     * @var resource
22
     */
23
    private $stream;
24
25
    /**
26
     * Pushed stream
27
     *
28
     * @var resource[]
29
     */
30
    private $streams;
31
32
    /**
33
     * @var array
34
     */
35
    private $hash = [];
36
37
    /**
38
     * @param RenderInterface $renderer
39
     *
40
     * @Named("renderer=original,stream=BEAR\Middleware\Annotation\Stream")
41
     */
42
    public function __construct(RenderInterface $renderer, $stream)
43
    {
44
        $this->renderer = $renderer;
45
        $this->stream = $stream;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function render(ResourceObject $ro)
52
    {
53
        if (is_array($ro->body)) {
54
            $this->pushArrayBody($ro);
55
56
            return $this->renderer->render($ro);
57
        }
58
59
        return $this->pushScalarBody($ro);
60
    }
61
62
    /**
63
     * Covert string + stream holder to stream
64
     *
65
     * @param string $string
66
     *
67
     * @return resource
68
     */
69
    public function toStream($string)
70
    {
71
        if (! $this->hash) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->hash of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
72
            fwrite($this->stream, $string);
73
74
            return $this->stream;
75
        }
76
77
        return $this->mergeStream($string, $this->stream);
78
    }
79
80
    /**
81
     * @param resource $item
82
     *
83
     * @return string
84
     */
85
    private function pushStream($item)
86
    {
87
        $id = uniqid('STREAM_' . mt_rand(), true) . '_';
88
        $this->streams[$id] = $item; // push
89
        $this->hash[] = $id;
90
        $item = $id;
91
92
        return $item;
93
    }
94
95
    /**
96
     * @param string   $string
97
     * @param resource $stream
98
     *
99
     * @return resource
100
     */
101
    private function mergeStream($string, $stream)
102
    {
103
        rewind($stream);
104
        $regex = sprintf('/(%s)/', implode('|', $this->hash));
105
        preg_match_all($regex, $string, $match, PREG_SET_ORDER);
106
        $list = $this->collect($match);
0 ignored issues
show
Bug introduced by
It seems like $match can also be of type null; however, BEAR\Middleware\Module\StreamRenderer::collect() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
107
        $bodies = preg_split($regex, $string);
108
        foreach ($bodies as $body) {
109
            fwrite($stream, $body);
110
            $index = array_shift($list);
111
            if (isset($this->streams[$index])) {
112
                $popStream = $this->streams[$index];
113
                rewind($popStream);
114
                stream_copy_to_stream($popStream, $stream);
115
            }
116
        }
117
118
        return $stream;
119
    }
120
121
    /**
122
     * @param array $match
123
     *
124
     * @return array
125
     */
126
    private function collect(array $match)
127
    {
128
        $list = [];
129
        foreach ($match as $item) {
130
            $list[] = $item[0];
131
        }
132
133
        return $list;
134
    }
135
136
    /**
137
     * @param ResourceObject $ro
138
     *
139
     * @return string
140
     */
141
    private function pushScalarBody(ResourceObject $ro)
142
    {
143
        if (is_resource($ro->body) && get_resource_type($ro->body) == 'stream') {
144
            return $this->pushStream($ro->body);
145
        }
146
147
        return $this->renderer->render($ro);
148
    }
149
150
    /**
151
     * @param ResourceObject $ro
152
     */
153
    private function pushArrayBody(ResourceObject $ro)
154
    {
155
        foreach ($ro->body as &$item) {
156
            if (is_resource($item) && get_resource_type($item) == 'stream') {
157
                $item = $this->pushStream($item);
158
            }
159
        }
160
    }
161
}
162