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

StreamTokeniser   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 84
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 2 Features 0
Metric Value
wmc 10
c 5
b 2
f 0
lcom 1
cbo 6
dl 0
loc 84
rs 10
ccs 31
cts 31
cp 1

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
C getTokens() 0 41 7
A changeEncoding() 0 4 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 24
     *
39
     * @param CsvConfigurationInterface $config
40 24
     * @param StreamInterface           $stream
41 24
     */
42 24
    public function __construct(CsvConfigurationInterface $config, StreamInterface $stream)
43 24
    {
44 24
        $this->tokenStore = new TokenStore($config);
45
        $this->state = $this->buildStates($this->tokenStore);
46
        $types = $this->tokenStore->getTokens();
47
        $this->maxTypeLength = count($types) > 0 ? strlen(array_keys($types)[0]) : 1;
48
        $this->stream = $stream;
49
    }
50
51
    /**
52 23
     * 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 23
     *
55 23
     * @return Iterator
56 23
     */
57
    public function getTokens()
58
    {
59 23
        $this->stream->rewind();
60
        $position = $this->stream->tell();
61 23
        $buffer = $this->stream->read($this->maxTypeLength);
62 21
63 21
        /** @var Token $last */
64
        $last = null;
65 21
66
        while (strlen($buffer) > 0) {
67
            $token = $this->state->match($position, $buffer);
68 21
69 21
            if ($token->getType() == Token::T_BOM) {
70 21
                $this->changeEncoding($token);
71 20
            }
72 19
73 19
            $this->state = $this->state->getNextState($token->getType());
74 19
75 20
            $len = $token->getLength();
76
77
            // merge tokens together to condense T_CONTENT tokens
78 21
            if ($token->getType() == Token::T_CONTENT) {
79 21
                $last = (!is_null($last)) ? $last->addContent($token->getContent()) : $token;
80 21
            } else {
81
                if (!is_null($last)) {
82 22
                    yield $last;
83 7
                    $last = null;
84 7
                }
85
                yield $token;
86 22
            }
87 22
88
            $position += $len;
89
            $buffer = substr($buffer, $len) . $this->stream->read($len);
90
        }
91
92
        if (!is_null($last)) {
93
            yield $last;
94
        }
95
96
        $this->stream->close();
97
    }
98
99
    /**
100
     * @param Token $token
101
     */
102
    private function changeEncoding(Token $token)
103
    {
104
        $this->tokenStore->setEncoding(Bom::getEncoding($token->getContent()));
105
    }
106
}
107