Passed
Pull Request — master (#315)
by Théo
02:34
created

ToString   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 34
eloc 86
dl 0
loc 238
rs 9.68
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A reset() 0 7 1
B postIndent() 0 34 10
A setBreakChar() 0 5 1
A setIndentChar() 0 5 1
A handle() 0 17 3
C preIndent() 0 32 12
A useColonSpace() 0 5 1
A indent() 0 10 4
A setIndentSize() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Annotation\Convert;
16
17
use Doctrine\Common\Annotations\DocLexer;
18
use KevinGH\Box\Annotation\Tokens;
19
20
/**
21
 * Converts a series of tokens into a string representation.
22
 *
23
 * @author Kevin Herrera <[email protected]>
24
 */
25
class ToString extends AbstractConvert
26
{
27
    /**
28
     * The line break character(s).
29
     *
30
     * @var string
31
     */
32
    private $break = "\n";
33
34
    /**
35
     * The indentation character.
36
     *
37
     * @var string
38
     */
39
    private $char = ' ';
40
41
    /**
42
     * The current indentation level.
43
     *
44
     * @var int
45
     */
46
    private $level;
47
48
    /**
49
     * The flag used to add a space after a colon (assignment).
50
     *
51
     * @var bool
52
     */
53
    private $space = false;
54
55
    /**
56
     * The token to character map.
57
     *
58
     * @var array
59
     */
60
    private static $map = [
61
        DocLexer::T_AT => '@',
62
        DocLexer::T_CLOSE_CURLY_BRACES => '}',
63
        DocLexer::T_CLOSE_PARENTHESIS => ')',
64
        DocLexer::T_COLON => ':',
65
        DocLexer::T_COMMA => ',',
66
        DocLexer::T_EQUALS => '=',
67
        DocLexer::T_NAMESPACE_SEPARATOR => '\\',
68
        DocLexer::T_OPEN_CURLY_BRACES => '{',
69
        DocLexer::T_OPEN_PARENTHESIS => '(',
70
    ];
71
72
    /**
73
     * The indentation size.
74
     *
75
     * @var int
76
     */
77
    private $size = 0;
78
79
    /**
80
     * Sets the line break character(s) used for indentation.
81
     *
82
     * @param string $break the character(s)
83
     *
84
     * @return ToString the converter
85
     */
86
    public function setBreakChar($break): self
87
    {
88
        $this->break = $break;
89
90
        return $this;
91
    }
92
93
    /**
94
     * Sets the repeated indentation character.
95
     *
96
     * @param string $char the character
97
     *
98
     * @return ToString the converter
99
     */
100
    public function setIndentChar($char): self
101
    {
102
        $this->char = $char;
103
104
        return $this;
105
    }
106
107
    /**
108
     * Sets the size of the indentation.
109
     *
110
     * @param int $size the size
111
     *
112
     * @return ToString the converter
113
     */
114
    public function setIndentSize($size): self
115
    {
116
        $this->size = $size;
117
118
        return $this;
119
    }
120
121
    /**
122
     * Sets the flag that determines if a space is added after a colon.
123
     *
124
     * @param bool $space Add the space?
125
     *
126
     * @return ToString the converter
127
     */
128
    public function useColonSpace($space): self
129
    {
130
        $this->space = $space;
131
132
        return $this;
133
    }
134
135
    /**
136
     * Processes the current token.
137
     */
138
    protected function handle(): void
139
    {
140
        $token = $this->tokens->current();
141
142
        $this->preIndent();
143
144
        if (isset(self::$map[$token[0]])) {
145
            $this->result .= self::$map[$token[0]];
146
        } else {
147
            if (DocLexer::T_STRING === $token[0]) {
148
                $this->result .= '"'.$token[1].'"';
149
            } else {
150
                $this->result .= $token[1];
151
            }
152
        }
153
154
        $this->postIndent();
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    protected function reset(Tokens $tokens): void
161
    {
162
        $this->level = 0;
163
        $this->result = '';
164
        $this->tokens = $tokens;
165
166
        $tokens->rewind();
167
    }
168
169
    /**
170
     * Adds indentation to the result.
171
     *
172
     * @param bool $force Force add a line break?
173
     */
174
    private function indent($force = false): void
175
    {
176
        if ($this->size || $force) {
177
            $this->result .= $this->break;
178
        }
179
180
        if ($this->size) {
181
            $this->result .= str_repeat(
182
                $this->char,
183
                $this->size * $this->level
184
            );
185
        }
186
    }
187
188
    /**
189
     * Handles indentation after the current token.
190
     */
191
    private function postIndent(): void
192
    {
193
        $next = $this->tokens->getId($this->tokens->key() + 1);
194
195
        switch ($this->tokens->getId()) {
196
            case DocLexer::T_COLON:
197
                if ($this->space) {
198
                    $this->result .= ' ';
199
                }
200
201
                break;
202
            case DocLexer::T_COMMA:
203
                if ((DocLexer::T_CLOSE_CURLY_BRACES !== $next)
204
                    && (DocLexer::T_CLOSE_PARENTHESIS !== $next)) {
205
                    $this->indent();
206
                }
207
208
                break;
209
            case DocLexer::T_OPEN_CURLY_BRACES:
210
                $this->level++;
211
212
                if (DocLexer::T_CLOSE_CURLY_BRACES !== $next) {
213
                    $this->indent();
214
                }
215
216
                break;
217
            case DocLexer::T_OPEN_PARENTHESIS:
218
                $this->level++;
219
220
                if (DocLexer::T_CLOSE_PARENTHESIS !== $next) {
221
                    $this->indent();
222
                }
223
224
                break;
225
        }
226
    }
227
228
    /**
229
     * Handles indentation before the current token.
230
     */
231
    private function preIndent(): void
232
    {
233
        $prev = $this->tokens->getId($this->tokens->key() - 1);
234
235
        switch ($this->tokens->getId()) {
236
            case DocLexer::T_AT:
237
                if ($prev
0 ignored issues
show
Bug Best Practice introduced by
The expression $prev of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
238
                    && (DocLexer::T_COLON !== $prev)
239
                    && (DocLexer::T_COMMA !== $prev)
240
                    && (DocLexer::T_EQUALS !== $prev)
241
                    && (DocLexer::T_OPEN_CURLY_BRACES !== $prev)
242
                    && (DocLexer::T_OPEN_PARENTHESIS !== $prev)) {
243
                    $this->indent(true);
244
                }
245
246
                break;
247
            case DocLexer::T_CLOSE_CURLY_BRACES:
248
                $this->level--;
249
250
                if (DocLexer::T_OPEN_CURLY_BRACES !== $prev) {
251
                    $this->indent();
252
                }
253
254
                break;
255
            case DocLexer::T_CLOSE_PARENTHESIS:
256
                $this->level--;
257
258
                if (DocLexer::T_OPEN_PARENTHESIS !== $prev) {
259
                    $this->indent();
260
                }
261
262
                break;
263
        }
264
    }
265
}
266