1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Junty |
4
|
|
|
* |
5
|
|
|
* @author Gabriel Jacinto aka. GabrielJMJ <[email protected]> |
6
|
|
|
* @license MIT License |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Junty\Stream; |
10
|
|
|
|
11
|
|
|
use Psr\Http\Message\StreamInterface; |
12
|
|
|
use GuzzleHttp\Psr7; |
13
|
|
|
use Junty\Stream\Stream; |
14
|
|
|
use Junty\Plugin\PluginInterface; |
15
|
|
|
use Junty\ToDir\ToDirPlugin; |
16
|
|
|
|
17
|
|
|
class StreamHandler |
18
|
|
|
{ |
19
|
|
|
private $globs = []; |
20
|
|
|
|
21
|
|
|
private $toPush = []; |
22
|
|
|
|
23
|
|
|
private $temp = []; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Provides streams by the pattern passed |
27
|
|
|
* |
28
|
|
|
* @param string|array $accept |
29
|
|
|
* @param string|array|null $exclude |
30
|
|
|
* |
31
|
|
|
* @return self |
32
|
|
|
*/ |
33
|
|
|
public function src($accept, $exclude = null) : self |
34
|
|
|
{ |
35
|
|
|
if ((!is_string($accept) && !is_array($accept)) || ($exclude !== null && !is_string($exclude) && !is_array($exclude))) { |
36
|
|
|
throw new \InvalidArgumentException('You can only pass a string pattern or array with patterns'); |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
if (is_array($accept)) { |
40
|
|
|
$fileGroups = []; |
41
|
|
|
|
42
|
|
|
foreach ($accept as $pattern) { |
43
|
|
|
$fileGroups[] = $this->recoursiveGlob($pattern, GLOB_ERR); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
$globs = call_user_func_array('array_merge', $fileGroups); |
47
|
|
|
} else { |
48
|
|
|
$globs = $this->recoursiveGlob($accept, GLOB_ERR); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
$this->globs = $this->ignoreFiles($globs, $exclude); |
|
|
|
|
52
|
|
|
|
53
|
|
|
return $this; |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Handle each stream |
58
|
|
|
* |
59
|
|
|
* @param callable|PluginInterface $callback |
60
|
|
|
* |
61
|
|
|
* @return self |
62
|
|
|
*/ |
63
|
|
|
public function forStream($callback) : self |
64
|
|
|
{ |
65
|
|
|
$cb = \Closure::bind($this->getCallback($callback), $this); |
66
|
|
|
|
67
|
|
|
if (count($this->toPush)) { |
68
|
|
|
foreach ($this->toPush as $stream) { |
69
|
|
|
$cb($stream); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
return $this; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$streams = array_map(function ($file) { |
76
|
|
|
return new Stream(fopen($file, 'r+')); |
77
|
|
|
}, $this->globs); |
78
|
|
|
|
79
|
|
|
foreach ($streams as $stream) { |
80
|
|
|
$cb($stream); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
return $this; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Handle all streams |
88
|
|
|
* |
89
|
|
|
* @param callable|PluginInterface $callback |
90
|
|
|
* |
91
|
|
|
* @return self |
92
|
|
|
*/ |
93
|
|
|
public function forStreams($callback) : self |
94
|
|
|
{ |
95
|
|
|
$cb = \Closure::bind($this->getCallback($callback), $this); |
96
|
|
|
|
97
|
|
|
if (count($this->toPush)) { |
98
|
|
|
$cb($this->toPush); |
99
|
|
|
|
100
|
|
|
return $this; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
$streams = array_map(function ($file) { |
104
|
|
|
return new Stream(fopen($file, 'r+')); |
105
|
|
|
}, $this->globs); |
106
|
|
|
|
107
|
|
|
$cb($streams); |
108
|
|
|
|
109
|
|
|
return $this; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
private function getCallback($cb) : callable |
113
|
|
|
{ |
114
|
|
|
if (!($cb instanceof PluginInterface) && !is_callable($cb)) { |
115
|
|
|
throw new \InvalidArgumentException('Invalid callback type: ' + gettype($cb)); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
if ($cb instanceof PluginInterface) { |
119
|
|
|
return $cb->getCallback(); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
return $cb; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Pushes a stream to be used on destination |
127
|
|
|
* |
128
|
|
|
* @param StreamInterface $stream |
129
|
|
|
*/ |
130
|
|
|
public function push(StreamInterface $stream) |
131
|
|
|
{ |
132
|
|
|
$this->toPush[] = $stream; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Creates a temporary stream |
137
|
|
|
* It will be deleted in the end of task execution |
138
|
|
|
* |
139
|
|
|
* @param StreamInterface $stream |
140
|
|
|
*/ |
141
|
|
|
public function temp(StreamInterface $stream) |
142
|
|
|
{ |
143
|
|
|
$this->push($stream); |
144
|
|
|
$this->temp[] = $stream->getMetadata('uri'); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Sends pushed streams to a directory (plugin) |
149
|
|
|
* |
150
|
|
|
* @param string $dest |
151
|
|
|
* |
152
|
|
|
* @return callable |
153
|
|
|
*/ |
154
|
|
|
public function toDir(string $dest) : ToDirPlugin |
155
|
|
|
{ |
156
|
|
|
return new ToDirPlugin($dest); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Cleans up pushed streams and delete indicated temporary files |
161
|
|
|
* |
162
|
|
|
* @return self |
163
|
|
|
*/ |
164
|
|
|
public function end() : self |
165
|
|
|
{ |
166
|
|
|
foreach ($this->toPush as $stream) { |
167
|
|
|
$stream->close(); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
foreach ($this->temp as $tempf) { |
171
|
|
|
unlink($tempf); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
$this->toPush = []; |
175
|
|
|
return $this; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
private function recoursiveGlob($pattern, $flags = 0) : array |
179
|
|
|
{ |
180
|
|
|
$globs = glob($pattern, $flags); |
181
|
|
|
$hasDir = false; |
182
|
|
|
|
183
|
|
|
foreach ($globs as $glob) { |
184
|
|
|
if (is_dir($glob)) { |
185
|
|
|
$hasDir = true; |
186
|
|
|
} |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
if (!$hasDir) { |
190
|
|
|
return $globs; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
foreach ( |
194
|
|
|
glob( |
195
|
|
|
dirname($pattern) . DIRECTORY_SEPARATOR . '*', |
196
|
|
|
GLOB_ONLYDIR | GLOB_NOSORT |
197
|
|
|
) |
198
|
|
|
as $dir |
199
|
|
|
) { |
200
|
|
|
$globs = array_merge( |
201
|
|
|
$globs, |
202
|
|
|
$this->recoursiveGlob( |
203
|
|
|
$dir . DIRECTORY_SEPARATOR . basename($pattern), $flags |
204
|
|
|
) |
205
|
|
|
); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
$globs = array_filter($globs, function ($res) { |
209
|
|
|
return !is_dir($res); |
210
|
|
|
}); |
211
|
|
|
|
212
|
|
|
return $globs; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Ignore files provided by glob function |
217
|
|
|
* |
218
|
|
|
* @param array $files |
219
|
|
|
* @param array|string $patterns |
220
|
|
|
* |
221
|
|
|
* @return array |
222
|
|
|
*/ |
223
|
|
|
private function ignoreFiles(array $files, $patterns) |
224
|
|
|
{ |
225
|
|
|
if ($patterns !== null) { |
226
|
|
|
$cbFilter = function () {return true;}; |
227
|
|
|
|
228
|
|
|
if (is_array($patterns) && count($patterns)) { |
229
|
|
|
$cbFilter = function ($glob) use ($patterns) { |
230
|
|
|
foreach ($patterns as $pattern) { |
231
|
|
|
if (preg_match($pattern, $glob)) { |
232
|
|
|
return false; |
233
|
|
|
} |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
return true; |
237
|
|
|
}; |
238
|
|
|
} elseif (is_string($patterns)) { |
239
|
|
|
$cbFilter = function ($glob) use ($patterns) { |
240
|
|
|
return !preg_match($patterns, $glob); |
241
|
|
|
}; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
$files = array_filter($files, $cbFilter); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
return $files; |
248
|
|
|
} |
249
|
|
|
} |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.