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
|
6 |
|
public function __construct(RenderInterface $renderer, $stream) |
43
|
|
|
{ |
44
|
6 |
|
$this->renderer = $renderer; |
45
|
6 |
|
$this->stream = $stream; |
46
|
6 |
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* {@inheritdoc} |
50
|
|
|
*/ |
51
|
5 |
|
public function render(ResourceObject $ro) |
52
|
|
|
{ |
53
|
5 |
|
if (is_array($ro->body)) { |
54
|
3 |
|
$this->pushArrayBody($ro); |
55
|
|
|
|
56
|
3 |
|
return $this->renderer->render($ro); |
57
|
|
|
} |
58
|
|
|
|
59
|
2 |
|
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
|
5 |
|
public function toStream($string) |
70
|
|
|
{ |
71
|
5 |
|
if (! $this->hash) { |
|
|
|
|
72
|
2 |
|
fwrite($this->stream, $string); |
73
|
|
|
|
74
|
2 |
|
return $this->stream; |
75
|
|
|
} |
76
|
|
|
|
77
|
3 |
|
return $this->mergeStream($string, $this->stream); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @param resource $item |
82
|
|
|
* |
83
|
|
|
* @return string |
84
|
|
|
*/ |
85
|
3 |
|
private function pushStream($item) |
86
|
|
|
{ |
87
|
3 |
|
$id = uniqid('STREAM_' . mt_rand(), true) . '_'; |
88
|
3 |
|
$this->streams[$id] = $item; // push |
89
|
3 |
|
$this->hash[] = $id; |
90
|
3 |
|
$item = $id; |
91
|
|
|
|
92
|
3 |
|
return $item; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @param string $string |
97
|
|
|
* @param resource $stream |
98
|
|
|
* |
99
|
|
|
* @return resource |
100
|
|
|
*/ |
101
|
3 |
|
private function mergeStream($string, $stream) |
102
|
|
|
{ |
103
|
3 |
|
rewind($stream); |
104
|
3 |
|
$regex = sprintf('/(%s)/', implode('|', $this->hash)); |
105
|
3 |
|
preg_match_all($regex, $string, $match, PREG_SET_ORDER); |
106
|
3 |
|
$list = $this->collect($match); |
|
|
|
|
107
|
3 |
|
$bodies = preg_split($regex, $string); |
108
|
3 |
|
foreach ($bodies as $body) { |
109
|
3 |
|
fwrite($stream, $body); |
110
|
3 |
|
$index = array_shift($list); |
111
|
3 |
|
if (isset($this->streams[$index])) { |
112
|
3 |
|
$popStream = $this->streams[$index]; |
113
|
3 |
|
rewind($popStream); |
114
|
3 |
|
stream_copy_to_stream($popStream, $stream); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
3 |
|
return $stream; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* @param array $match |
123
|
|
|
* |
124
|
|
|
* @return array |
125
|
|
|
*/ |
126
|
3 |
|
private function collect(array $match) |
127
|
|
|
{ |
128
|
3 |
|
$list = []; |
129
|
3 |
|
foreach ($match as $item) { |
130
|
3 |
|
$list[] = $item[0]; |
131
|
|
|
} |
132
|
|
|
|
133
|
3 |
|
return $list; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* @param ResourceObject $ro |
138
|
|
|
* |
139
|
|
|
* @return string |
140
|
|
|
*/ |
141
|
2 |
|
private function pushScalarBody(ResourceObject $ro) |
142
|
|
|
{ |
143
|
2 |
|
if (is_resource($ro->body) && get_resource_type($ro->body) == 'stream') { |
144
|
1 |
|
return $this->pushStream($ro->body); |
145
|
|
|
} |
146
|
|
|
|
147
|
1 |
|
return $this->renderer->render($ro); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param ResourceObject $ro |
152
|
|
|
*/ |
153
|
3 |
|
private function pushArrayBody(ResourceObject $ro) |
154
|
|
|
{ |
155
|
3 |
|
foreach ($ro->body as &$item) { |
156
|
3 |
|
if (is_resource($item) && get_resource_type($item) == 'stream') { |
157
|
2 |
|
$item = $this->pushStream($item); |
158
|
|
|
} |
159
|
|
|
} |
160
|
3 |
|
} |
161
|
|
|
} |
162
|
|
|
|
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.