Completed
Pull Request — master (#7)
by Harry
02:41
created

StreamTokeniser::changeEncoding()   A

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 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
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/csv-token
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/csv-token/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/csv-token
12
 */
13
14
namespace Graze\CsvToken\Tokeniser;
15
16
use Graze\CsvToken\Csv\Bom;
17
use Graze\CsvToken\Csv\CsvConfigurationInterface;
18
use Graze\CsvToken\Tokeniser\Token\Token;
19
use Graze\CsvToken\Tokeniser\Token\TokenStore;
20
use Iterator;
21
use Psr\Http\Message\StreamInterface;
22
23
class StreamTokeniser implements TokeniserInterface
24
{
25
    use StateBuilder;
26
27
    /** @var int */
28
    private $maxTypeLength;
29
    /** @var StreamInterface */
30
    private $stream;
31
    /** @var State */
32
    private $state;
33
    /** @var TokenStore */
34
    private $tokenStore;
35
36
    /**
37
     * Tokeniser constructor.
38
     *
39
     * @param CsvConfigurationInterface $config
40
     * @param StreamInterface           $stream
41
     */
42 28
    public function __construct(CsvConfigurationInterface $config, StreamInterface $stream)
43
    {
44 28
        $this->tokenStore = new TokenStore($config);
45 28
        $this->state = $this->buildStates($this->tokenStore);
46 28
        $types = $this->tokenStore->getTokens();
47 28
        $this->maxTypeLength = count($types) > 0 ? strlen(array_keys($types)[0]) : 1;
48 28
        $this->stream = $stream;
49 28
    }
50
51
    /**
52
     * Loop through the stream, pulling maximum type length each time, find the largest type that matches and create a
53
     * token, then move on length characters
54
     *
55
     * @return Iterator
56
     */
57 27
    public function getTokens()
58
    {
59 27
        $this->stream->rewind();
60 27
        $position = $this->stream->tell();
61 27
        $buffer = $this->stream->read($this->maxTypeLength);
62
63
        /** @var Token $last */
64 27
        $last = null;
65
66 27
        while (strlen($buffer) > 0) {
67 25
            $token = $this->state->match($position, $buffer);
68
69 25
            if ($token->getType() == Token::T_BOM) {
70 3
                $this->changeEncoding($token);
71 3
            }
72
73 25
            $this->state = $this->state->getNextState($token->getType());
74
75 25
            $len = $token->getLength();
76
77
            // merge tokens together to condense T_CONTENT tokens
78 25
            if ($token->getType() == Token::T_CONTENT) {
79 25
                $last = (!is_null($last)) ? $last->addContent($token->getContent()) : $token;
80 25
            } else {
81 24
                if (!is_null($last)) {
82 23
                    yield $last;
83 23
                    $last = null;
84 23
                }
85 24
                yield $token;
86
            }
87
88 25
            $position += $len;
89 25
            $buffer = substr($buffer, $len) . $this->stream->read($len);
90 25
        }
91
92 26
        if (!is_null($last)) {
93 7
            yield $last;
94 7
        }
95
96 26
        $this->stream->close();
97 26
    }
98
99
    /**
100
     * @param Token $token
101
     */
102 3
    private function changeEncoding(Token $token)
103
    {
104 3
        $this->tokenStore->setEncoding(Bom::getEncoding($token->getContent()));
105 3
    }
106
}
107