diff --git a/src/Validation/Validation.php b/src/Validation/Validation.php index 146eebe5cb8..a4f34bf9035 100644 --- a/src/Validation/Validation.php +++ b/src/Validation/Validation.php @@ -34,7 +34,9 @@ class Validation * @var array */ protected static $_pattern = [ - 'hostname' => '(?:[_\p{L}0-9][-_\p{L}0-9]*\.)*(?:[\p{L}0-9][-\p{L}0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,})' + 'hostname' => '(?:[_\p{L}0-9][-_\p{L}0-9]*\.)*(?:[\p{L}0-9][-\p{L}0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,})', + 'latitude' => '[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)', + 'longitude' => '[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)', ]; /** @@ -1020,6 +1022,45 @@ public static function uploadedFile($file, array $options = []) return true; } +/** + * Validates a geographic coordinate. + * + * Supported formats are right now: + * + * - , Example: -25.274398, 133.775136 + * + * ### Options + * + * - `type` - A string of the coordinate format, right now only `longLat`. + * - `longLat` - By default `both`, can be `long` and `lat` as well to validate + * only a part of the coordinate. + * + * @param string Geographic location as string + * @param array $options Options for the validation logic. + * @return boolean + */ + public static function geoCoordinate($value, array $options = []) + { + $options += [ + 'longLat' => 'both', + 'type' => 'longLat' + ]; + if ($options['type'] === 'longLat') { + if ($options['longLat'] === 'both') { + $pattern = '/^' . self::$_pattern['latitude'] . ',\s*' . self::$_pattern['longitude'] . '$/'; + } + if ($options['longLat'] === 'long') { + $pattern = '/^' . self::$_pattern['longitude'] . '$/'; + } + if ($options['longLat'] === 'lat') { + $pattern = '/^' . self::$_pattern['latitude'] . '$/'; + } + } else { + throw new \RuntimeException(sprintf('Unsupported coordinate type "%s".', $options['type'])); + } + return (bool)preg_match($pattern, $value); + } + /** * Converts an array representing a date or datetime into a ISO string. * The arrays are typically sent for validation from a form generated by diff --git a/tests/TestCase/Validation/ValidationTest.php b/tests/TestCase/Validation/ValidationTest.php index c7cc77d96ed..499787df225 100644 --- a/tests/TestCase/Validation/ValidationTest.php +++ b/tests/TestCase/Validation/ValidationTest.php @@ -2490,4 +2490,19 @@ public function testCompareWith() $context = []; $this->assertFalse(Validation::compareWith('a value', 'other', $context)); } + + /** + * Test the geoCoordinate method. + * + * @return void + */ + public function testGeoCoordinate() + { + $this->assertTrue(Validation::geoCoordinate('51.165691, 10.451526')); + $this->assertTrue(Validation::geoCoordinate('-25.274398, 133.775136')); + $this->assertFalse(Validation::geoCoordinate('51.165691 10.451526')); + $this->assertFalse(Validation::geoCoordinate('-245.274398, -133.775136')); + $this->assertTrue(Validation::geoCoordinate('51.165691', ['longLat' => 'lat'])); + $this->assertTrue(Validation::geoCoordinate('10.451526', ['longLat' => 'long'])); + } }