diff options
-rw-r--r-- | src/Components/GroupKeyword.php | 141 | ||||
-rw-r--r-- | src/Parser.php | 2 | ||||
-rw-r--r-- | tests/Components/GroupKeywordTest.php | 24 |
3 files changed, 166 insertions, 1 deletions
diff --git a/src/Components/GroupKeyword.php b/src/Components/GroupKeyword.php new file mode 100644 index 0000000..4fb667f --- /dev/null +++ b/src/Components/GroupKeyword.php @@ -0,0 +1,141 @@ +<?php + +/** + * `GROUP BY` keyword parser. + */ + +namespace PhpMyAdmin\SqlParser\Components; + +use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parser; +use PhpMyAdmin\SqlParser\Token; +use PhpMyAdmin\SqlParser\TokensList; + +/** + * `GROUP BY` keyword parser. + * + * @category Keywords + * + * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+ + */ +class GroupKeyword extends Component +{ + /** + * The expression that is used for ordering. + * + * @var Expression + */ + public $expr; + + /** + * The order type. + * + * @var string + */ + public $type; + + /** + * Constructor. + * + * @param Expression $expr the expression that we are sorting by + * @param string $type the sorting type + */ + public function __construct($expr = null, $type = '') + { + $this->expr = $expr; + $this->type = $type; + } + + /** + * @param Parser $parser the parser that serves as context + * @param TokensList $list the list of tokens that are being parsed + * @param array $options parameters for parsing + * + * @return GroupKeyword[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = array()) + { + $ret = array(); + + $expr = new self(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 --------------------[ expression ]-------------------> 1 + * + * 1 ------------------------[ , ]------------------------> 0 + * 1 -------------------[ ASC / DESC ]--------------------> 1 + * + * @var int + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + * + * @var Token + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === Token::TYPE_DELIMITER) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) { + continue; + } + + if ($state === 0) { + $expr->expr = Expression::parse($parser, $list); + $state = 1; + } elseif ($state === 1) { + if (($token->type === Token::TYPE_KEYWORD) + && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) + ) { + $expr->type = $token->keyword; + } elseif (($token->type === Token::TYPE_OPERATOR) + && ($token->value === ',') + ) { + if (!empty($expr->expr)) { + $ret[] = $expr; + } + $expr = new self(); + $state = 0; + } else { + break; + } + } + } + + // Last iteration was not processed. + if (!empty($expr->expr)) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** + * @param GroupKeyword|GroupKeyword[] $component the component to be built + * @param array $options parameters for building + * + * @return string + */ + public static function build($component, array $options = array()) + { + if (is_array($component)) { + return implode(', ', $component); + } + + return trim($component->expr . ' ' . $component->type); + + } +} diff --git a/src/Parser.php b/src/Parser.php index 1aaa565..9ef7deb 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -168,7 +168,7 @@ class Parser extends Core 'options' => array('field' => 'table'), ), 'GROUP BY' => array( - 'class' => 'PhpMyAdmin\\SqlParser\\Components\\OrderKeyword', + 'class' => 'PhpMyAdmin\\SqlParser\\Components\\GroupKeyword', 'field' => 'group', ), 'HAVING' => array( diff --git a/tests/Components/GroupKeywordTest.php b/tests/Components/GroupKeywordTest.php new file mode 100644 index 0000000..515de6b --- /dev/null +++ b/tests/Components/GroupKeywordTest.php @@ -0,0 +1,24 @@ +<?php + +namespace PhpMyAdmin\SqlParser\Tests\Components; + +use PhpMyAdmin\SqlParser\Components\Expression; +use PhpMyAdmin\SqlParser\Components\GroupKeyword; +use PhpMyAdmin\SqlParser\Tests\TestCase; + +class GroupKeywordTest extends TestCase +{ + public function testBuild() + { + $this->assertEquals( + GroupKeyword::build( + array( + new GroupKeyword(new Expression('a'), 'ASC'), + new GroupKeyword(new Expression('b'), 'DESC'), + new GroupKeyword(new Expression('c')), + ) + ), + 'a ASC, b DESC, c' + ); + } +} |