CsvParser::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
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\Format\Parser;
15
16
use CallbackFilterIterator;
17
use Graze\CsvToken\Parser;
18
use Graze\CsvToken\Tokeniser\StreamTokeniser;
19
use Graze\DataFile\Format\CsvFormatInterface;
20
use Graze\DataFile\Helper\MapIterator;
21
use Iterator;
22
use LimitIterator;
23
use RuntimeException;
24
25
class CsvParser implements ParserInterface
26
{
27
    /** @var CsvFormatInterface */
28
    private $csvFormat;
29
    /** @var array */
30
    private $headerRow = [];
31
32
    /**
33
     * @param CsvFormatInterface $csvFormat
34
     */
35 13
    public function __construct(CsvFormatInterface $csvFormat)
36
    {
37 13
        $this->csvFormat = $csvFormat;
38 13
    }
39
40
    /**
41
     * @param resource $stream
42
     *
43
     * @return Iterator
44
     */
45 12
    public function parse($stream)
46
    {
47 12
        $tokeniser = new StreamTokeniser($this->csvFormat, $stream);
48 12
        $parser = new Parser();
49 12
        return $this->parseIterator(
50 12
            $parser->parse($tokeniser->getTokens())
51
        );
52
    }
53
54
    /**
55
     * Parse a supplied iterator
56
     *
57
     * @param Iterator $iterator
58
     *
59
     * @return Iterator
60
     */
61 12
    private function parseIterator(Iterator $iterator)
62
    {
63 12
        $iterator = $this->parseHeaderRow($iterator);
64 12
        if ($this->csvFormat->getDataStart() > 1 || $this->csvFormat->getLimit() !== -1) {
65 6
            $iterator = new LimitIterator(
66
                $iterator,
67 6
                max(0, $this->csvFormat->getDataStart() - 1),
68 6
                $this->csvFormat->getLimit()
69
            );
70
        }
71 12
        return $iterator;
72
    }
73
74
    /**
75
     * @param Iterator $iterator
76
     *
77
     * @return Iterator
78
     */
79 12
    private function parseHeaderRow(Iterator $iterator)
80
    {
81 12
        if ($this->csvFormat->hasHeaderRow()) {
82 4
            $iterator = new CallbackFilterIterator($iterator, [$this, 'handleHeaderRow']);
83 4
            $iterator = new MapIterator($iterator, [$this, 'mapHeaders']);
84
        }
85 12
        return $iterator;
86
    }
87
88
    /**
89
     * Parse the rows looking for the header row and storing it locally
90
     *
91
     * @param array $current
92
     * @param int   $key
93
     *
94
     * @return bool
95
     */
96 4
    public function handleHeaderRow(array $current, $key)
97
    {
98 4
        if ($key == $this->csvFormat->getHeaderRow() - 1) {
99 4
            if (count($current) > 1 || strlen($current[0]) > 0) {
100 3
                $this->headerRow = $current;
101
            }
102
        }
103 4
        return true;
104
    }
105
106
    /**
107
     * Map any headers found onto each element in the data
108
     *
109
     * @param array $current
110
     *
111
     * @return array
112
     */
113 4
    public function mapHeaders(array $current)
114
    {
115 4
        if (count($this->headerRow) > 0) {
116 3
            if (count($this->headerRow) !== count($current)) {
117 1
                throw new RuntimeException(
118 1
                    "The number of entries in: " . implode(',', $current) .
119 1
                    " does not match the header: " . implode(',', $this->headerRow)
120
                );
121
            }
122 2
            return array_combine(
123 2
                $this->headerRow,
124
                $current
125
            );
126
        }
127 1
        return $current;
128
    }
129
}
130