├── .codeclimate.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── TODO.md ├── composer.json ├── lib └── CrEOF │ └── Geo │ └── WKT │ ├── Exception │ ├── ExceptionInterface.php │ ├── InvalidArgumentException.php │ ├── RangeException.php │ └── UnexpectedValueException.php │ ├── Lexer.php │ └── Parser.php ├── phpunit.xml.dist └── tests └── CrEOF └── Geo └── WKT └── Tests ├── LexerTest.php └── ParserTest.php /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | fixme: 3 | enabled: true 4 | phpcodesniffer: 5 | enabled: true 6 | phpmd: 7 | enabled: true 8 | ratings: 9 | paths: 10 | - "**.php" 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - 7.0 9 | - hhvm 10 | 11 | before_script: 12 | - composer --prefer-source install 13 | 14 | script: 15 | - ./vendor/bin/phpunit -v --coverage-clover ./build/logs/clover.xml 16 | 17 | after_script: 18 | - ./vendor/bin/test-reporter --coverage-report ./build/logs/clover.xml 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unreleased] 6 | ### Added 7 | 8 | ### Changed 9 | 10 | ### Removed 11 | 12 | ## [2.2.0] - 2016-05-03 13 | ### Added 14 | - Tests namespace to PSR-0 autoload in composer.json. 15 | - Support for 3DZ, 3DM, 4DZM objects added. Dimension(s) now in 'dimension' key of returned array. 16 | 17 | ### Changed 18 | - Token pattern regex changed to capture numbers in scientific notation as a single value. 19 | - Let PHP handle scientific number conversion to float instead of manually calculating. 20 | - Only instantiate Lexer object in Parser constructor if it doesn't exist. 21 | - Move function return value tests from switch statement in Lexer. Switch statement now doing only string comparison. 22 | - Remove static visibility from Lexer instance in Parser. 23 | - PHPUnit now bootstraps Composer autoload. 24 | - Update PHPUnit config XML to be compliant with XSD. 25 | - Documentation updated for 3DZ, 3DM, 4DZM support. 26 | 27 | ### Removed 28 | - Removed E token used with scientific notation from Lexer. 29 | - Removed now unused TestInit. 30 | 31 | ## [2.1.0] - 2016-04-09 32 | ### Added 33 | - Add tokens for 3DM, 3DZ, and 4D coordinates to Lexer. 34 | - Method Lexer::value() to get current token value. 35 | - Match Z, M, or ZM tokens in Parser (not currently used). 36 | - Add test for Parser reuse. 37 | - Add test for Lexer reuse. 38 | 39 | ### Changed 40 | - Regex used to catch tokens. 41 | - Allow Lexer instantiation with no parameters so object can be reused. 42 | - Allow Parser instantiation with no parameters so object can be reused. 43 | - Changed visibility of Parser::$type. 44 | - Use Lexer::value() in Parser. 45 | - Set srid to null before parsing value. 46 | - Consolidated all Parser test data into ParserTest. 47 | - Update usage documentation in README.md. 48 | 49 | ## [2.0.0] - 2015-11-18 50 | ### Added 51 | - Change base namespace to CrEOF\Geo\WKT to avoid class collision with other CrEOF packages. 52 | 53 | ## [1.0.0] - 2015-11-11 54 | ### Added 55 | - Initial release. 56 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | (this is a work in progress) 2 | 3 | - Code formatting MUST follow PSR-2. 4 | - Issues SHOULD include code and/or data to reproduce the issue. 5 | - PR's for issues SHOULD include test(s) for issue. 6 | - PR's SHOULD have adequate documentation (commit messages, comments, etc.) to readily convey what and/or why. 7 | - Code SHOULD attempt to follow [Object Calisthenics](http://www.xpteam.com/jeff/writings/objectcalisthenics.rtf) methodology. 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 Derek J. Lambert 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # creof/wkt-parser 2 | 3 | [![Code Climate](https://codeclimate.com/github/creof/wkt-parser/badges/gpa.svg)](https://codeclimate.com/github/creof/wkt-parser) 4 | [![Test Coverage](https://codeclimate.com/github/creof/wkt-parser/badges/coverage.svg)](https://codeclimate.com/github/creof/wkt-parser/coverage) 5 | [![Build Status](https://travis-ci.org/creof/wkt-parser.svg?branch=master)](https://travis-ci.org/creof/wkt-parser) 6 | 7 | Lexer and parser library for 2D, 3D, and 4D WKT/EWKT spatial object strings. 8 | 9 | ## Usage 10 | 11 | There are two use patterns for the parser. The value to be parsed can be passed into the constructor, then parse() 12 | called on the returned ```Parser``` object: 13 | 14 | ```php 15 | $input = 'POLYGON((0 0,10 0,10 10,0 10,0 0))'; 16 | 17 | $parser = new Parser($input); 18 | 19 | $value = $parser->parse(); 20 | ``` 21 | 22 | If many values need to be parsed, a single ```Parser``` instance can be used: 23 | 24 | ```php 25 | $input1 = 'POLYGON((0 0,10 0,10 10,0 10,0 0))'; 26 | $input2 = 'POINT(0,0)'; 27 | 28 | $parser = new Parser(); 29 | 30 | $value1 = $parser->parse($input1); 31 | $value2 = $parser->parse($input2); 32 | ``` 33 | 34 | ## Return 35 | 36 | The parser will return an array with the keys ```type```, ```value```, ```srid```, and ```dimension```. 37 | - ```type``` string, the spatial object type (POINT, LINESTRING, etc.) without any dimension. 38 | - ```value``` array, contains integer or float values for points, or nested arrays containing these based on spatial object type. 39 | - ```srid``` integer, the SRID if EWKT value was parsed, ```null``` otherwise. 40 | - ```dimension``` string, will contain ```Z```, ```M```, or ```ZM``` for the respective 3D and 4D objects, ```null``` otherwise. 41 | 42 | ## Exceptions 43 | 44 | The ```Lexer``` and ```Parser``` will throw exceptions implementing interface ```CrEOF\Geo\WKT\Exception\ExceptionInterface```. 45 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creof/wkt-parser/bc4c051b7a4e99b4943e2ec358218ed200aa991e/TODO.md -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "creof/wkt-parser", 3 | "type": "library", 4 | "description": "Parser for well-known text (WKT) object strings", 5 | "keywords": ["parser", "lexer", "string", "text", "geometry", "geography", "spatial", "wkt", "ewkt"], 6 | "authors": [ 7 | { 8 | "name": "Derek J. Lambert", 9 | "email": "dlambert@dereklambert.com" 10 | } 11 | ], 12 | "license": "MIT", 13 | "require": { 14 | "php": ">=5.3.3", 15 | "ext-SPL": "*", 16 | "doctrine/lexer": "~1.0" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit": ">=4.8", 20 | "codeclimate/php-test-reporter": "dev-master" 21 | }, 22 | "autoload": { 23 | "psr-0": { 24 | "CrEOF\\Geo\\WKT": "lib/" 25 | } 26 | }, 27 | "autoload-dev": { 28 | "psr-0": { 29 | "CrEOF\\Geo\\WKT\\Tests": "tests/" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/CrEOF/Geo/WKT/Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 30 | * @license http://dlambert.mit-license.org MIT 31 | */ 32 | interface ExceptionInterface 33 | { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /lib/CrEOF/Geo/WKT/Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 30 | * @license http://dlambert.mit-license.org MIT 31 | */ 32 | class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface 33 | { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /lib/CrEOF/Geo/WKT/Exception/RangeException.php: -------------------------------------------------------------------------------- 1 | 30 | * @license http://dlambert.mit-license.org MIT 31 | */ 32 | class RangeException extends \RangeException implements ExceptionInterface 33 | { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /lib/CrEOF/Geo/WKT/Exception/UnexpectedValueException.php: -------------------------------------------------------------------------------- 1 | 30 | * @license http://dlambert.mit-license.org MIT 31 | */ 32 | class UnexpectedValueException extends \UnexpectedValueException implements ExceptionInterface 33 | { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /lib/CrEOF/Geo/WKT/Lexer.php: -------------------------------------------------------------------------------- 1 | 32 | * @license http://dlambert.mit-license.org MIT 33 | */ 34 | class Lexer extends AbstractLexer 35 | { 36 | const T_NONE = 1; 37 | const T_INTEGER = 2; 38 | const T_STRING = 3; 39 | const T_FLOAT = 5; 40 | const T_CLOSE_PARENTHESIS = 6; 41 | const T_OPEN_PARENTHESIS = 7; 42 | const T_COMMA = 8; 43 | const T_DOT = 10; 44 | const T_EQUALS = 11; 45 | const T_MINUS = 14; 46 | const T_SEMICOLON = 50; 47 | const T_SRID = 500; 48 | const T_ZM = 501; 49 | const T_Z = 502; 50 | const T_M = 503; 51 | 52 | // Geometry types > 600 53 | const T_TYPE = 600; 54 | const T_POINT = 601; 55 | const T_LINESTRING = 602; 56 | const T_POLYGON = 603; 57 | const T_MULTIPOINT = 604; 58 | const T_MULTILINESTRING = 605; 59 | const T_MULTIPOLYGON = 606; 60 | const T_GEOMETRYCOLLECTION = 607; 61 | const T_CIRCULARSTRING = 608; 62 | const T_COMPOUNDCURVE = 609; 63 | const T_CURVEPOLYGON = 610; 64 | const T_MULTICURVE = 611; 65 | const T_MULTISURFACE = 612; 66 | const T_CURVE = 613; 67 | const T_SURFACE = 614; 68 | const T_POLYHEDRALSURFACE = 615; 69 | const T_TIN = 616; 70 | const T_TRIANGLE = 617; 71 | 72 | /** 73 | * @param string $input a query string 74 | */ 75 | public function __construct($input = null) 76 | { 77 | if (null !== $input) { 78 | $this->setInput($input); 79 | } 80 | } 81 | 82 | /** 83 | * @return mixed 84 | */ 85 | public function value() 86 | { 87 | return $this->token['value']; 88 | } 89 | 90 | /** 91 | * @param string $value 92 | * 93 | * @return int 94 | */ 95 | protected function getType(&$value) 96 | { 97 | if (is_numeric($value)) { 98 | $value += 0; 99 | 100 | if (is_int($value)) { 101 | return self::T_INTEGER; 102 | } 103 | 104 | return self::T_FLOAT; 105 | } 106 | 107 | if (ctype_alpha($value)) { 108 | $name = __CLASS__ . '::T_' . strtoupper($value); 109 | 110 | if (defined($name)) { 111 | return constant($name); 112 | } 113 | 114 | return self::T_STRING; 115 | } 116 | 117 | switch ($value) { 118 | case ',': 119 | return self::T_COMMA; 120 | case '(': 121 | return self::T_OPEN_PARENTHESIS; 122 | case ')': 123 | return self::T_CLOSE_PARENTHESIS; 124 | case '=': 125 | return self::T_EQUALS; 126 | case ';': 127 | return self::T_SEMICOLON; 128 | default: 129 | return self::T_NONE; 130 | } 131 | } 132 | 133 | /** 134 | * @return string[] 135 | */ 136 | protected function getCatchablePatterns() 137 | { 138 | return array( 139 | '', 140 | 'zm|[a-z]+[a-ln-y]', 141 | '[+-]?[0-9]+(?:[\.][0-9]+)?(?:e[+-]?[0-9]+)?' 142 | ); 143 | } 144 | 145 | /** 146 | * @return string[] 147 | */ 148 | protected function getNonCatchablePatterns() 149 | { 150 | return array('\s+'); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /lib/CrEOF/Geo/WKT/Parser.php: -------------------------------------------------------------------------------- 1 | 32 | * @license http://dlambert.mit-license.org MIT 33 | */ 34 | class Parser 35 | { 36 | /** 37 | * @var string 38 | */ 39 | private $type; 40 | 41 | /** 42 | * @var string 43 | */ 44 | private $input; 45 | 46 | /** 47 | * @var int 48 | */ 49 | private $srid; 50 | 51 | /** 52 | * @var string 53 | */ 54 | private $dimension; 55 | 56 | /** 57 | * @var Lexer 58 | */ 59 | private $lexer; 60 | 61 | /** 62 | * @param string|null $input 63 | */ 64 | public function __construct($input = null) 65 | { 66 | $this->lexer = new Lexer(); 67 | 68 | if (null !== $input) { 69 | $this->input = $input; 70 | } 71 | } 72 | 73 | /** 74 | * @param string|null $input 75 | * 76 | * @return array 77 | */ 78 | public function parse($input = null) 79 | { 80 | if (null !== $input) { 81 | $this->input = $input; 82 | } 83 | 84 | $this->lexer->setInput($this->input); 85 | $this->lexer->moveNext(); 86 | 87 | $this->srid = null; 88 | $this->dimension = null; 89 | 90 | if ($this->lexer->isNextToken(Lexer::T_SRID)) { 91 | $this->srid = $this->srid(); 92 | } 93 | 94 | $geometry = $this->geometry(); 95 | $geometry['srid'] = $this->srid; 96 | $geometry['dimension'] = '' === $this->dimension ? null : $this->dimension; 97 | 98 | return $geometry; 99 | } 100 | 101 | /** 102 | * Match SRID in EWKT object 103 | * 104 | * @return int 105 | */ 106 | protected function srid() 107 | { 108 | $this->match(Lexer::T_SRID); 109 | $this->match(Lexer::T_EQUALS); 110 | $this->match(Lexer::T_INTEGER); 111 | 112 | $srid = $this->lexer->value(); 113 | 114 | $this->match(Lexer::T_SEMICOLON); 115 | 116 | return $srid; 117 | } 118 | 119 | /** 120 | * Match spatial data type 121 | * 122 | * @return string 123 | */ 124 | protected function type() 125 | { 126 | $this->match(Lexer::T_TYPE); 127 | 128 | return $this->lexer->value(); 129 | } 130 | 131 | /** 132 | * Match spatial geometry object 133 | * 134 | * @return array 135 | */ 136 | protected function geometry() 137 | { 138 | $type = $this->type(); 139 | $this->type = $type; 140 | 141 | if ($this->lexer->isNextTokenAny(array(Lexer::T_Z, Lexer::T_M, Lexer::T_ZM))) { 142 | $this->match($this->lexer->lookahead['type']); 143 | 144 | $this->dimension = $this->lexer->value(); 145 | } 146 | 147 | $this->match(Lexer::T_OPEN_PARENTHESIS); 148 | 149 | $value = $this->$type(); 150 | 151 | $this->match(Lexer::T_CLOSE_PARENTHESIS); 152 | 153 | return array( 154 | 'type' => $type, 155 | 'value' => $value 156 | ); 157 | } 158 | 159 | /** 160 | * Match a coordinate pair 161 | * 162 | * @return array 163 | */ 164 | protected function point() 165 | { 166 | if (null !== $this->dimension) { 167 | return $this->coordinates(2 + strlen($this->dimension)); 168 | } 169 | 170 | $values = $this->coordinates(2); 171 | 172 | for ($i = 3; $i <= 4 && $this->lexer->isNextTokenAny(array(Lexer::T_FLOAT, Lexer::T_INTEGER)); $i++) { 173 | $values[] = $this->coordinate(); 174 | } 175 | 176 | switch (count($values)) { 177 | case 2: 178 | $this->dimension = ''; 179 | break; 180 | case 3: 181 | $this->dimension = 'Z'; 182 | break; 183 | case 4: 184 | $this->dimension = 'ZM'; 185 | break; 186 | } 187 | 188 | return $values; 189 | } 190 | 191 | /** 192 | * @param int $count 193 | * 194 | * @return array 195 | */ 196 | protected function coordinates($count) 197 | { 198 | $values = array(); 199 | 200 | for ($i = 1; $i <= $count; $i++) { 201 | $values[] = $this->coordinate(); 202 | } 203 | 204 | return $values; 205 | } 206 | 207 | /** 208 | * Match a number and optional exponent 209 | * 210 | * @return int|float 211 | */ 212 | protected function coordinate() 213 | { 214 | $this->match(($this->lexer->isNextToken(Lexer::T_FLOAT) ? Lexer::T_FLOAT : Lexer::T_INTEGER)); 215 | 216 | return $this->lexer->value(); 217 | } 218 | 219 | /** 220 | * Match LINESTRING value 221 | * 222 | * @return array[] 223 | */ 224 | protected function lineString() 225 | { 226 | return $this->pointList(); 227 | } 228 | 229 | /** 230 | * Match POLYGON value 231 | * 232 | * @return array[] 233 | */ 234 | protected function polygon() 235 | { 236 | return $this->pointLists(); 237 | } 238 | 239 | /** 240 | * Match a list of coordinates 241 | * 242 | * @return array[] 243 | */ 244 | protected function pointList() 245 | { 246 | $points = array($this->point()); 247 | 248 | while ($this->lexer->isNextToken(Lexer::T_COMMA)) { 249 | $this->match(Lexer::T_COMMA); 250 | 251 | $points[] = $this->point(); 252 | } 253 | 254 | return $points; 255 | } 256 | 257 | /** 258 | * Match nested lists of coordinates 259 | * 260 | * @return array[] 261 | */ 262 | protected function pointLists() 263 | { 264 | $this->match(Lexer::T_OPEN_PARENTHESIS); 265 | 266 | $pointLists = array($this->pointList()); 267 | 268 | $this->match(Lexer::T_CLOSE_PARENTHESIS); 269 | 270 | while ($this->lexer->isNextToken(Lexer::T_COMMA)) { 271 | $this->match(Lexer::T_COMMA); 272 | $this->match(Lexer::T_OPEN_PARENTHESIS); 273 | 274 | $pointLists[] = $this->pointList(); 275 | 276 | $this->match(Lexer::T_CLOSE_PARENTHESIS); 277 | } 278 | 279 | return $pointLists; 280 | } 281 | 282 | /** 283 | * Match MULTIPOLYGON value 284 | * 285 | * @return array[] 286 | */ 287 | protected function multiPolygon() 288 | { 289 | $this->match(Lexer::T_OPEN_PARENTHESIS); 290 | 291 | $polygons = array($this->polygon()); 292 | 293 | $this->match(Lexer::T_CLOSE_PARENTHESIS); 294 | 295 | while ($this->lexer->isNextToken(Lexer::T_COMMA)) { 296 | $this->match(Lexer::T_COMMA); 297 | $this->match(Lexer::T_OPEN_PARENTHESIS); 298 | 299 | $polygons[] = $this->polygon(); 300 | 301 | $this->match(Lexer::T_CLOSE_PARENTHESIS); 302 | } 303 | 304 | return $polygons; 305 | } 306 | 307 | /** 308 | * Match MULTIPOINT value 309 | * 310 | * @return array[] 311 | */ 312 | protected function multiPoint() 313 | { 314 | return $this->pointList(); 315 | } 316 | 317 | /** 318 | * Match MULTILINESTRING value 319 | * 320 | * @return array[] 321 | */ 322 | protected function multiLineString() 323 | { 324 | return $this->pointLists(); 325 | } 326 | 327 | /** 328 | * Match GEOMETRYCOLLECTION value 329 | * 330 | * @return array[] 331 | */ 332 | protected function geometryCollection() 333 | { 334 | $collection = array($this->geometry()); 335 | 336 | while ($this->lexer->isNextToken(Lexer::T_COMMA)) { 337 | $this->match(Lexer::T_COMMA); 338 | 339 | $collection[] = $this->geometry(); 340 | } 341 | 342 | return $collection; 343 | } 344 | 345 | /** 346 | * Match token at current position in input 347 | * 348 | * @param $token 349 | */ 350 | protected function match($token) 351 | { 352 | $lookaheadType = $this->lexer->lookahead['type']; 353 | 354 | if ($lookaheadType !== $token && ($token !== Lexer::T_TYPE || $lookaheadType <= Lexer::T_TYPE)) { 355 | throw $this->syntaxError($this->lexer->getLiteral($token)); 356 | } 357 | 358 | $this->lexer->moveNext(); 359 | } 360 | 361 | /** 362 | * Create exception with descriptive error message 363 | * 364 | * @param string $expected 365 | * 366 | * @return UnexpectedValueException 367 | */ 368 | private function syntaxError($expected) 369 | { 370 | $expected = sprintf('Expected %s, got', $expected); 371 | $token = $this->lexer->lookahead; 372 | $found = null === $this->lexer->lookahead ? 'end of string.' : sprintf('"%s"', $token['value']); 373 | $message = sprintf( 374 | '[Syntax Error] line 0, col %d: Error: %s %s in value "%s"', 375 | isset($token['position']) ? $token['position'] : '-1', 376 | $expected, 377 | $found, 378 | $this->input 379 | ); 380 | 381 | return new UnexpectedValueException($message); 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | ./tests/CrEOF/Geo/WKT/Tests 13 | 14 | 15 | 16 | 17 | 18 | lib 19 | 20 | tests 21 | vendor 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/CrEOF/Geo/WKT/Tests/LexerTest.php: -------------------------------------------------------------------------------- 1 | 32 | * @license http://dlambert.mit-license.org MIT 33 | */ 34 | class LexerTest extends \PHPUnit_Framework_TestCase 35 | { 36 | /** 37 | * @param $value 38 | * @param array $expected 39 | * 40 | * @dataProvider tokenData 41 | */ 42 | public function testTokenRecognition($value, array $expected) 43 | { 44 | $lexer = new Lexer($value); 45 | 46 | foreach ($expected as $token) { 47 | $lexer->moveNext(); 48 | 49 | $actual = $lexer->lookahead; 50 | 51 | $this->assertEquals($token[0], $actual['type']); 52 | $this->assertEquals($token[1], $actual['value']); 53 | $this->assertEquals($token[2], $actual['position']); 54 | } 55 | } 56 | 57 | public function testTokenRecognitionReuseLexer() 58 | { 59 | $lexer = new Lexer(); 60 | 61 | foreach ($this->tokenData() as $name => $testData) { 62 | $lexer->setInput($testData['value']); 63 | 64 | foreach ($testData['expected'] as $token) { 65 | $lexer->moveNext(); 66 | 67 | $actual = $lexer->lookahead; 68 | 69 | $this->assertEquals($token[0], $actual['type']); 70 | $this->assertEquals($token[1], $actual['value']); 71 | $this->assertEquals($token[2], $actual['position']); 72 | } 73 | } 74 | } 75 | 76 | /** 77 | * @return array 78 | */ 79 | public function tokenData() 80 | { 81 | return array( 82 | 'POINT' => array( 83 | 'value' => 'POINT', 84 | 'expected' => array( 85 | array(Lexer::T_POINT, 'POINT', 0) 86 | ) 87 | ), 88 | 'POINTM' => array( 89 | 'value' => 'POINTM', 90 | 'expected' => array( 91 | array(Lexer::T_POINT, 'POINT', 0), 92 | array(Lexer::T_M, 'M', 5) 93 | ) 94 | ), 95 | 'POINT M' => array( 96 | 'value' => 'POINTM', 97 | 'expected' => array( 98 | array(Lexer::T_POINT, 'POINT', 0), 99 | array(Lexer::T_M, 'M', 5) 100 | ) 101 | ), 102 | 'POINTZ' => array( 103 | 'value' => 'POINTZ', 104 | 'expected' => array( 105 | array(Lexer::T_POINT, 'POINT', 0), 106 | array(Lexer::T_Z, 'Z', 5) 107 | ) 108 | ), 109 | 'POINT Z' => array( 110 | 'value' => 'POINT Z', 111 | 'expected' => array( 112 | array(Lexer::T_POINT, 'POINT', 0), 113 | array(Lexer::T_Z, 'Z', 6) 114 | ) 115 | ), 116 | 'POINT ZM' => array( 117 | 'value' => 'POINT ZM', 118 | 'expected' => array( 119 | array(Lexer::T_POINT, 'POINT', 0), 120 | array(Lexer::T_ZM, 'ZM', 6) 121 | ) 122 | ), 123 | 'POINTZM' => array( 124 | 'value' => 'POINTZM', 125 | 'expected' => array( 126 | array(Lexer::T_POINT, 'POINT', 0), 127 | array(Lexer::T_ZM, 'ZM', 5) 128 | ) 129 | ), 130 | 'LINESTRING' => array( 131 | 'value' => 'LINESTRING', 132 | 'expected' => array( 133 | array(Lexer::T_LINESTRING, 'LINESTRING', 0) 134 | ) 135 | ), 136 | 'LINESTRINGM' => array( 137 | 'value' => 'LINESTRINGM', 138 | 'expected' => array( 139 | array(Lexer::T_LINESTRING, 'LINESTRING', 0), 140 | array(Lexer::T_M, 'M', 10) 141 | ) 142 | ), 143 | 'POLYGON' => array( 144 | 'value' => 'POLYGON', 145 | 'expected' => array( 146 | array(Lexer::T_POLYGON, 'POLYGON', 0) 147 | ) 148 | ), 149 | 'POLYGONM' => array( 150 | 'value' => 'POLYGONM', 151 | 'expected' => array( 152 | array(Lexer::T_POLYGON, 'POLYGON', 0), 153 | array(Lexer::T_M, 'M', 7) 154 | ) 155 | ), 156 | 'MULTIPOINT' => array( 157 | 'value' => 'MULTIPOINT', 158 | 'expected' => array( 159 | array(Lexer::T_MULTIPOINT, 'MULTIPOINT', 0) 160 | ) 161 | ), 162 | 'MULTIPOINTM' => array( 163 | 'value' => 'MULTIPOINTM', 164 | 'expected' => array( 165 | array(Lexer::T_MULTIPOINT, 'MULTIPOINT', 0), 166 | array(Lexer::T_M, 'M', 10) 167 | ) 168 | ), 169 | 'MULTILINESTRING' => array( 170 | 'value' => 'MULTILINESTRING', 171 | 'expected' => array( 172 | array(Lexer::T_MULTILINESTRING, 'MULTILINESTRING', 0) 173 | ) 174 | ), 175 | 'MULTILINESTRINGM' => array( 176 | 'value' => 'MULTILINESTRINGM', 177 | 'expected' => array( 178 | array(Lexer::T_MULTILINESTRING, 'MULTILINESTRING', 0), 179 | array(Lexer::T_M, 'M', 15) 180 | ) 181 | ), 182 | 'MULTIPOLYGON' => array( 183 | 'value' => 'MULTIPOLYGON', 184 | 'expected' => array( 185 | array(Lexer::T_MULTIPOLYGON, 'MULTIPOLYGON', 0) 186 | ) 187 | ), 188 | 'MULTIPOLYGONM' => array( 189 | 'value' => 'MULTIPOLYGONM', 190 | 'expected' => array( 191 | array(Lexer::T_MULTIPOLYGON, 'MULTIPOLYGON', 0), 192 | array(Lexer::T_M, 'M', 12) 193 | ) 194 | ), 195 | 'GEOMETRYCOLLECTION' => array( 196 | 'value' => 'GEOMETRYCOLLECTION', 197 | 'expected' => array( 198 | array(Lexer::T_GEOMETRYCOLLECTION, 'GEOMETRYCOLLECTION', 0) 199 | ) 200 | ), 201 | 'GEOMETRYCOLLECTIONM' => array( 202 | 'value' => 'GEOMETRYCOLLECTIONM', 203 | 'expected' => array( 204 | array(Lexer::T_GEOMETRYCOLLECTION, 'GEOMETRYCOLLECTION', 0), 205 | array(Lexer::T_M, 'M', 18) 206 | ) 207 | ), 208 | 'COMPOUNDCURVE' => array( 209 | 'value' => 'COMPOUNDCURVE', 210 | 'expected' => array( 211 | array(Lexer::T_COMPOUNDCURVE, 'COMPOUNDCURVE', 0) 212 | ) 213 | ), 214 | 'COMPOUNDCURVEM' => array( 215 | 'value' => 'COMPOUNDCURVEM', 216 | 'expected' => array( 217 | array(Lexer::T_COMPOUNDCURVE, 'COMPOUNDCURVE', 0), 218 | array(Lexer::T_M, 'M', 13) 219 | ) 220 | ), 221 | 'CIRCULARSTRING' => array( 222 | 'value' => 'CIRCULARSTRING', 223 | 'expected' => array( 224 | array(Lexer::T_CIRCULARSTRING, 'CIRCULARSTRING', 0) 225 | ) 226 | ), 227 | 'CIRCULARSTRINGM' => array( 228 | 'value' => 'CIRCULARSTRINGM', 229 | 'expected' => array( 230 | array(Lexer::T_CIRCULARSTRING, 'CIRCULARSTRING', 0), 231 | array(Lexer::T_M, 'M', 14) 232 | ) 233 | ), 234 | '35' => array( 235 | 'value' => '35', 236 | 'expected' => array( 237 | array(Lexer::T_INTEGER, 35, 0) 238 | ) 239 | ), 240 | '-25' => array( 241 | 'value' => '-25', 242 | 'expected' => array( 243 | array(Lexer::T_INTEGER, -25, 0) 244 | ) 245 | ), 246 | '-120.33' => array( 247 | 'value' => '-120.33', 248 | 'expected' => array( 249 | array(Lexer::T_FLOAT, -120.33, 0) 250 | ) 251 | ), 252 | 'SRID' => array( 253 | 'value' => 'SRID', 254 | 'expected' => array( 255 | array(Lexer::T_SRID, 'SRID', 0) 256 | ) 257 | ), 258 | 'SRID=4326;LINESTRING(0 0.0, 10.1 -10.025, 20.5 25.9, 53E-003 60)' => array( 259 | 'value' => 'SRID=4326;LINESTRING(0 0.0, 10.1 -10.025, 20.5 25.9, 53E-003 60)', 260 | 'expected' => array( 261 | array(Lexer::T_SRID, 'SRID', 0), 262 | array(Lexer::T_EQUALS, '=', 4), 263 | array(Lexer::T_INTEGER, 4326, 5), 264 | array(Lexer::T_SEMICOLON, ';', 9), 265 | array(Lexer::T_LINESTRING, 'LINESTRING', 10), 266 | array(Lexer::T_OPEN_PARENTHESIS, '(', 20), 267 | array(Lexer::T_INTEGER, 0, 21), 268 | array(Lexer::T_FLOAT, 0, 23), 269 | array(Lexer::T_COMMA, ',', 26), 270 | array(Lexer::T_FLOAT, 10.1, 28), 271 | array(Lexer::T_FLOAT, -10.025, 33), 272 | array(Lexer::T_COMMA, ',', 40), 273 | array(Lexer::T_FLOAT, 20.5, 42), 274 | array(Lexer::T_FLOAT, 25.9, 47), 275 | array(Lexer::T_COMMA, ',', 51), 276 | array(Lexer::T_FLOAT, 0.053, 53), 277 | array(Lexer::T_INTEGER, 60, 61), 278 | array(Lexer::T_CLOSE_PARENTHESIS, ')', 63) 279 | ) 280 | ) 281 | ); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /tests/CrEOF/Geo/WKT/Tests/ParserTest.php: -------------------------------------------------------------------------------- 1 | 34 | * @license http://dlambert.mit-license.org MIT 35 | */ 36 | class ParserTest extends \PHPUnit_Framework_TestCase 37 | { 38 | /** 39 | * @param string $value 40 | * @param array $expected 41 | * 42 | * @dataProvider parserTestData 43 | */ 44 | public function testParser($value, $expected) 45 | { 46 | $parser = new Parser($value); 47 | 48 | if ($expected instanceof ExceptionInterface) { 49 | $this->setExpectedException(get_class($expected), $expected->getMessage()); 50 | } 51 | 52 | $actual = $parser->parse(); 53 | 54 | $this->assertEquals($expected, $actual); 55 | } 56 | 57 | public function testReusedParser() 58 | { 59 | $parser = new Parser(); 60 | 61 | foreach ($this->parserTestData() as $name => $testData) { 62 | $value = $testData['value']; 63 | $expected = $testData['expected']; 64 | 65 | if ($expected instanceof ExceptionInterface) { 66 | $this->setExpectedException(get_class($expected), $expected->getMessage()); 67 | } 68 | 69 | $actual = $parser->parse($value); 70 | 71 | $this->assertEquals($expected, $actual, 'Failed dataset "'. $name . '"'); 72 | } 73 | } 74 | 75 | /** 76 | * @return array[] 77 | */ 78 | public function parserTestData() 79 | { 80 | return array( 81 | 'testParsingGarbage' => array( 82 | 'value' => '@#_$%', 83 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 0: Error: Expected CrEOF\Geo\WKT\Lexer::T_TYPE, got "@" in value "@#_$%"') 84 | ), 85 | 'testParsingBadType' => array( 86 | 'value' => 'PNT(10 10)', 87 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 0: Error: Expected CrEOF\Geo\WKT\Lexer::T_TYPE, got "PNT" in value "PNT(10 10)"') 88 | ), 89 | 'testParsingPointValue' => array( 90 | 'value' => 'POINT(34.23 -87)', 91 | 'expected' => array( 92 | 'srid' => null, 93 | 'type' => 'POINT', 94 | 'value' => array(34.23, -87), 95 | 'dimension' => null 96 | ) 97 | ), 98 | 'testParsingPointZValue' => array( 99 | 'value' => 'POINT(34.23 -87 10)', 100 | 'expected' => array( 101 | 'srid' => null, 102 | 'type' => 'POINT', 103 | 'value' => array(34.23, -87, 10), 104 | 'dimension' => 'Z' 105 | ) 106 | ), 107 | 'testParsingPointDeclaredZValue' => array( 108 | 'value' => 'POINTZ(34.23 -87 10)', 109 | 'expected' => array( 110 | 'srid' => null, 111 | 'type' => 'POINT', 112 | 'value' => array(34.23, -87, 10), 113 | 'dimension' => 'Z' 114 | ) 115 | ), 116 | 'testParsingPointMValue' => array( 117 | 'value' => 'POINTM(34.23 -87 10)', 118 | 'expected' => array( 119 | 'srid' => null, 120 | 'type' => 'POINT', 121 | 'value' => array(34.23, -87, 10), 122 | 'dimension' => 'M' 123 | ) 124 | ), 125 | 'testParsingPointZMValue' => array( 126 | 'value' => 'POINT(34.23 -87 10 30)', 127 | 'expected' => array( 128 | 'srid' => null, 129 | 'type' => 'POINT', 130 | 'value' => array(34.23, -87, 10, 30), 131 | 'dimension' => 'ZM' 132 | ) 133 | ), 134 | 'testParsingPointDeclaredZMValue' => array( 135 | 'value' => 'POINT ZM(34.23 -87 10 30)', 136 | 'expected' => array( 137 | 'srid' => null, 138 | 'type' => 'POINT', 139 | 'value' => array(34.23, -87, 10, 30), 140 | 'dimension' => 'ZM' 141 | ) 142 | ), 143 | 'testParsingPointValueWithSrid' => array( 144 | 'value' => 'SRID=4326;POINT(34.23 -87)', 145 | 'expected' => array( 146 | 'srid' => 4326, 147 | 'type' => 'POINT', 148 | 'value' => array(34.23, -87), 149 | 'dimension' => null 150 | ) 151 | ), 152 | 'testParsingPointZValueWithSrid' => array( 153 | 'value' => 'SRID=4326;POINT(34.23 -87 10)', 154 | 'expected' => array( 155 | 'srid' => 4326, 156 | 'type' => 'POINT', 157 | 'value' => array(34.23, -87, 10), 158 | 'dimension' => 'Z' 159 | ) 160 | ), 161 | 'testParsingPointValueScientificWithSrid' => array( 162 | 'value' => 'SRID=4326;POINT(4.23e-005 -8E-003)', 163 | 'expected' => array( 164 | 'srid' => 4326, 165 | 'type' => 'POINT', 166 | 'value' => array(0.0000423, -0.008), 167 | 'dimension' => null 168 | ) 169 | ), 170 | 'testParsingPointValueWithBadSrid' => array( 171 | 'value' => 'SRID=432.6;POINT(34.23 -87)', 172 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 5: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got "432.6" in value "SRID=432.6;POINT(34.23 -87)"') 173 | ), 174 | 'testParsingPointValueMissingCoordinate' => array( 175 | 'value' => 'POINT(34.23)', 176 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 11: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got ")" in value "POINT(34.23)"') 177 | ), 178 | 'testParsingPointMValueMissingCoordinate' => array( 179 | 'value' => 'POINTM(34.23 10)', 180 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 15: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got ")" in value "POINTM(34.23 10)"') 181 | ), 182 | 'testParsingPointMValueExtraCoordinate' => array( 183 | 'value' => 'POINTM(34.23 10 30 40)', 184 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 19: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "40" in value "POINTM(34.23 10 30 40)"') 185 | ), 186 | 'testParsingPointZMValueMissingCoordinate' => array( 187 | 'value' => 'POINTZM(34.23 10 45)', 188 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 19: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got ")" in value "POINTZM(34.23 10 45)"') 189 | ), 190 | 'testParsingPointZMValueExtraCoordinate' => array( 191 | 'value' => 'POINTZM(34.23 10 45 4.5 99)', 192 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 24: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "99" in value "POINTZM(34.23 10 45 4.5 99)"') 193 | ), 194 | 'testParsingPointValueShortString' => array( 195 | 'value' => 'POINT(34.23', 196 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col -1: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got end of string. in value "POINT(34.23"') 197 | ), 198 | 'testParsingPointValueWrongScientificWithSrid' => array( 199 | 'value' => 'SRID=4326;POINT(4.23test-005 -8e-003)', 200 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 20: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got "test" in value "SRID=4326;POINT(4.23test-005 -8e-003)"') 201 | ), 202 | 'testParsingPointValueWithComma' => array( 203 | 'value' => 'POINT(10, 10)', 204 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 8: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got "," in value "POINT(10, 10)"') 205 | ), 206 | 'testParsingLineStringValue' => array( 207 | 'value' => 'LINESTRING(34.23 -87, 45.3 -92)', 208 | 'expected' => array( 209 | 'srid' => null, 210 | 'type' => 'LINESTRING', 211 | 'value' => array( 212 | array(34.23, -87), 213 | array(45.3, -92) 214 | ), 215 | 'dimension' => null 216 | ) 217 | ), 218 | 'testParsingLineStringZValue' => array( 219 | 'value' => 'LINESTRING(34.23 -87 10, 45.3 -92 10)', 220 | 'expected' => array( 221 | 'srid' => null, 222 | 'type' => 'LINESTRING', 223 | 'value' => array( 224 | array(34.23, -87, 10), 225 | array(45.3, -92, 10) 226 | ), 227 | 'dimension' => 'Z' 228 | ) 229 | ), 230 | 'testParsingLineStringMValue' => array( 231 | 'value' => 'LINESTRINGM(34.23 -87 10, 45.3 -92 10)', 232 | 'expected' => array( 233 | 'srid' => null, 234 | 'type' => 'LINESTRING', 235 | 'value' => array( 236 | array(34.23, -87, 10), 237 | array(45.3, -92, 10) 238 | ), 239 | 'dimension' => 'M' 240 | ) 241 | ), 242 | 'testParsingLineStringZMValue' => array( 243 | 'value' => 'LINESTRINGZM(34.23 -87 10 20, 45.3 -92 10 20)', 244 | 'expected' => array( 245 | 'srid' => null, 246 | 'type' => 'LINESTRING', 247 | 'value' => array( 248 | array(34.23, -87, 10, 20), 249 | array(45.3, -92, 10, 20) 250 | ), 251 | 'dimension' => 'ZM' 252 | ) 253 | ), 254 | 'testParsingLineStringValueWithSrid' => array( 255 | 'value' => 'SRID=4326;LINESTRING(34.23 -87, 45.3 -92)', 256 | 'expected' => array( 257 | 'srid' => 4326, 258 | 'type' => 'LINESTRING', 259 | 'value' => array( 260 | array(34.23, -87), 261 | array(45.3, -92) 262 | ), 263 | 'dimension' => null 264 | ) 265 | ), 266 | 'testParsingLineStringValueMissingCoordinate' => array( 267 | 'value' => 'LINESTRING(34.23 -87, 45.3)', 268 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 26: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got ")" in value "LINESTRING(34.23 -87, 45.3)"') 269 | ), 270 | 'testParsingLineStringValueMismatchedDimensions' => array( 271 | 'value' => 'LINESTRING(34.23 -87, 45.3 56 23.4)', 272 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 30: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "23.4" in value "LINESTRING(34.23 -87, 45.3 56 23.4)"') 273 | ), 274 | 'testParsingPolygonValue' => array( 275 | 'value' => 'POLYGON((0 0,10 0,10 10,0 10,0 0))', 276 | 'expected' => array( 277 | 'srid' => null, 278 | 'type' => 'POLYGON', 279 | 'value' => array( 280 | array( 281 | array(0, 0), 282 | array(10, 0), 283 | array(10, 10), 284 | array(0, 10), 285 | array(0, 0) 286 | ) 287 | ) , 288 | 'dimension' => null 289 | ) 290 | ), 291 | 'testParsingPolygonZValue' => array( 292 | 'value' => 'POLYGON((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0))', 293 | 'expected' => array( 294 | 'srid' => null, 295 | 'type' => 'POLYGON', 296 | 'value' => array( 297 | array( 298 | array(0, 0, 0), 299 | array(10, 0, 0), 300 | array(10, 10, 0), 301 | array(0, 10, 0), 302 | array(0, 0, 0) 303 | ) 304 | ) , 305 | 'dimension' => 'Z' 306 | ) 307 | ), 308 | 'testParsingPolygonMValue' => array( 309 | 'value' => 'POLYGONM((0 0 0,10 0 0,10 10 0,0 10 0,0 0 0))', 310 | 'expected' => array( 311 | 'srid' => null, 312 | 'type' => 'POLYGON', 313 | 'value' => array( 314 | array( 315 | array(0, 0, 0), 316 | array(10, 0, 0), 317 | array(10, 10, 0), 318 | array(0, 10, 0), 319 | array(0, 0, 0) 320 | ) 321 | ) , 322 | 'dimension' => 'M' 323 | ) 324 | ), 325 | 'testParsingPolygonZMValue' => array( 326 | 'value' => 'POLYGONZM((0 0 0 1,10 0 0 1,10 10 0 1,0 10 0 1,0 0 0 1))', 327 | 'expected' => array( 328 | 'srid' => null, 329 | 'type' => 'POLYGON', 330 | 'value' => array( 331 | array( 332 | array(0, 0, 0, 1), 333 | array(10, 0, 0, 1), 334 | array(10, 10, 0, 1), 335 | array(0, 10, 0, 1), 336 | array(0, 0, 0, 1) 337 | ) 338 | ) , 339 | 'dimension' => 'ZM' 340 | ) 341 | ), 342 | 'testParsingPolygonValueWithSrid' => array( 343 | 'value' => 'SRID=4326;POLYGON((0 0,10 0,10 10,0 10,0 0))', 344 | 'expected' => array( 345 | 'srid' => 4326, 346 | 'type' => 'POLYGON', 347 | 'value' => array( 348 | array( 349 | array(0, 0), 350 | array(10, 0), 351 | array(10, 10), 352 | array(0, 10), 353 | array(0, 0) 354 | ) 355 | ), 356 | 'dimension' => null 357 | ) 358 | ), 359 | 'testParsingPolygonValueMultiRing' => array( 360 | 'value' => 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))', 361 | 'expected' => array( 362 | 'srid' => null, 363 | 'type' => 'POLYGON', 364 | 'value' => array( 365 | array( 366 | array(0, 0), 367 | array(10, 0), 368 | array(10, 10), 369 | array(0, 10), 370 | array(0, 0) 371 | ), 372 | array( 373 | array(5, 5), 374 | array(7, 5), 375 | array(7, 7), 376 | array(5, 7), 377 | array(5, 5) 378 | ) 379 | ), 380 | 'dimension' => null 381 | ) 382 | ), 383 | 'testParsingPolygonValueMultiRingWithSrid' => array( 384 | 'value' => 'SRID=4326;POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))', 385 | 'expected' => array( 386 | 'srid' => 4326, 387 | 'type' => 'POLYGON', 388 | 'value' => array( 389 | array( 390 | array(0, 0), 391 | array(10, 0), 392 | array(10, 10), 393 | array(0, 10), 394 | array(0, 0) 395 | ), 396 | array( 397 | array(5, 5), 398 | array(7, 5), 399 | array(7, 7), 400 | array(5, 7), 401 | array(5, 5) 402 | ) 403 | ), 404 | 'dimension' => null 405 | ) 406 | ), 407 | 'testParsingPolygonValueMissingParenthesis' => array( 408 | 'value' => 'POLYGON(0 0,10 0,10 10,0 10,0 0)', 409 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 8: Error: Expected CrEOF\Geo\WKT\Lexer::T_OPEN_PARENTHESIS, got "0" in value "POLYGON(0 0,10 0,10 10,0 10,0 0)"') 410 | ), 411 | 'testParsingPolygonValueMismatchedDimension' => array( 412 | 'value' => 'POLYGON((0 0,10 0,10 10 10,0 10,0 0))', 413 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 24: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "10" in value "POLYGON((0 0,10 0,10 10 10,0 10,0 0))"') 414 | ), 415 | 'testParsingPolygonValueMultiRingMissingComma' => array( 416 | 'value' => 'POLYGON((0 0,10 0,10 10,0 10,0 0)(5 5,7 5,7 7,5 7,5 5))', 417 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 33: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "(" in value "POLYGON((0 0,10 0,10 10,0 10,0 0)(5 5,7 5,7 7,5 7,5 5))"') 418 | ), 419 | 'testParsingMultiPointValue' => array( 420 | 'value' => 'MULTIPOINT(0 0,10 0,10 10,0 10)', 421 | 'expected' => array( 422 | 'srid' => null, 423 | 'type' => 'MULTIPOINT', 424 | 'value' => array( 425 | array(0, 0), 426 | array(10, 0), 427 | array(10, 10), 428 | array(0, 10) 429 | ), 430 | 'dimension' => null 431 | ) 432 | ), 433 | 'testParsingMultiPointMValue' => array( 434 | 'value' => 'MULTIPOINTM(0 0 0,10 0 0,10 10 0,0 10 0)', 435 | 'expected' => array( 436 | 'srid' => null, 437 | 'type' => 'MULTIPOINT', 438 | 'value' => array( 439 | array(0, 0, 0), 440 | array(10, 0, 0), 441 | array(10, 10, 0), 442 | array(0, 10, 0) 443 | ), 444 | 'dimension' => 'M' 445 | ) 446 | ), 447 | 'testParsingMultiPointValueWithSrid' => array( 448 | 'value' => 'SRID=4326;MULTIPOINT(0 0,10 0,10 10,0 10)', 449 | 'expected' => array( 450 | 'srid' => 4326, 451 | 'type' => 'MULTIPOINT', 452 | 'value' => array( 453 | array(0, 0), 454 | array(10, 0), 455 | array(10, 10), 456 | array(0, 10) 457 | ), 458 | 'dimension' => null 459 | ) 460 | ), 461 | 'testParsingMultiPointValueWithExtraParenthesis' => array( 462 | 'value' => 'MULTIPOINT((0 0,10 0,10 10,0 10))', 463 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 11: Error: Expected CrEOF\Geo\WKT\Lexer::T_INTEGER, got "(" in value "MULTIPOINT((0 0,10 0,10 10,0 10))"') 464 | ), 465 | 'testParsingMultiLineStringValue' => array( 466 | 'value' => 'MULTILINESTRING((0 0,10 0,10 10,0 10),(5 5,7 5,7 7,5 7))', 467 | 'expected' => array( 468 | 'srid' => null, 469 | 'type' => 'MULTILINESTRING', 470 | 'value' => array( 471 | array( 472 | array(0, 0), 473 | array(10, 0), 474 | array(10, 10), 475 | array(0, 10), 476 | ), 477 | array( 478 | array(5, 5), 479 | array(7, 5), 480 | array(7, 7), 481 | array(5, 7), 482 | ) 483 | ), 484 | 'dimension' => null 485 | ) 486 | ), 487 | 'testParsingMultiLineStringZValue' => array( 488 | 'value' => 'MULTILINESTRING((0 0 0,10 0 0,10 10 0,0 10 0),(5 5 1,7 5 1,7 7 1,5 7 1))', 489 | 'expected' => array( 490 | 'srid' => null, 491 | 'type' => 'MULTILINESTRING', 492 | 'value' => array( 493 | array( 494 | array(0, 0, 0), 495 | array(10, 0, 0), 496 | array(10, 10, 0), 497 | array(0, 10, 0), 498 | ), 499 | array( 500 | array(5, 5, 1), 501 | array(7, 5, 1), 502 | array(7, 7, 1), 503 | array(5, 7, 1), 504 | ) 505 | ), 506 | 'dimension' => 'Z' 507 | ) 508 | ), 509 | 'testParsingMultiLineStringValueWithSrid' => array( 510 | 'value' => 'SRID=4326;MULTILINESTRING((0 0,10 0,10 10,0 10),(5 5,7 5,7 7,5 7))', 511 | 'expected' => array( 512 | 'srid' => 4326, 513 | 'type' => 'MULTILINESTRING', 514 | 'value' => array( 515 | array( 516 | array(0, 0), 517 | array(10, 0), 518 | array(10, 10), 519 | array(0, 10), 520 | ), 521 | array( 522 | array(5, 5), 523 | array(7, 5), 524 | array(7, 7), 525 | array(5, 7), 526 | ) 527 | ), 528 | 'dimension' => null 529 | ) 530 | ), 531 | 'testParsingMultiLineStringValueMissingComma' => array( 532 | 'value' => 'MULTILINESTRING((0 0,10 0,10 10,0 10)(5 5,7 5,7 7,5 7))', 533 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 37: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "(" in value "MULTILINESTRING((0 0,10 0,10 10,0 10)(5 5,7 5,7 7,5 7))"') 534 | ), 535 | 'testParsingMultiPolygonValue' => array( 536 | 'value' => 'MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5)),((1 1, 3 1, 3 3, 1 3, 1 1)))', 537 | 'expected' => array( 538 | 'srid' => null, 539 | 'type' => 'MULTIPOLYGON', 540 | 'value' => array( 541 | array( 542 | array( 543 | array(0, 0), 544 | array(10, 0), 545 | array(10, 10), 546 | array(0, 10), 547 | array(0, 0) 548 | ), 549 | array( 550 | array(5, 5), 551 | array(7, 5), 552 | array(7, 7), 553 | array(5, 7), 554 | array(5, 5) 555 | ) 556 | ), 557 | array( 558 | array( 559 | array(1, 1), 560 | array(3, 1), 561 | array(3, 3), 562 | array(1, 3), 563 | array(1, 1) 564 | ) 565 | ) 566 | ), 567 | 'dimension' => null 568 | ) 569 | ), 570 | 'testParsingMultiPolygonValueWithSrid' => array( 571 | 'value' => 'SRID=4326;MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5)),((1 1, 3 1, 3 3, 1 3, 1 1)))', 572 | 'expected' => array( 573 | 'srid' => 4326, 574 | 'type' => 'MULTIPOLYGON', 575 | 'value' => array( 576 | array( 577 | array( 578 | array(0, 0), 579 | array(10, 0), 580 | array(10, 10), 581 | array(0, 10), 582 | array(0, 0) 583 | ), 584 | array( 585 | array(5, 5), 586 | array(7, 5), 587 | array(7, 7), 588 | array(5, 7), 589 | array(5, 5) 590 | ) 591 | ), 592 | array( 593 | array( 594 | array(1, 1), 595 | array(3, 1), 596 | array(3, 3), 597 | array(1, 3), 598 | array(1, 1) 599 | ) 600 | ) 601 | ), 602 | 'dimension' => null 603 | ) 604 | ), 605 | 'testParsingMultiPolygonValueMissingParenthesis' => array( 606 | 'value' => 'MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5)),(1 1, 3 1, 3 3, 1 3, 1 1))', 607 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 64: Error: Expected CrEOF\Geo\WKT\Lexer::T_OPEN_PARENTHESIS, got "1" in value "MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5)),(1 1, 3 1, 3 3, 1 3, 1 1))"') 608 | ), 609 | 'testParsingGeometryCollectionValue' => array( 610 | 'value' => 'GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))', 611 | 'expected' => array( 612 | 'srid' => null, 613 | 'type' => 'GEOMETRYCOLLECTION', 614 | 'value' => array( 615 | array( 616 | 'type' => 'POINT', 617 | 'value' => array(10, 10) 618 | ), 619 | array( 620 | 'type' => 'POINT', 621 | 'value' => array(30, 30) 622 | ), 623 | array( 624 | 'type' => 'LINESTRING', 625 | 'value' => array( 626 | array(15, 15), 627 | array(20, 20) 628 | ) 629 | ) 630 | ), 631 | 'dimension' => null 632 | ) 633 | ), 634 | 'testParsingGeometryCollectionMValue' => array( 635 | 'value' => 'GEOMETRYCOLLECTIONM(POINT(10 10 0), POINT(30 30 0), LINESTRING(15 15 0, 20 20 0))', 636 | 'expected' => array( 637 | 'srid' => null, 638 | 'type' => 'GEOMETRYCOLLECTION', 639 | 'value' => array( 640 | array( 641 | 'type' => 'POINT', 642 | 'value' => array(10, 10, 0) 643 | ), 644 | array( 645 | 'type' => 'POINT', 646 | 'value' => array(30, 30, 0) 647 | ), 648 | array( 649 | 'type' => 'LINESTRING', 650 | 'value' => array( 651 | array(15, 15, 0), 652 | array(20, 20, 0) 653 | ) 654 | ) 655 | ), 656 | 'dimension' => 'M' 657 | ) 658 | ), 659 | 'testParsingGeometryCollectionValueWithSrid' => array( 660 | 'value' => 'SRID=4326;GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))', 661 | 'expected' => array( 662 | 'srid' => 4326, 663 | 'type' => 'GEOMETRYCOLLECTION', 664 | 'value' => array( 665 | array( 666 | 'type' => 'POINT', 667 | 'value' => array(10, 10) 668 | ), 669 | array( 670 | 'type' => 'POINT', 671 | 'value' => array(30, 30) 672 | ), 673 | array( 674 | 'type' => 'LINESTRING', 675 | 'value' => array( 676 | array(15, 15), 677 | array(20, 20) 678 | ) 679 | ) 680 | ), 681 | 'dimension' => null 682 | ) 683 | ), 684 | 'testParsingGeometryCollectionValueWithBadType' => array( 685 | 'value' => 'GEOMETRYCOLLECTION(PNT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))', 686 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 19: Error: Expected CrEOF\Geo\WKT\Lexer::T_TYPE, got "PNT" in value "GEOMETRYCOLLECTION(PNT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))"') 687 | ), 688 | 'testParsingGeometryCollectionValueWithMismatchedDimenstion' => array( 689 | 'value' => 'GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30 10), LINESTRING(15 15, 20 20))', 690 | 'expected' => new UnexpectedValueException('[Syntax Error] line 0, col 45: Error: Expected CrEOF\Geo\WKT\Lexer::T_CLOSE_PARENTHESIS, got "10" in value "GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30 10), LINESTRING(15 15, 20 20))"') 691 | ) 692 | ); 693 | } 694 | } 695 | --------------------------------------------------------------------------------