Completed
Push — master ( d12968...2a6550 )
by Harry
02:36
created

StreamTokeniser::match()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.4285
cc 3
eloc 5
nc 3
nop 2
crap 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 16
    public function __construct(CsvConfigurationInterface $config, StreamInterface $stream)
27
    {
28 16
        $this->types = $this->getTypes($config);
29
30
        // sort by reverse key length
31 16
        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 16
            return strlen($b) - strlen($a);
33 16
        });
34 16
        $this->maxTypeLength = count($this->types) > 0 ? strlen(array_keys($this->types)[0]) : 1;
35 16
        $this->stream = $stream;
36 16
    }
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 15
    public function getTokens()
45
    {
46 15
        $this->stream->rewind();
47 15
        $position = $this->stream->tell();
48 15
        $buffer = $this->stream->read($this->maxTypeLength);
49
50
        /** @var Token $last */
51 15
        $last = null;
52
53 15
        while (strlen($buffer) > 0) {
54 13
            $token = $this->match($position, $buffer);
55 13
            $len = $token->getLength();
56
57
            // merge tokens together to condense T_CONTENT tokens
58 13
            if ($token->getType() == Token::T_CONTENT) {
59 13
                $last = (!is_null($last)) ? $last->addContent($token->getContent()) : $token;
60 13
            } else {
61 12
                if (!is_null($last)) {
62 12
                    yield $last;
63 12
                    $last = null;
64 12
                }
65 12
                yield $token;
66
            }
67
68 13
            $position += $len;
69 13
            $buffer = substr($buffer, $len) . $this->stream->read($len);
70 13
        }
71
72 14
        if (!is_null($last)) {
73 4
            yield $last;
74 4
        }
75
76 14
        $this->stream->close();
77 14
    }
78
79
    /**
80
     * @param int    $position
81
     * @param string $buffer
82
     *
83
     * @return Token
84
     */
85 13
    private function match($position, $buffer)
86
    {
87 13
        foreach ($this->types as $search => $tokenType) {
88 13
            if (substr($buffer, 0, strlen($search)) == $search) {
89 12
                return new Token($tokenType, $search, $position);
90
            }
91 13
        }
92
93 13
        return new Token(Token::T_CONTENT, $buffer[0], $position);
94
    }
95
}
96