Completed
Push — master ( aa33b2...c5ca8d )
by Gabriel
02:08
created

StreamHandler::temp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
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
    private $streams = [];
26
27
    /**
28
     * Provides streams by the pattern passed
29
     *
30
     * @param string|array      $accept
31
     * @param string|array|null $exclude
32
     *
33
     * @return self
34
     */
35
    public function src($accept, $exclude = null) : self
36
    {
37
        if ((!is_string($accept) && !is_array($accept)) || ($exclude !== null && !is_string($exclude) && !is_array($exclude))) {
38
            throw new \InvalidArgumentException('You can only pass a string pattern or array with patterns');
39
        }
40
41
        if (is_array($accept)) {
42
            $fileGroups = [];
43
44
            foreach ($accept as $pattern) {
45
                $fileGroups[] = $this->recoursiveGlob($pattern, GLOB_ERR);
46
            }
47
48
            $globs = call_user_func_array('array_merge', $fileGroups);
49
        } else {
50
            $globs = $this->recoursiveGlob($accept, GLOB_ERR);
51
        }
52
53
        $this->globs = $this->ignoreFiles($globs, $exclude);
54
55
        foreach ($this->globs as $glob) {
56
            $this->streams[] = new Stream(fopen($glob, 'r+'));
57
        }
58
59
        return $this;
60
    }
61
62
    /**
63
     * Handle each stream
64
     *
65
     * @param callable|PluginInterface $callback
66
     *
67
     * @return self
68
     */
69
    public function forStream($callback) : self
70
    {
71
        $cb = \Closure::bind($this->getCallback($callback), $this);
72
73
        if (count($this->toPush)) {
74
            foreach ($this->toPush as &$stream) {
75
                $cb($stream);
76
            }
77
78
            return $this;
79
        }
80
81
        foreach ($this->streams as &$stream) {
82
            $cb($stream);
83
        }
84
85
        return $this;
86
    }
87
88
    /**
89
     * Handle all streams
90
     *
91
     * @param callable|PluginInterface $callback
92
     *
93
     * @return self
94
     */
95
    public function forStreams($callback) : self
96
    {
97
        $cb = \Closure::bind($this->getCallback($callback), $this);
98
99
        if (count($this->toPush)) {
100
            $cb($this->toPush);
101
102
            return $this;
103
        }
104
105
        $cb($this->streams);
106
107
        return $this;
108
    }
109
110
    private function getCallback($cb) : callable
111
    {
112
        if (!($cb instanceof PluginInterface) && !is_callable($cb)) {
113
            throw new \InvalidArgumentException('Invalid callback type: ' + gettype($cb));
114
        }
115
116
        if ($cb instanceof PluginInterface) {
117
            return $cb->getCallback();
118
        }
119
120
        return $cb;
121
    }
122
123
    /**
124
     * Pushes a stream to be used on destination
125
     *
126
     * @param StreamInterface $stream
127
     */
128
    public function push(StreamInterface $stream)
129
    {
130
        $this->toPush[] = $stream;
131
    }
132
133
    /**
134
     * Creates a temporary stream
135
     * It will be deleted in the end of task execution
136
     *
137
     * @param StreamInterface $stream
138
     */
139
    public function temp(StreamInterface $stream)
140
    {
141
        $this->push($stream);
142
        $this->temp[] = $stream->getMetadata('uri');
143
    }
144
145
    /**
146
     * Sends pushed streams to a directory (plugin)
147
     *
148
     * @param string $dest
149
     *
150
     * @return callable
151
     */
152
    public function toDir(string $dest) : ToDirPlugin
153
    {
154
        return new ToDirPlugin($dest);
155
    }
156
157
    /**
158
     * Cleans up pushed streams and delete indicated temporary files
159
     *
160
     * @return self
161
     */
162
    public function end() : self
163
    {
164
        $this->closeAll();
165
166
        foreach ($this->temp as $tempf) {
167
            unlink($tempf);
168
        }
169
170
        $this->toPush = [];
171
        return $this;
172
    }
173
174
    /**
175
     * Destructor closes all opened streams
176
     */
177
    public function __destruct()
178
    {
179
        $this->closeAll();
180
    }
181
182
    private function recoursiveGlob($pattern, $flags = 0) : array
183
    {
184
        $globs = glob($pattern, $flags);
185
        $hasDir = false;
186
187
        foreach ($globs as $glob) {
188
            if (is_dir($glob)) {
189
                $hasDir = true;
190
            }
191
        }
192
193
        if (!$hasDir) {
194
            return $globs;
195
        }
196
197
        foreach (
198
            glob(
199
                dirname($pattern) . DIRECTORY_SEPARATOR . '*',
200
                GLOB_ONLYDIR | GLOB_NOSORT
201
            )
202
            as $dir
203
        ) {
204
            $globs = array_merge(
205
                $globs,
206
                $this->recoursiveGlob(
207
                    $dir . DIRECTORY_SEPARATOR . basename($pattern), $flags
208
                )
209
            );
210
        }
211
212
        $globs = array_filter($globs, function ($res) {
213
            return !is_dir($res);
214
        });
215
216
        return $globs;
217
    }
218
219
    /**
220
     * Ignore files provided by glob function
221
     *
222
     * @param array             $files
223
     * @param array|string|null $patterns
224
     *
225
     * @return array
226
     */
227
    private function ignoreFiles(array $files, $patterns)
228
    {
229
        if (null !== $patterns) {
230
            $cbFilter = function () {return true;};
231
232
            if (is_array($patterns)) {
233
                $cbFilter = function ($glob) use ($patterns) {
234
                    foreach ($patterns as $pattern) {
235
                        if (preg_match($pattern, $glob)) {
236
                            return false;
237
                        }
238
                    }
239
240
                    return true;
241
                };
242
            } elseif (is_string($patterns)) {
243
                $cbFilter = function ($glob) use ($patterns) {
244
                    return !preg_match($patterns, $glob);
245
                };
246
            }
247
248
            $files = array_filter($files, $cbFilter);
249
        }
250
251
        return $files;
252
    }
253
254
    /**
255
     * Closes all opened streams
256
     */
257
    private function closeAll()
258
    {
259
        foreach ($this->streams as $stream) {
260
            $stream->close();
261
        }
262
263
        foreach ($this->toPush as $stream) {
264
            $stream->close();
265
        }
266
    }
267
}