LineStreamIterator::current()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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