Completed
Pull Request — master (#309)
by ignace nyamagana
02:04
created

RFC4180Iterator::getIterator()   F

Complexity

Conditions 20
Paths 84

Size

Total Lines 119

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 65
CRAP Score 20

Importance

Changes 0
Metric Value
cc 20
nc 84
nop 0
dl 0
loc 119
ccs 65
cts 65
cp 1
crap 20
rs 3.3333
c 0
b 0
f 0

How to fix   Long Method    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
/**
4
 * League.Csv (https://csv.thephpleague.com).
5
 *
6
 * @author  Ignace Nyamagana Butera <[email protected]>
7
 * @license https://github.com/thephpleague/csv/blob/master/LICENSE (MIT License)
8
 * @version 9.1.5
9
 * @link    https://github.com/thephpleague/csv
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
declare(strict_types=1);
16
17
namespace League\Csv;
18
19
use IteratorAggregate;
20
use SplFileObject;
21
use TypeError;
22
use function get_class;
23
use function gettype;
24
use function is_object;
25
use function sprintf;
26
use function substr;
27
use function trim;
28
29
/**
30
 * A RFC4180 Compliant Parser in Pure PHP.
31
 *
32
 * @see https://php.net/manual/en/function.fgetcsv.php
33
 * @see https://php.net/manual/en/function.fgetc.php
34
 * @see https://tools.ietf.org/html/rfc4180
35
 * @see http://edoceo.com/utilitas/csv-file-format
36
 *
37
 * @package League.csv
38
 * @since   9.2.0
39
 * @author  Ignace Nyamagana Butera <[email protected]>
40
 * @internal used internally to produce RFC4180 compliant records
41
 */
42
final class RFC4180Iterator implements IteratorAggregate
43
{
44
    /**
45
     * The CSV document.
46
     *
47
     * @var SplFileObject|Stream
48
     */
49
    private $document;
50
51
    /**
52
     * New instance.
53
     *
54
     * @param SplFileObject|Stream $document
55
     */
56 9
    public function __construct($document)
57
    {
58 9
        if (!$document instanceof Stream && !$document instanceof SplFileObject) {
59 3
            throw new TypeError(sprintf(
60 3
                'Expected a %s or an SplFileObject object, % given',
61 3
                Stream::class,
62 3
                is_object($document) ? get_class($document) : gettype($document)
63
            ));
64
        }
65
66 6
        $this->document = $document;
67 6
    }
68
69
    /**
70
     * @inheritdoc
71
     *
72
     * Converts the stream into a CSV record iterator
73
     */
74 12
    public function getIterator()
75
    {
76
        //initialisation
77 12
        $record = [];
78 12
        $buffer = null;
79 12
        $previous_char = '';
80 12
        $enclosed_field = false;
81 12
        list($delimiter, $enclosure, ) = $this->document->getCsvControl();
82 12
        $trim_mask = str_replace([$delimiter, $enclosure], '', " \t\0\x0B");
83 12
        $this->document->rewind();
84
85
        //let's walk through the stream char by char
86 12
        while (false !== ($char = $this->document->fgetc())) {
87
            switch ($char) {
88 12
                case $enclosure:
89 12
                    if (!$enclosed_field) {
90
                        //the enclosure is at the start of the record
91
                        //so we have an enclosed field
92 12
                        if (null === $buffer) {
93 12
                            $enclosed_field = true;
94 12
                            break;
95
                        }
96
                        //invalid CSV content let's deal with it like fgetcsv
97
                        //we add the character to the buffer and we move on
98 3
                        $previous_char = $char;
99 3
                        $buffer .= $char;
100 3
                        break;
101
                    }
102
                    //double quoted enclosure let's skip the character and move on
103 12
                    if ($previous_char === $enclosure) {
104
                        //we reset the previous character
105
                        //to avoid stripping to much enclosure character
106 3
                        $previous_char = '';
107 3
                        break;
108
                    }
109 12
                    $previous_char = $char;
110 12
                    $buffer .= $char;
111 12
                    break;
112 12
                case $delimiter:
113 12
                    if ($enclosed_field) {
114
                        //the delimiter is enclosed let's add it to the buffer and move on
115 12
                        if ($previous_char !== $enclosure) {
116 9
                            $buffer .= $char;
117 9
                            $previous_char = $char;
118 9
                            break;
119
                        }
120
                        //strip the enclosure character present at the
121
                        //end of the buffer; this is the end of en enclosed field
122 12
                        $buffer = substr($buffer, 0, -1);
123
                    }
124
125
                    //the buffer is the field content we add it to the record
126
                    //and convert it into a string
127 12
                    $buffer = ''.$buffer;
128
                    //if the field is not enclose we trim white spaces
129 12
                    if (!$enclosed_field) {
130 9
                        $buffer = trim($buffer, $trim_mask);
131
                    }
132 12
                    $record[] = $buffer;
133
134
                    //reset field parameters
135 12
                    $buffer = null;
136 12
                    $previous_char = '';
137 12
                    $enclosed_field = false;
138 12
                    break;
139 12
                case "\n":
140 12
                case "\r":
141 12
                    if ($enclosed_field) {
142
                        //the line break is enclosed let's add it to the buffer and move on
143 6
                        if ($previous_char !== $enclosure) {
144 3
                            $previous_char = $char;
145 3
                            $buffer .= $char;
146 3
                            break;
147
                        }
148
                        //strip the enclosure character present at the
149
                        //end of the buffer; this is the end of a record
150 3
                        $buffer = substr($buffer, 0, -1);
151
                    }
152
153
                    //if the field is not enclose we trim white spaces
154 12
                    if (null !== $buffer && !$enclosed_field) {
155 9
                        $buffer = trim($buffer, $trim_mask);
156
                    }
157
                    //adding field content to the record
158 12
                    $record[] = $buffer;
159
                    //reset field parameters
160 12
                    $buffer = null;
161 12
                    $enclosed_field = false;
162 12
                    $previous_char = '';
163
164
                    //yield the record
165 12
                    yield $record;
166
167
                    //reset record
168 12
                    $record = [];
169 12
                    break;
170
                default:
171 12
                    $previous_char = $char;
172 12
                    $buffer .= $char;
173 12
                    break;
174
            }
175
        }
176
177
        //yield the remaining buffer
178 12
        if ($enclosed_field && $enclosure === substr($buffer, -1, 1)) {
179
            //strip the enclosure character present at the
180
            //end of the buffer; this is the end of en enclosed field
181 3
            $buffer = substr($buffer, 0, -1);
182
        }
183
184
        //if the field is not enclose we trim white spaces
185 12
        if (!$enclosed_field && null !== $buffer) {
186 9
            $buffer = trim($buffer, $trim_mask);
187
        }
188
189 12
        $record[] = $buffer;
190
191 12
        yield $record;
192 12
    }
193
}
194