Browse Source

Merge branch 'geo-validation' into 3.1

Merge changes from #7170 into 3.1
Mark Story 10 years ago
parent
commit
9084ce84ef
2 changed files with 109 additions and 1 deletions
  1. 72 1
      src/Validation/Validation.php
  2. 37 0
      tests/TestCase/Validation/ValidationTest.php

+ 72 - 1
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+)?)',
     ];
 
     /**
@@ -1027,6 +1029,75 @@ class Validation
     }
 
     /**
+     * Validates a geographic coordinate.
+     *
+     * Supported formats:
+     *
+     * - `<latitude>, <longitude>` Example: `-25.274398, 133.775136`
+     *
+     * ### Options
+     *
+     * - `type` - A string of the coordinate format, right now only `latLong`.
+     * - `format` - By default `both`, can be `long` and `lat` as well to validate
+     *   only a part of the coordinate.
+     *
+     * @param string $value Geographic location as string
+     * @param array $options Options for the validation logic.
+     * @return bool
+     */
+    public static function geoCoordinate($value, array $options = [])
+    {
+        $options += [
+            'format' => 'both',
+            'type' => 'latLong'
+        ];
+        if ($options['type'] !== 'latLong') {
+            throw new \RuntimeException(sprintf(
+                'Unsupported coordinate type "%s". Use "latLong" instead.',
+                $options['type']
+            ));
+        }
+        $pattern = '/^' . self::$_pattern['latitude'] . ',\s*' . self::$_pattern['longitude'] . '$/';
+        if ($options['format'] === 'long') {
+            $pattern = '/^' . self::$_pattern['longitude'] . '$/';
+        }
+        if ($options['format'] === 'lat') {
+            $pattern = '/^' . self::$_pattern['latitude'] . '$/';
+        }
+        return (bool)preg_match($pattern, $value);
+    }
+
+    /**
+     * Convenience method for latitude validation.
+     *
+     * @param string $value Latitude as string
+     * @param array $options Options for the validation logic.
+     * @return bool
+     * @link https://en.wikipedia.org/wiki/Latitude
+     * @see Validation::geoCoordinate()
+     */
+    public static function latitude($value, array $options = [])
+    {
+        $options['format'] = 'lat';
+        return self::geoCoordinate($value, $options);
+    }
+
+    /**
+     * Convenience method for longitude validation.
+     *
+     * @param string $value Latitude as string
+     * @param array $options Options for the validation logic.
+     * @return bool
+     * @link https://en.wikipedia.org/wiki/Longitude
+     * @see Validation::geoCoordinate()
+     */
+    public static function longitude($value, array $options = [])
+    {
+        $options['format'] = 'long';
+        return self::geoCoordinate($value, $options);
+    }
+
+    /**
      * Converts an array representing a date or datetime into a ISO string.
      * The arrays are typically sent for validation from a form generated by
      * the CakePHP FormHelper.

+ 37 - 0
tests/TestCase/Validation/ValidationTest.php

@@ -2527,4 +2527,41 @@ class ValidationTest extends TestCase
         $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', ['format' => 'lat']));
+        $this->assertTrue(Validation::geoCoordinate('10.451526', ['format' => 'long']));
+    }
+
+    /**
+     * Test the geoCoordinate method.
+     *
+     * @return void
+     */
+    public function testLatitude()
+    {
+        $this->assertTrue(Validation::latitude('51.165691'));
+        $this->assertFalse(Validation::latitude('200.23552'));
+    }
+
+    /**
+     * Test the geoCoordinate method.
+     *
+     * @return void
+     */
+    public function testLongitude()
+    {
+        $this->assertTrue(Validation::longitude('10.451526'));
+        $this->assertFalse(Validation::longitude('-190.52236'));
+    }
 }