Completed
Push — master ( d97897...85851c )
by Harry
03:38
created

LineStreamIterator::isBlankBuffer()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 3
eloc 2
nc 3
nop 1
crap 3
1
<?php
2
/**
3
 * This file is part of graze/data-file
4
 *
5
 * Copyright (c) 2016 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/data-file/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/data-file
12
 */
13
14
namespace Graze\DataFile\Helper;
15
16
use Iterator;
17
use Psr\Http\Message\StreamInterface;
18
19
class LineStreamIterator implements Iterator
20
{
21
    use GetOptionTrait;
22
23
    const OPTION_ENDING         = 'ending';
24
    const OPTION_IGNORE_BLANK   = 'ignoreBlank';
25
    const OPTION_INCLUDE_ENDING = 'includeEnding';
26
27
    const DEFAULT_ENDING         = PHP_EOL;
28
    const DEFAULT_IGNORE_BLANK   = true;
29
    const DEFAULT_INCLUDE_ENDING = false;
30
31
    /** @var string */
32
    private $ending;
33
    /** @var int */
34
    private $position = 0;
35
    /** @var string|bool */
36
    private $current;
37
    /** @var bool */
38
    private $ignoreBlank = true;
39
    /** @var StreamInterface */
40
    private $stream;
41
    /** @var bool */
42
    private $includeEnding;
43
44
    /**
45
     * LineStreamIterator constructor.
46
     *
47
     * @param StreamInterface $stream
48
     * @param array           $options
49
     */
50 9
    public function __construct(StreamInterface $stream, array $options = [])
51
    {
52 9
        $this->stream = $stream;
53 9
        $this->options = $options;
54 9
        $this->ending = $this->getOption(static::OPTION_ENDING, static::DEFAULT_ENDING);
55 9
        $this->ignoreBlank = $this->getOption(static::OPTION_IGNORE_BLANK, static::DEFAULT_IGNORE_BLANK);
56 9
        $this->includeEnding = $this->getOption(static::OPTION_INCLUDE_ENDING, static::DEFAULT_INCLUDE_ENDING);
57 9
    }
58
59
    /**
60
     * @param bool $ignore
61
     *
62
     * @return $this
63
     */
64 4
    public function setIgnoreBlank($ignore)
65
    {
66 4
        $this->ignoreBlank = $ignore;
67 4
        return $this;
68
    }
69
70
    /**
71
     * Return the current element
72
     *
73
     * @link  http://php.net/manual/en/iterator.current.php
74
     * @return mixed Can return any type.
75
     * @since 5.0.0
76
     */
77 6
    public function current()
78
    {
79 6
        return $this->current;
80
    }
81
82
    /**
83
     * Move forward to next element
84
     *
85
     * @link  http://php.net/manual/en/iterator.next.php
86
     * @since 5.0.0
87
     */
88 6
    public function next()
89
    {
90 6
        if ($this->readStream()) {
91 6
            $this->position++;
92
        }
93 6
    }
94
95
    /**
96
     * @param string $ending
97
     *
98
     * @return string
99
     */
100 6
    private function readStreamTill($ending)
101
    {
102 6
        $buffer = '';
103 6
        $len = strlen($ending);
104
        do {
105 6
            $char = $this->stream->read(1);
106 6
            $buffer .= $char;
107 6
        } while ($char && substr($buffer, $len * -1) != $ending && !$this->stream->eof());
108 6
        return $buffer;
109
    }
110
111
    /**
112
     * @return bool
113
     */
114 6
    private function readStream()
115
    {
116 6
        if ($this->stream->eof()) {
117 5
            $this->current = false;
118 5
            return false;
119
        } else {
120 6
            $buffer = $this->readStreamTill($this->ending);
121
122 6
            if ($this->isBlankBuffer($buffer)) {
123 1
                return $this->readStream();
124
            } else {
125 6
                $this->stripEnding($buffer);
126 6
                $this->current = $buffer;
127 6
                return true;
128
            }
129
        }
130
    }
131
132
    /**
133
     * @param string $buffer Reference as we want speed here!
134
     *
135
     * @return bool
136
     */
137 6
    private function isBlankBuffer(&$buffer)
138
    {
139 6
        return (($buffer == '' || $buffer == $this->ending) && $this->ignoreBlank);
140
    }
141
142
    /**
143
     * @param string $buffer Reference as we want speed here!
144
     */
145 6
    private function stripEnding(&$buffer)
146
    {
147 6
        $len = strlen($this->ending) * -1;
148 6
        if (!$this->includeEnding && substr($buffer, $len) == $this->ending) {
149 5
            $buffer = substr($buffer, 0, $len);
150
        }
151 6
    }
152
153
    /**
154
     * Return the key of the current element
155
     *
156
     * @link  http://php.net/manual/en/iterator.key.php
157
     * @return mixed scalar on success, or null on failure.
158
     * @since 5.0.0
159
     */
160 6
    public function key()
161
    {
162 6
        return $this->position;
163
    }
164
165
    /**
166
     * Checks if current position is valid
167
     *
168
     * @link  http://php.net/manual/en/iterator.valid.php
169
     * @return bool The return value will be casted to boolean and then evaluated.
170
     *        Returns true on success or false on failure.
171
     * @since 5.0.0
172
     */
173 5
    public function valid()
174
    {
175 5
        return $this->current !== false;
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181 6
    public function rewind()
182
    {
183 6
        $this->position = 0;
184 6
        $this->stream->seek(0);
185 6
        $this->readStream();
186 6
    }
187
188
    /**
189
     * @return bool
190
     */
191 3
    public function isIgnoreBlank()
192
    {
193 3
        return $this->ignoreBlank;
194
    }
195
196
    /**
197
     * @return bool
198
     */
199 3
    public function isIncludeEnding()
200
    {
201 3
        return $this->includeEnding;
202
    }
203
204
    /**
205
     * @param bool $includeEnding
206
     *
207
     * @return $this
208
     */
209 1
    public function setIncludeEnding($includeEnding)
210
    {
211 1
        $this->includeEnding = $includeEnding;
212 1
        return $this;
213
    }
214
215
    /**
216
     * @param string $ending
217
     *
218
     * @return $this
219
     */
220 1
    public function setEnding($ending)
221
    {
222 1
        $this->ending = $ending;
223 1
        return $this;
224
    }
225
226
    /**
227
     * @return string
228
     */
229 3
    public function getEnding()
230
    {
231 3
        return $this->ending;
232
    }
233
}
234