Completed
Pull Request — master (#15)
by Harry
04:28
created

CsvParser   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 56.52%

Importance

Changes 0
Metric Value
dl 0
loc 106
c 0
b 0
f 0
wmc 14
lcom 1
cbo 4
ccs 26
cts 46
cp 0.5652
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A parse() 0 8 1
A parseIterator() 0 12 3
A parseHeaderRow() 0 8 2
A handleHeaderRow() 0 10 4
A mapHeaders() 0 16 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\Format\Parser;
15
16
use ArrayIterator;
17
use CallbackFilterIterator;
18
use Graze\CsvToken\Parser;
19
use Graze\CsvToken\Tokeniser\StreamTokeniser;
20
use Graze\DataFile\Format\CsvFormatInterface;
21
use Graze\DataFile\Helper\MapIterator;
22
use Iterator;
23
use LimitIterator;
24
use Psr\Http\Message\StreamInterface;
25
use RuntimeException;
26
27
class CsvParser implements ParserInterface
28
{
29
    /** @var CsvFormatInterface */
30
    private $csvFormat;
31
    /** @var array */
32
    private $headerRow = [];
33
34
    /**
35
     * @param CsvFormatInterface $csvFormat
36
     */
37 13
    public function __construct(CsvFormatInterface $csvFormat)
38
    {
39 13
        $this->csvFormat = $csvFormat;
40 13
    }
41
42
    /**
43
     * @param StreamInterface $stream
44
     *
45
     * @return Iterator
46
     */
47 12
    public function parse(StreamInterface $stream)
48 1
    {
49 12
        $tokeniser = new StreamTokeniser($this->csvFormat, $stream);
0 ignored issues
show
Documentation introduced by
$stream is of type object<Psr\Http\Message\StreamInterface>, but the function expects a resource.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
50 12
        $parser = new Parser();
51 12
        return $this->parseIterator(
52 12
            $parser->parse($tokeniser->getTokens())
53 12
        );
54
    }
55
56
    /**
57
     * Parse a supplied iterator
58
     *
59
     * @param Iterator $iterator
60
     *
61
     * @return Iterator
62
     */
63 12
    private function parseIterator(Iterator $iterator)
64
    {
65 12
        $iterator = $this->parseHeaderRow($iterator);
66 12
        if ($this->csvFormat->getDataStart() > 1 || $this->csvFormat->getLimit() !== -1) {
67 6
            $iterator = new LimitIterator(
68 6
                $iterator,
69 6
                max(0, $this->csvFormat->getDataStart() - 1),
70 6
                $this->csvFormat->getLimit()
71 6
            );
72 6
        }
73 12
        return $iterator;
74
    }
75
76
    /**
77
     * @param Iterator $iterator
78
     *
79
     * @return Iterator
80
     */
81 12
    private function parseHeaderRow(Iterator $iterator)
82
    {
83 12
        if ($this->csvFormat->hasHeaderRow()) {
84 4
            $iterator = new CallbackFilterIterator($iterator, [$this, 'handleHeaderRow']);
85 4
            $iterator = new MapIterator($iterator, [$this, 'mapHeaders']);
86 4
        }
87 12
        return $iterator;
88
    }
89
90
    /**
91
     * Parse the rows looking for the header row and storing it locally
92
     *
93
     * @param ArrayIterator $current
94
     * @param int           $key
95
     *
96
     * @return bool
97
     */
98
    public function handleHeaderRow(ArrayIterator $current, $key)
99
    {
100
        if ($key == $this->csvFormat->getHeaderRow() - 1) {
101
            $arr = iterator_to_array($current);
102
            if (count($arr) > 1 || strlen($arr[0]) > 0) {
103
                $this->headerRow = $arr;
104
            }
105
        }
106
        return true;
107
    }
108
109
    /**
110
     * Map any headers found onto each element in the data
111
     *
112
     * @param ArrayIterator $current
113
     *
114
     * @return ArrayIterator
115
     */
116
    public function mapHeaders(ArrayIterator $current)
117
    {
118
        if (count($this->headerRow) > 0) {
119
            if (count($this->headerRow) !== $current->count()) {
120
                throw new RuntimeException(
121
                    "The number of entries in: " . implode(',', iterator_to_array($current)) .
122
                    " does not match the header: " . implode(',', $this->headerRow)
123
                );
124
            }
125
            return new ArrayIterator(array_combine(
126
                $this->headerRow,
127
                iterator_to_array($current)
128
            ));
129
        }
130
        return $current;
131
    }
132
}
133