Completed
Push — master ( 4105f6...24ea54 )
by Michal
25:18
created

Formatter::formatList()   F

Complexity

Conditions 50
Paths 13833

Size

Total Lines 226
Code Lines 84

Duplication

Lines 8
Ratio 3.54 %

Code Coverage

Tests 57
CRAP Score 305.1099

Importance

Changes 5
Bugs 2 Features 1
Metric Value
c 5
b 2
f 1
dl 8
loc 226
ccs 57
cts 107
cp 0.5326
rs 2
cc 50
eloc 84
nc 13833
nop 1
crap 305.1099

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Utilities that are used for formatting queries.
5
 *
6
 * @package    SqlParser
7
 * @subpackage Utils
8
 */
9
namespace SqlParser\Utils;
10
11
use SqlParser\Lexer;
12
use SqlParser\Parser;
13
use SqlParser\Token;
14
use SqlParser\TokensList;
15
16
/**
17
 * Utilities that are used for formatting queries.
18
 *
19
 * @category   Misc
20
 * @package    SqlParser
21
 * @subpackage Utils
22
 * @author     Dan Ungureanu <[email protected]>
23
 * @license    http://opensource.org/licenses/GPL-2.0 GNU Public License
24
 */
25
class Formatter
0 ignored issues
show
Coding Style introduced by
The property $INLINE_CLAUSES is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
26
{
27
28
    /**
29
     * The formatting options.
30
     *
31
     * @var array
32
     */
33
    public $options;
34
35
    /**
36
     * Clauses that must be inlined.
37
     *
38
     * These clauses usually are short and it's nicer to have them inline.
39
     *
40
     * @var array
41
     */
42
    public static $INLINE_CLAUSES = array(
43
        'CREATE'                        => true,
44
        'LIMIT'                         => true,
45
        'PARTITION BY'                  => true,
46
        'PARTITION'                     => true,
47
        'PROCEDURE'                     => true,
48
        'SUBPARTITION BY'               => true,
49
        'VALUES'                        => true,
50
    );
51
52
    /**
53
     * Constructor.
54
     *
55
     * @param array $options The formatting options.
56
     */
57 1
    public function __construct(array $options = array())
58
    {
59
        // The specified formatting options are merged with the default values.
60 1
        $this->options = array_merge(
61
            array(
62
63
                /**
64
                 * The format of the result.
65
                 *
66
                 * @var string The type ('text', 'cli' or 'html')
67
                 */
68 1
                'type' => php_sapi_name() == 'cli' ? 'cli' : 'text',
69
70
                /**
71
                 * The line ending used.
72
                 * By default, for text this is "\n" and for HTML this is "<br/>".
73
                 *
74
                 * @var string
75
                 */
76 1
                'line_ending' => $this->options['type'] == 'html' ? '<br/>' : "\n",
77
78
                /**
79
                 * The string used for indentation.
80
                 *
81
                 * @var string
82
                 */
83 1
                'indentation' => "  ",
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
84
85
                /**
86
                 * Whether comments should be removed or not.
87
                 *
88
                 * @var bool
89
                 */
90 1
                'remove_comments' => false,
91
92
                /**
93
                 * Whether each clause should be on a new line.
94
                 *
95
                 * @var bool
96
                 */
97 1
                'clause_newline' => true,
98
99
                /**
100
                 * Whether each part should be on a new line.
101
                 * Parts are delimited by brackets and commas.
102
                 *
103
                 * @var bool
104
                 */
105 1
                'parts_newline' => true,
106
107
                /**
108
                 * Whether each part of each clause should be indented.
109
                 *
110
                 * @var bool
111
                 */
112 1
                'indent_parts' => true,
113
114
                /**
115
                 * The styles used for HTML formatting.
116
                 * array($type, $flags, $span, $callback)
117
                 *
118
                 * @var array[]
119
                 */
120
                'formats' => array(
121
                    array(
122 1
                        'type'      => Token::TYPE_KEYWORD,
123 1
                        'flags'     => Token::FLAG_KEYWORD_RESERVED,
124 1
                        'html'      => 'class="sql-reserved"',
125 1
                        'cli'      => "\e[35m",
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal \e[35m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
126 1
                        'function'  => 'strtoupper',
127 1
                    ),
128
                    array(
129 1
                        'type'      => Token::TYPE_KEYWORD,
130 1
                        'flags'     => 0,
131 1
                        'html'      => 'class="sql-keyword"',
132 1
                        'cli'      => "\e[95m",
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal \e[95m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
133 1
                        'function'  => 'strtoupper',
134 1
                    ),
135
                    array(
136 1
                        'type'      => Token::TYPE_COMMENT,
137 1
                        'flags'     => 0,
138 1
                        'html'      => 'class="sql-comment"',
139 1
                        'cli'      => "\e[37m",
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal \e[37m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
140 1
                        'function'  => '',
141 1
                    ),
142
                    array(
143 1
                        'type'      => Token::TYPE_BOOL,
144 1
                        'flags'     => 0,
145 1
                        'html'      => 'class="sql-atom"',
146 1
                        'cli'      => "\e[36m",
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal \e[36m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
147 1
                        'function'  => 'strtoupper',
148 1
                    ),
149
                    array(
150 1
                        'type'      => Token::TYPE_NUMBER,
151 1
                        'flags'     => 0,
152 1
                        'html'      => 'class="sql-number"',
153 1
                        'cli'      => "\e[92m",
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal \e[92m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
154 1
                        'function'  => 'strtolower',
155 1
                    ),
156
                    array(
157 1
                        'type'      => Token::TYPE_STRING,
158 1
                        'flags'     => 0,
159 1
                        'html'      => 'class="sql-string"',
160 1
                        'cli'      => "\e[91m",
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal \e[91m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
161 1
                        'function'  => '',
162 1
                    ),
163
                    array(
164 1
                        'type'      => Token::TYPE_SYMBOL,
165 1
                        'flags'     => 0,
166 1
                        'html'      => 'class="sql-variable"',
167 1
                        'cli'      => "\e[36m",
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal \e[36m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
168 1
                        'function'  => '',
169 1
                    ),
170
                )
171 1
            ),
172
            $options
173 1
        );
174
175
        // `parts_newline` requires `clause_newline`
1 ignored issue
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
176 1
        $this->options['parts_newline'] &= $this->options['clause_newline'];
177 1
    }
178
179
    /**
180
     * Formats the given list of tokens.
181
     *
182
     * @param TokensList $list The list of tokens.
183
     *
184
     * @return string
185
     */
186 1
    public function formatList($list)
187
    {
188
189
        /**
190
         * The query to be returned.
191
         *
192
         * @var string $ret
193
         */
194 1
        $ret = '';
195
196
        /**
197
         * The indentation level.
198
         *
199
         * @var int $indent
200
         */
201 1
        $indent = 0;
202
203
        /**
204
         * Whether the line ended.
205
         *
206
         * @var bool $lineEnded
207
         */
208 1
        $lineEnded = false;
209
210
        /**
211
         * The name of the last clause.
212
         *
213
         * @var string $lastClause
214
         */
215 1
        $lastClause = '';
216
217
        /**
218
         * A stack that keeps track of the indentation level every time a new
219
         * block is found.
220
         *
221
         * @var array $blocksIndentation
222
         */
223 1
        $blocksIndentation = array();
224
225
        /**
226
         * A stack that keeps track of the line endings every time a new block
227
         * is found.
228
         *
229
         * @var array $blocksLineEndings
230
         */
231 1
        $blocksLineEndings = array();
232
233
        /**
234
         * Whether clause's options were formatted.
235
         *
236
         * @var bool $formattedOptions
237
         */
238 1
        $formattedOptions = false;
239
240
        /**
241
         * Previously parsed token.
242
         *
243
         * @var Token $prev
244
         */
245 1
        $prev = null;
246
247
        /**
248
         * Comments are being formatted separately to maintain the whitespaces
249
         * before and after them.
250
         *
251
         * @var string $comment
252
         */
253 1
        $comment = '';
254
255
        // In order to be able to format the queries correctly, the next token
256
        // must be taken into consideration. The loop below uses two pointers,
257
        // `$prev` and `$curr` which store two consecutive tokens.
258
        // Actually, at every iteration the previous token is being used.
259 1
        for ($list->idx = 0; $list->idx < $list->count; ++$list->idx) {
260
            /**
261
             * Token parsed at this moment.
262
             *
263
             * @var Token $curr
264
             */
265 1
            $curr = $list->tokens[$list->idx];
266
267 1
            if ($curr->type === Token::TYPE_WHITESPACE) {
268
                // Whitespaces are skipped because the formatter adds its own.
269 1
                continue;
270 1
            } elseif ($curr->type === Token::TYPE_COMMENT) {
271
                // Whether the comments should be parsed.
272
                if (!empty($this->options['remove_comments'])) {
273
                    continue;
274
                }
275
276
                if ($list->tokens[$list->idx - 1]->type === Token::TYPE_WHITESPACE) {
277
                    // The whitespaces before and after are preserved for
278
                    // formatting reasons.
279
                    $comment .= $list->tokens[$list->idx - 1]->token;
280
                }
281
                $comment .= $this->toString($curr);
282
                if (($list->tokens[$list->idx + 1]->type === Token::TYPE_WHITESPACE)
283
                    && ($list->tokens[$list->idx + 2]->type !== Token::TYPE_COMMENT)
284
                ) {
285
                    // Adding the next whitespace only there is no comment that
286
                    // follows it immediately which may cause adding a
287
                    // whitespace twice.
288
                    $comment .= $list->tokens[$list->idx + 1]->token;
289
                }
290
291
                // Everything was handled here, no need to continue.
292
                continue;
293
            }
294
295
            // Checking if pointers were initialized.
296 1
            if ($prev !== null) {
297
                // Checking if a new clause started.
298 1
                if (static::isClause($prev) !== false) {
299 1
                    $lastClause = $prev->value;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
300 1
                    $formattedOptions = false;
301 1
                }
302
303
                // The options of a clause should stay on the same line and everything that follows.
304 1
                if (($this->options['parts_newline'])
305 1
                    && (!$formattedOptions)
306 1
                    && (empty(self::$INLINE_CLAUSES[$lastClause]))
307 1
                    && (($curr->type !== Token::TYPE_KEYWORD)
308
                    || (($curr->type === Token::TYPE_KEYWORD)
309
                    && ($curr->flags & Token::FLAG_KEYWORD_FUNCTION)))
310 1
                ) {
311 1
                    $formattedOptions = true;
312 1
                    $lineEnded = true;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 8 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
313 1
                    ++$indent;
314 1
                }
315
316
                // Checking if this clause ended.
317 1
                if ($tmp = static::isClause($curr)) {
318
                    if (($tmp == 2) || ($this->options['clause_newline'])) {
319
                        $lineEnded = true;
320
                        if ($this->options['parts_newline']) {
321
                            --$indent;
322
                        }
323
                    }
324
                }
325
326
                // Indenting BEGIN ... END blocks.
327 1
                if (($prev->type === Token::TYPE_KEYWORD) && ($prev->value === 'BEGIN')) {
328
                    $lineEnded = true;
329
                    array_push($blocksIndentation, $indent);
330
                    ++$indent;
331 1 View Code Duplication
                } elseif (($curr->type === Token::TYPE_KEYWORD) && ($curr->value === 'END')) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
332
                    $lineEnded = true;
333
                    $indent = array_pop($blocksIndentation);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
334
                }
335
336
                // Formatting fragments delimited by comma.
337 1
                if (($prev->type === Token::TYPE_OPERATOR) && ($prev->value === ',')) {
338
                    // Fragments delimited by a comma are broken into multiple
339
                    // pieces only if the clause is not inlined or this fragment
340
                    // is between brackets that are on new line.
341
                    if (((empty(self::$INLINE_CLAUSES[$lastClause]))
342
                        && ($this->options['parts_newline']))
343
                        || (end($blocksLineEndings) === true)
344
                    ) {
345
                        $lineEnded = true;
346
                    }
347
                }
348
349
                // Handling brackets.
350
                // Brackets are indented only if the length of the fragment between
351
                // them is longer than 30 characters.
352 1
                if (($prev->type === Token::TYPE_OPERATOR) && ($prev->value === '(')) {
353
                    array_push($blocksIndentation, $indent);
354
                    if (static::getGroupLength($list) > 30) {
355
                        ++$indent;
356
                        $lineEnded = true;
357
                    }
358
                    array_push($blocksLineEndings, $lineEnded);
359 1 View Code Duplication
                } elseif (($curr->type === Token::TYPE_OPERATOR) && ($curr->value === ')')) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
360
                    $indent = array_pop($blocksIndentation);
361
                    $lineEnded |= array_pop($blocksLineEndings);
362
                }
363
364
                // Delimiter must be placed on the same line with the last
365
                // clause.
366 1
                if ($curr->type === Token::TYPE_DELIMITER) {
367 1
                    $lineEnded = false;
368 1
                }
369
370
                // Adding the token.
371 1
                $ret .= $this->toString($prev);
372
373
                // Finishing the line.
374 1
                if ($lineEnded) {
375 1
                    if ($indent < 0) {
376
                        // TODO: Make sure this never occurs and delete it.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
377
                        $indent = 0;
378
                    }
379
380 1
                    if ($curr->type !== Token::TYPE_COMMENT) {
381 1
                        $ret .= $this->options['line_ending']
382 1
                            . str_repeat($this->options['indentation'], $indent);
383 1
                    }
384 1
                    $lineEnded = false;
385 1
                } else {
386
                    // If the line ended there is no point in adding whitespaces.
387
                    // Also, some tokens do not have spaces before or after them.
388 1
                    if (!((($prev->type === Token::TYPE_OPERATOR) && (($prev->value === '.') || ($prev->value === '(')))
389
                        // No space after . (
390 1
                        || (($curr->type === Token::TYPE_OPERATOR) && (($curr->value === '.') || ($curr->value === ',') || ($curr->value === '(') || ($curr->value === ')')))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 173 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
391
                        // No space before . , ( )
392 1
                        || (($curr->type === Token::TYPE_DELIMITER)) && (mb_strlen($curr->value, 'UTF-8') < 2))
393
                        // A space after delimiters that are longer than 2 characters.
394 1
                        || ($prev->value === 'DELIMITER')
395 1
                    ) {
396
                        $ret .= ' ';
397
                    }
398
                }
399 1
            }
400
401 1
            if (!empty($comment)) {
402
                $ret .= $comment;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
403
                $comment = '';
404
            }
405
406
            // Iteration finished, consider current token as previous.
407 1
            $prev = $curr;
408 1
        }
409
410 1
        return $ret;
411
    }
412
413
    /**
414
     * Tries to print the query and returns the result.
415
     *
416
     * @param Token $token The token to be printed.
417
     *
418
     * @return string
419
     */
420 1
    public function toString($token)
421
    {
422 1
        $text = $token->token;
423
424 1
        foreach ($this->options['formats'] as $format) {
425 1
            if (($token->type === $format['type'])
426 1
                && (($token->flags & $format['flags']) === $format['flags'])
427 1
            ) {
428
                // Running transformation function.
429 1
                if (!empty($format['function'])) {
430 1
                    $func = $format['function'];
431 1
                    $text = $func($text);
432 1
                }
433
434
                // Formatting HTML.
435 1
                if ($this->options['type'] === 'html') {
436 1
                    return '<span ' . $format['html'] . '>' . $text . '</span>';
437
                } elseif ($this->options['type'] === 'cli') {
438
                    return $format['cli'] . $text;
439
                }
440
441
                break;
442
            }
443 1
        }
444
445
        if ($this->options['type'] === 'cli') {
446
            return "\e[39m" . $text;
1 ignored issue
show
Coding Style Comprehensibility introduced by
The string literal \e[39m does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
447
        }
448
        return $text;
449
    }
450
451
    /**
452
     * Formats a query.
453
     *
454
     * @param string $query   The query to be formatted
455
     * @param array  $options The formatting options.
456
     *
457
     * @return string          The formatted string.
458
     */
459 1
    public static function format($query, array $options = array())
460
    {
461 1
        $lexer = new Lexer($query);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
462 1
        $formatter = new Formatter($options);
463 1
        return $formatter->formatList($lexer->list);
464
    }
465
466
    /**
467
     * Computes the length of a group.
468
     *
469
     * A group is delimited by a pair of brackets.
470
     *
471
     * @param TokensList $list The list of tokens.
472
     *
473
     * @return int
474
     */
475
    public static function getGroupLength($list)
476
    {
477
        /**
478
         * The number of opening brackets found.
479
         * This counter starts at one because by the time this function called,
480
         * the list already advanced one position and the opening bracket was
481
         * already parsed.
482
         *
483
         * @var int $count
484
         */
485
        $count = 1;
486
487
        /**
488
         * The length of this group.
489
         *
490
         * @var int $length
491
         */
492
        $length = 0;
493
494
        for ($idx = $list->idx; $idx < $list->count; ++$idx) {
495
            // Counting the brackets.
496
            if ($list->tokens[$idx]->type === Token::TYPE_OPERATOR) {
497
                if ($list->tokens[$idx]->value === '(') {
498
                    ++$count;
499
                } elseif ($list->tokens[$idx]->value === ')') {
500
                    --$count;
501
                    if ($count == 0) {
502
                        break;
503
                    }
504
                }
505
            }
506
507
            // Keeping track of this group's length.
508
            $length += mb_strlen($list->tokens[$idx]->value, 'UTF-8');
509
        }
510
511
        return $length;
512
    }
513
514
    /**
515
     * Checks if a token is a statement or a clause inside a statement.
516
     *
517
     * @param Token $token The token to be checked.
518
     *
519
     * @return int|bool
520
     */
521 1
    public static function isClause($token)
522
    {
523 1
        if ((($token->type === Token::TYPE_NONE) && (strtoupper($token->token) === 'DELIMITER'))
524 1
            || (($token->type === Token::TYPE_KEYWORD) && (isset(Parser::$STATEMENT_PARSERS[$token->value])))
525 1
        ) {
526 1
            return 2;
527 1
        } elseif (($token->type === Token::TYPE_KEYWORD) && (isset(Parser::$KEYWORD_PARSERS[$token->value]))) {
528
            return 1;
529
        }
530 1
        return false;
531
    }
532
}
533