summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Čihař <michal@cihar.com>2017-01-02 15:57:26 +0100
committerMichal Čihař <michal@cihar.com>2017-01-02 15:57:26 +0100
commit3129d94d09467fb125d03973181d5670738bd1e5 (patch)
tree211249761d5612d9391f261352672baffaecd03c
parentaaee66ae8a11f99ce3a97714721b6772eaa20196 (diff)
parent4f5cac4bc2391ace4f19058097dbb9d99265772a (diff)
downloadsql-parser-3129d94d09467fb125d03973181d5670738bd1e5.zip
sql-parser-3129d94d09467fb125d03973181d5670738bd1e5.tar.gz
sql-parser-3129d94d09467fb125d03973181d5670738bd1e5.tar.bz2
Merge branch 'master' into motranslator
-rw-r--r--CHANGELOG.md4
-rw-r--r--src/Components/JoinKeyword.php1
-rw-r--r--src/Utils/Formatter.php303
-rw-r--r--tests/Utils/FormatterTest.php214
4 files changed, 406 insertions, 116 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc2b295..9b9dace 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,12 @@
## [Unreleased]
+## [3.4.15] - 2017-01-02
+
* Fix return value of Formatter.toString() when type is text
* Fix parsing of FIELDS and LINES options in SELECT..INTO
+* PHP 7.2 compatibility.
+* Better parameter passing to query formatter.
## [3.4.14] - 2016-11-30
diff --git a/src/Components/JoinKeyword.php b/src/Components/JoinKeyword.php
index 548a64e..60711ce 100644
--- a/src/Components/JoinKeyword.php
+++ b/src/Components/JoinKeyword.php
@@ -41,7 +41,6 @@ class JoinKeyword extends Component
'RIGHT OUTER JOIN' => 'RIGHT',
'NATURAL JOIN' => 'NATURAL',
'NATURAL LEFT JOIN' => 'NATURAL LEFT',
- 'NATURAL LEFT JOIN' => 'NATURAL LEFT',
'NATURAL RIGHT JOIN' => 'NATURAL RIGHT',
'NATURAL LEFT OUTER JOIN' => 'NATURAL LEFT OUTER',
'NATURAL RIGHT OUTER JOIN' => 'NATURAL RIGHT OUTER',
diff --git a/src/Utils/Formatter.php b/src/Utils/Formatter.php
index 1d19440..51f8633 100644
--- a/src/Utils/Formatter.php
+++ b/src/Utils/Formatter.php
@@ -55,128 +55,201 @@ class Formatter
*/
public function __construct(array $options = array())
{
- // The specified formatting options are merged with the default values.
- $this->options = array_merge(
- array(
+ $this->options = $this->getMergedOptions($options);
+ }
- /**
- * The format of the result.
- *
- * @var string The type ('text', 'cli' or 'html')
- */
- 'type' => php_sapi_name() == 'cli' ? 'cli' : 'text',
-
- /**
- * The line ending used.
- * By default, for text this is "\n" and for HTML this is "<br/>".
- *
- * @var string
- */
- 'line_ending' => NULL,
-
- /**
- * The string used for indentation.
- *
- * @var string
- */
- 'indentation' => ' ',
-
- /**
- * Whether comments should be removed or not.
- *
- * @var bool
- */
- 'remove_comments' => false,
-
- /**
- * Whether each clause should be on a new line.
- *
- * @var bool
- */
- 'clause_newline' => true,
-
- /**
- * Whether each part should be on a new line.
- * Parts are delimited by brackets and commas.
- *
- * @var bool
- */
- 'parts_newline' => true,
-
- /**
- * Whether each part of each clause should be indented.
- *
- * @var bool
- */
- 'indent_parts' => true,
-
- /**
- * The styles used for HTML formatting.
- * array($type, $flags, $span, $callback)
- *
- * @var array[]
- */
- 'formats' => array(
- array(
- 'type' => Token::TYPE_KEYWORD,
- 'flags' => Token::FLAG_KEYWORD_RESERVED,
- 'html' => 'class="sql-reserved"',
- 'cli' => "\x1b[35m",
- 'function' => 'strtoupper',
- ),
- array(
- 'type' => Token::TYPE_KEYWORD,
- 'flags' => 0,
- 'html' => 'class="sql-keyword"',
- 'cli' => "\x1b[95m",
- 'function' => 'strtoupper',
- ),
- array(
- 'type' => Token::TYPE_COMMENT,
- 'flags' => 0,
- 'html' => 'class="sql-comment"',
- 'cli' => "\x1b[37m",
- 'function' => '',
- ),
- array(
- 'type' => Token::TYPE_BOOL,
- 'flags' => 0,
- 'html' => 'class="sql-atom"',
- 'cli' => "\x1b[36m",
- 'function' => 'strtoupper',
- ),
- array(
- 'type' => Token::TYPE_NUMBER,
- 'flags' => 0,
- 'html' => 'class="sql-number"',
- 'cli' => "\x1b[92m",
- 'function' => 'strtolower',
- ),
- array(
- 'type' => Token::TYPE_STRING,
- 'flags' => 0,
- 'html' => 'class="sql-string"',
- 'cli' => "\x1b[91m",
- 'function' => '',
- ),
- array(
- 'type' => Token::TYPE_SYMBOL,
- 'flags' => 0,
- 'html' => 'class="sql-variable"',
- 'cli' => "\x1b[36m",
- 'function' => '',
- ),
- )
- ),
+ /**
+ * The specified formatting options are merged with the default values.
+ *
+ * @param array $options
+ * @return array
+ */
+ private function getMergedOptions(array $options)
+ {
+ $options = array_merge(
+ $this->getDefaultOptions(),
$options
);
- if (is_null($this->options['line_ending'])) {
- $this->options['line_ending'] = $this->options['type'] == 'html' ? '<br/>' : "\n";
+ $options['formats'] = self::mergeFormats($this->getDefaultFormats(), @$options['formats'] ?: array());
+
+ if (is_null($options['line_ending'])) {
+ $options['line_ending'] = $options['type'] === 'html' ? '<br/>' : "\n";
}
// `parts_newline` requires `clause_newline`
- $this->options['parts_newline'] &= $this->options['clause_newline'];
+ $options['parts_newline'] &= $options['clause_newline'];
+
+ return $options;
+ }
+
+ /**
+ * The default formatting options.
+ *
+ * @return array
+ */
+ protected function getDefaultOptions()
+ {
+ return array(
+ /**
+ * The format of the result.
+ *
+ * @var string The type ('text', 'cli' or 'html')
+ */
+ 'type' => php_sapi_name() === 'cli' ? 'cli' : 'text',
+
+ /**
+ * The line ending used.
+ * By default, for text this is "\n" and for HTML this is "<br/>".
+ *
+ * @var string
+ */
+ 'line_ending' => NULL,
+
+ /**
+ * The string used for indentation.
+ *
+ * @var string
+ */
+ 'indentation' => ' ',
+
+ /**
+ * Whether comments should be removed or not.
+ *
+ * @var bool
+ */
+ 'remove_comments' => false,
+
+ /**
+ * Whether each clause should be on a new line.
+ *
+ * @var bool
+ */
+ 'clause_newline' => true,
+
+ /**
+ * Whether each part should be on a new line.
+ * Parts are delimited by brackets and commas.
+ *
+ * @var bool
+ */
+ 'parts_newline' => true,
+
+ /**
+ * Whether each part of each clause should be indented.
+ *
+ * @var bool
+ */
+ 'indent_parts' => true,
+ );
+ }
+
+ /**
+ * The styles used for HTML formatting.
+ * array($type, $flags, $span, $callback)
+ *
+ * @return array
+ */
+ protected function getDefaultFormats()
+ {
+ return array(
+ array(
+ 'type' => Token::TYPE_KEYWORD,
+ 'flags' => Token::FLAG_KEYWORD_RESERVED,
+ 'html' => 'class="sql-reserved"',
+ 'cli' => "\x1b[35m",
+ 'function' => 'strtoupper',
+ ),
+ array(
+ 'type' => Token::TYPE_KEYWORD,
+ 'flags' => 0,
+ 'html' => 'class="sql-keyword"',
+ 'cli' => "\x1b[95m",
+ 'function' => 'strtoupper',
+ ),
+ array(
+ 'type' => Token::TYPE_COMMENT,
+ 'flags' => 0,
+ 'html' => 'class="sql-comment"',
+ 'cli' => "\x1b[37m",
+ 'function' => '',
+ ),
+ array(
+ 'type' => Token::TYPE_BOOL,
+ 'flags' => 0,
+ 'html' => 'class="sql-atom"',
+ 'cli' => "\x1b[36m",
+ 'function' => 'strtoupper',
+ ),
+ array(
+ 'type' => Token::TYPE_NUMBER,
+ 'flags' => 0,
+ 'html' => 'class="sql-number"',
+ 'cli' => "\x1b[92m",
+ 'function' => 'strtolower',
+ ),
+ array(
+ 'type' => Token::TYPE_STRING,
+ 'flags' => 0,
+ 'html' => 'class="sql-string"',
+ 'cli' => "\x1b[91m",
+ 'function' => '',
+ ),
+ array(
+ 'type' => Token::TYPE_SYMBOL,
+ 'flags' => 0,
+ 'html' => 'class="sql-variable"',
+ 'cli' => "\x1b[36m",
+ 'function' => '',
+ ),
+ );
+ }
+
+ private static function mergeFormats(array $formats, array $newFormats)
+ {
+ $added = array();
+
+ foreach ($formats as $i => $original) {
+ foreach ($newFormats as $j => $new) {
+ if (isset($new['type'])
+ && $new['type'] === $original['type']
+ && (
+ (
+ isset($new['flags'])
+ && $original['flags'] === $new['flags']
+ )
+ || (
+ !isset($new['flags'])
+ && $original['flags'] == 0
+ )
+ )
+ ) {
+ $formats[$i] = array(
+ 'type' => $original['type'],
+ 'flags' => isset($new['flags']) ? $new['flags'] : 0,
+ 'html' => isset($new['html']) ? $new['html'] : '',
+ 'cli' => isset($new['cli']) ? $new['cli'] : '',
+ 'function' => isset($new['function']) ? $new['function'] : '',
+ );
+
+ $added[] = $j;
+ }
+ }
+ }
+
+ foreach ($newFormats as $j => $new) {
+ if (!in_array($j, $added) && isset($new['type'])) {
+ $formats[] = array(
+ 'type' => $new['type'],
+ 'flags' => isset($new['flags']) ? $new['flags'] : 0,
+ 'html' => isset($new['html']) ? $new['html'] : '',
+ 'cli' => isset($new['cli']) ? $new['cli'] : '',
+ 'function' => isset($new['function']) ? $new['function'] : '',
+ );
+ }
+ }
+
+ return $formats;
}
/**
diff --git a/tests/Utils/FormatterTest.php b/tests/Utils/FormatterTest.php
index e7c7212..1cc3b06 100644
--- a/tests/Utils/FormatterTest.php
+++ b/tests/Utils/FormatterTest.php
@@ -9,6 +9,220 @@ use SqlParser\Tests\TestCase;
class FormatTest extends TestCase
{
/**
+ * @dataProvider mergeFormats
+ */
+ public function testMergeFormats($default, $overriding, $expected)
+ {
+ $formatter = $this->getMockBuilder('SqlParser\Utils\Formatter')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getDefaultOptions', 'getDefaultFormats'))
+ ->getMock();
+
+ $formatter->expects($this->once())
+ ->method('getDefaultOptions')
+ ->willReturn(array(
+ 'type' => 'text',
+ 'line_ending' => null,
+ 'clause_newline' => null,
+ 'parts_newline' => null,
+ ));
+
+ $formatter->expects($this->once())
+ ->method('getDefaultFormats')
+ ->willReturn($default);
+
+ $expectedOptions = array(
+ 'type' => 'test-type',
+ 'line_ending' => '<br>',
+ 'clause_newline' => null,
+ 'parts_newline' => 0,
+ 'formats' => $expected
+ );
+
+ $overridingOptions = array(
+ 'type' => 'test-type',
+ 'line_ending' => '<br>',
+ 'formats' => $overriding
+ );
+
+ $reflectionMethod = new \ReflectionMethod($formatter, 'getMergedOptions');
+ $reflectionMethod->setAccessible(true);
+ $this->assertEquals($expectedOptions, $reflectionMethod->invoke($formatter, $overridingOptions));
+ }
+
+ public function mergeFormats()
+ {
+ // array(default, overriding, expected)[]
+ return array(
+ 'empty formats' => array(
+ array( // default
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ ),
+ ),
+ array( // overriding
+ array(
+ ),
+ ),
+ array( // expected
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ ),
+ ),
+ ),
+ 'no flags' => array(
+ array( // default
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 1,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ ),
+ array( // overriding
+ array(
+ 'type' => 0,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ )
+ ),
+ array( // expected
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ 'function' => '',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 1,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ ),
+ ),
+ 'with flags' => array(
+ array( // default
+ array(
+ 'type' => -1,
+ 'flags' => 0,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 1,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ ),
+ array( // overriding
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ ),
+ ),
+ array( // expected
+ array(
+ 'type' => -1,
+ 'flags' => 0,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ 'function' => '',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 1,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ ),
+ ),
+ 'with extra formats' => array(
+ array( // default
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ ),
+ array( // overriding
+ array(
+ 'type' => 0,
+ 'flags' => 1,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ ),
+ array(
+ 'type' => 1,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ ),
+ array(
+ 'type' => 1,
+ 'flags' => 1,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ ),
+ ),
+ array( // expected
+ array(
+ 'type' => 0,
+ 'flags' => 0,
+ 'html' => 'html',
+ 'cli' => 'cli',
+ ),
+ array(
+ 'type' => 0,
+ 'flags' => 1,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ 'function' => '',
+ ),
+ array(
+ 'type' => 1,
+ 'flags' => 0,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ 'function' => '',
+ ),
+ array(
+ 'type' => 1,
+ 'flags' => 1,
+ 'html' => 'new html',
+ 'cli' => 'new cli',
+ 'function' => '',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
* @dataProvider formatQueries
*/
public function testFormat($query, $expected, $options)