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

RFC4180Iterator::getIterator()   C

Complexity

Conditions 13
Paths 15

Size

Total Lines 97

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 55
CRAP Score 13

Importance

Changes 0
Metric Value
cc 13
nc 15
nop 0
dl 0
loc 97
ccs 55
cts 55
cp 1
crap 13
rs 5.3587
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
28
/**
29
 * A RFC4180 Compliant Parser in Pure PHP.
30
 *
31
 * @see https://php.net/manual/en/function.fgetcsv.php
32
 * @see https://php.net/manual/en/function.fgetc.php
33
 * @see https://tools.ietf.org/html/rfc4180
34
 * @see http://edoceo.com/utilitas/csv-file-format
35
 *
36
 * @package League.csv
37
 * @since   9.2.0
38
 * @author  Ignace Nyamagana Butera <[email protected]>
39
 * @internal used internally to produce RFC4180 compliant records
40
 */
41
final class RFC4180Iterator implements IteratorAggregate
42
{
43
    /**
44
     * The CSV document.
45
     *
46
     * @var SplFileObject|Stream
47
     */
48
    private $document;
49
50
    /**
51
     * New instance.
52
     *
53
     * @param SplFileObject|Stream $document
54
     */
55 9
    public function __construct($document)
56
    {
57 9
        if (!$document instanceof Stream && !$document instanceof SplFileObject) {
58 3
            throw new TypeError(sprintf(
59 3
                'Expected a %s or an SplFileObject object, % given',
60 3
                Stream::class,
61 3
                is_object($document) ? get_class($document) : gettype($document)
62
            ));
63
        }
64
65 6
        $this->document = $document;
66 6
    }
67
68
    /**
69
     * @inheritdoc
70
     *
71
     * Converts the stream into a CSV record iterator
72
     */
73 12
    public function getIterator()
74
    {
75
        //initialisation
76 12
        $record = [];
77 12
        $buffer = null;
78 12
        $previous_char = '';
79 12
        $enclosed_field = false;
80 12
        list($delimiter, $enclosure, ) = $this->document->getCsvControl();
81 12
        $this->document->rewind();
82
83
        //let's walk through the stream char by char
84 12
        while (false !== ($char = $this->document->fgetc())) {
85
            switch ($char) {
86 12
                case $enclosure:
87 12
                    if (!$enclosed_field) {
88
                        //the enclosure is at the start of the record
89
                        //so we have an enclosed field
90 12
                        if (null === $buffer) {
91 12
                            $enclosed_field = true;
92 12
                            break;
93
                        }
94
                        //invalid CSV content let's deal with it like fgetcsv
95
                        //we add the character to the buffer and we move on
96 6
                        $previous_char = $char;
97 6
                        $buffer .= $char;
98 6
                        break;
99
                    }
100
                    //double quoted enclosure let's skip the character and move on
101 12
                    if ($previous_char === $enclosure) {
102
                        //we reset the previous character
103
                        //to avoid stripping to much enclosure character
104 6
                        $previous_char = '';
105 6
                        break;
106
                    }
107 12
                    $previous_char = $char;
108 12
                    $buffer .= $char;
109 12
                    break;
110 12
                case $delimiter:
111 12
                    if ($enclosed_field) {
112
                        //the delimiter is enclosed let's add it to the buffer and move on
113 12
                        if ($previous_char !== $enclosure) {
114 6
                            $buffer .= $char;
115 6
                            $previous_char = $char;
116 6
                            break;
117
                        }
118
                        //strip the enclosure character present at the
119
                        //end of the buffer; this is the end of en enclosed field
120 12
                        $buffer = substr($buffer, 0, -1);
121
                    }
122
123
                    //the buffer is the field content we add it to the record
124
                    //and convert it into a string
125 12
                    $record[] = ''.$buffer;
126
127
                    //reset field parameters
128 12
                    $buffer = null;
129 12
                    $previous_char = '';
130 12
                    $enclosed_field = false;
131 12
                    break;
132 12
                case "\n":
133 12
                case "\r":
134 12
                    if ($enclosed_field) {
135
                        //the line break is enclosed let's add it to the buffer and move on
136 12
                        if ($previous_char !== $enclosure) {
137 6
                            $previous_char = $char;
138 6
                            $buffer .= $char;
139 6
                            break;
140
                        }
141
                        //strip the enclosure character present at the
142
                        //end of the buffer; this is the end of a record
143 6
                        $buffer = substr($buffer, 0, -1);
144
                    }
145
146
                    //adding field content to the record
147 12
                    $record[] = $buffer;
148
                    //reset field parameters
149 12
                    $buffer = null;
150 12
                    $enclosed_field = false;
151 12
                    $previous_char = '';
152
153
                    //yield the record
154 12
                    yield $record;
155
156
                    //reset record
157 12
                    $record = [];
158 12
                    break;
159
                default:
160 12
                    $previous_char = $char;
161 12
                    $buffer .= $char;
162 12
                    break;
163
            }
164
        }
165 12
        $record[] = $buffer;
166
167
        //yield remaining record
168 12
        yield $record;
169 12
    }
170
}
171