Completed
Pull Request — master (#3)
by Harry
03:17
created

LineStreamIterator::readStreamTill()   C

Complexity

Conditions 10
Paths 4

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
ccs 16
cts 16
cp 1
rs 5.2164
cc 10
eloc 18
nc 4
nop 1
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 */
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->readStreamTill($this->ending)) {
91 6
            $this->position++;
92 6
        }
93 6
    }
94
95
    /**
96
     * @param string $ending
97
     *
98
     * @return bool
99
     */
100 6
    private function readStreamTill($ending)
101
    {
102 6
        if ($this->stream->eof()) {
103 5
            $this->current = false;
0 ignored issues
show
Documentation Bug introduced by
The property $current was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
104 5
            return false;
105
        } else {
106 6
            $len = strlen($ending);
107 6
            $buffer = '';
108
            do {
109 6
                $char = $this->stream->read(1);
110 6
                $buffer .= $char;
111 6
            } while ($char && substr($buffer, $len * -1) != $ending && !$this->stream->eof());
112
113 6
            if (($buffer == '' || $buffer == $ending) && $this->ignoreBlank) {
114 1
                return $this->readStreamTill($ending);
115
            } else {
116 6
                if (!$this->includeEnding && substr($buffer, $len * -1) == $ending) {
117 5
                    $buffer = substr($buffer, 0, $len * -1);
118 5
                }
119 6
                $this->current = $buffer;
120 6
                return true;
121
            }
122
        }
123
    }
124
125
    /**
126
     * Return the key of the current element
127
     *
128
     * @link  http://php.net/manual/en/iterator.key.php
129
     * @return mixed scalar on success, or null on failure.
130
     * @since 5.0.0
131
     */
132 6
    public function key()
133
    {
134 6
        return $this->position;
135
    }
136
137
    /**
138
     * Checks if current position is valid
139
     *
140
     * @link  http://php.net/manual/en/iterator.valid.php
141
     * @return bool The return value will be casted to boolean and then evaluated.
142
     *        Returns true on success or false on failure.
143
     * @since 5.0.0
144
     */
145 5
    public function valid()
146
    {
147 5
        return $this->current !== false;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 6
    public function rewind()
154
    {
155 6
        $this->position = 0;
156 6
        $this->stream->seek(0);
157 6
        $this->readStreamTill($this->ending);
158 6
    }
159
160
    /**
161
     * @return bool
162
     */
163 3
    public function isIgnoreBlank()
164
    {
165 3
        return $this->ignoreBlank;
166
    }
167
168
    /**
169
     * @return bool
170
     */
171 3
    public function isIncludeEnding()
172
    {
173 3
        return $this->includeEnding;
174
    }
175
176
    /**
177
     * @param bool $includeEnding
178
     *
179
     * @return $this
180
     */
181 1
    public function setIncludeEnding($includeEnding)
182
    {
183 1
        $this->includeEnding = $includeEnding;
184 1
        return $this;
185
    }
186
187
    /**
188
     * @param string $ending
189
     *
190
     * @return $this
191
     */
192 1
    public function setEnding($ending)
193
    {
194 1
        $this->ending = $ending;
195 1
        return $this;
196
    }
197
198
    /**
199
     * @return string
200
     */
201 3
    public function getEnding()
202
    {
203 3
        return $this->ending;
204
    }
205
}
206