Completed
Push — master ( e8fccd...9c2126 )
by Harry
02:44
created

StreamTokeniser   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 15.79%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 10
c 2
b 1
f 0
lcom 1
cbo 3
dl 0
loc 87
ccs 6
cts 38
cp 0.1579
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
B getTokens() 0 34 6
A match() 0 10 3
1
<?php
2
3
namespace Graze\CsvToken\Tokeniser;
4
5
use Graze\CsvToken\Csv\CsvConfigurationInterface;
6
use Iterator;
7
use Psr\Http\Message\StreamInterface;
8
9
class StreamTokeniser implements TokeniserInterface
10
{
11
    use TypeBuilder;
12
13
    /** @var int[] */
14
    private $types;
15
    /** @var int */
16
    private $maxTypeLength;
17
    /** @var StreamInterface */
18
    private $stream;
19
20
    /**
21
     * Tokeniser constructor.
22
     *
23
     * @param CsvConfigurationInterface $config
24
     * @param StreamInterface           $stream
25
     */
26 17
    public function __construct(CsvConfigurationInterface $config, StreamInterface $stream)
27
    {
28 17
        $this->types = $this->getTypes($config);
29
30
        // sort by reverse key length
31 17
        uksort($this->types, function ($a, $b) {
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $a. Configured minimum length is 2.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $b. Configured minimum length is 2.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
32 17
            return strlen($b) - strlen($a);
33 17
        });
34 17
        $this->maxTypeLength = strlen(reset(array_keys($this->types)));
0 ignored issues
show
Bug introduced by
array_keys($this->types) cannot be passed to reset() as the parameter $array expects a reference.
Loading history...
35
        $this->stream = $stream;
36
    }
37
38
    /**
39
     * Loop through the stream, pulling maximum type length each time, find the largest type that matches and create a
40
     * token, then move on length characters
41
     *
42
     * @return Iterator
43
     */
44
    public function getTokens()
45
    {
46
        $this->stream->rewind();
47
        $position = $this->stream->tell();
48
        $buffer = $this->stream->read($this->maxTypeLength);
49
50
        /** @var Token $last */
51
        $last = null;
52
53
        while (strlen($buffer) > 0) {
54
            $token = $this->match($position, $buffer);
55
            $len = $token->getLength();
56
57
            // merge tokens together to condense T_CONTENT tokens
58
            if ($token->getType() == Token::T_CONTENT) {
59
                $last = (!is_null($last)) ? $last->addContent($token->getContent()) : $token;
60
            } else {
61
                if (!is_null($last)) {
62
                    yield $last;
63
                    $last = null;
64
                }
65
                yield $token;
66
            }
67
68
            $position += $len;
69
            $buffer = substr($buffer, $len) . $this->stream->read($len);
70
        }
71
72
        if (!is_null($last)) {
73
            yield $last;
74
        }
75
76
        $this->stream->close();
77
    }
78
79
    /**
80
     * @param int    $position
81
     * @param string $buffer
82
     *
83
     * @return Token
84
     */
85
    private function match($position, $buffer)
86
    {
87
        foreach ($this->types as $search => $tokenType) {
88
            if (substr($buffer, 0, strlen($search)) == $search) {
89
                return new Token($tokenType, $search, $position);
90
            }
91
        }
92
93
        return new Token(Token::T_CONTENT, $buffer[0], $position);
94
    }
95
}
96