Daniel Werner has submitted this change and it was merged. Change subject: Remove parsing logic from GeoCoordinateParser and use new format specific parsers ......................................................................
Remove parsing logic from GeoCoordinateParser and use new format specific parsers Later need to figure out what to do with this class; probably want to take the sub parsers in the constructor Change-Id: I30788a3378da3ab3c601c44e5ae0e3c2ad8c80ec --- M ValueParsers/includes/parsers/GeoCoordinateParser.php 1 file changed, 15 insertions(+), 315 deletions(-) Approvals: Daniel Werner: Verified; Looks good to me, approved jenkins-bot: Verified diff --git a/ValueParsers/includes/parsers/GeoCoordinateParser.php b/ValueParsers/includes/parsers/GeoCoordinateParser.php index a988a24..50e62ad 100644 --- a/ValueParsers/includes/parsers/GeoCoordinateParser.php +++ b/ValueParsers/includes/parsers/GeoCoordinateParser.php @@ -106,334 +106,34 @@ * @throws ParseException */ protected function stringParse( $value ) { - $value = $this->getNormalizedNotation( $value ); - - $notationType = $this->getCoordinatesType( $value ); - - if ( $notationType === false ) { - throw new ParseException( 'Not a geographical coordinate' ); - } - - $coordinates = explode( $this->getOption( self::OPT_SEPARATOR_SYMBOL ), $value ); - - if ( count( $coordinates ) !== 2 ) { - throw new ParseException( 'A coordinates string with an incorrect segment count has made it through validation' ); - } - - list( $latitude, $longitude ) = $coordinates; - - $latitude = $this->getParsedCoordinate( $notationType, $latitude ); - $longitude = $this->getParsedCoordinate( $notationType, $longitude ); - - $coordinate = new GeoCoordinateValue( $latitude, $longitude ); - - return $coordinate; - } - - /** - * Parsers a single coordinate (either latitude or longitude) and returns it as a float. - * - * @since 0.1 - * - * @param string $notationType - * @param string $coordinate - * - * @return float - * - * @throws ParseException - */ - protected function getParsedCoordinate( $notationType, $coordinate ) { - $coordinate = $this->resolveDirection( $coordinate ); - - switch ( $notationType ) { - case self::TYPE_FLOAT: - return (float)$coordinate; - case self::TYPE_DD: - return $this->parseDDCoordinate( $coordinate ); - case self::TYPE_DM: - return $this->parseDMCoordinate( $coordinate ); - case self::TYPE_DMS: - return $this->parseDMSCoordinate( $coordinate ); - default: - throw new ParseException( 'Invalid coordinate type specified' ); - } - } - - /** - * Returns the type of the provided coordinates, or false if they are invalid. - * You can use this as validation function, but be sure to use ===, since 0 can be returned. - * - * @since 0.1 - * - * @param string $coordinates - * - * @return integer or false - */ - protected function getCoordinatesType( $coordinates ) { - switch ( true ) { - case $this->areFloatCoordinates( $coordinates ): - return self::TYPE_FLOAT; - break; - case $this->areDMSCoordinates( $coordinates ): - return self::TYPE_DMS; - break; - case $this->areDDCoordinates( $coordinates ): - return self::TYPE_DD; - break; - case $this->areDMCoordinates( $coordinates ): - return self::TYPE_DM; - break; - default: - return false; - } - } - - /** - * Turns directional notation (N/E/S/W) of a single coordinate into non-directional notation (+/-). - * This method assumes there are no preceding or tailing spaces. - * - * @since 0.1 - * - * @param string $coordinate - * - * @return string - */ - protected function resolveDirection( $coordinate ) { - // Get the last char, which could be a direction indicator - $lastChar = strtoupper( substr( $coordinate, -1 ) ); - - $n = $this->getOption( self::OPT_NORTH_SYMBOL ); - $e = $this->getOption( self::OPT_EAST_SYMBOL ); - $s = $this->getOption( self::OPT_SOUTH_SYMBOL ); - $w = $this->getOption( self::OPT_WEST_SYMBOL ); - - // If there is a direction indicator, remove it, and prepend a minus sign for south and west directions. - // If there is no direction indicator, the coordinate is already non-directional and no work is required. - if ( in_array( $lastChar, array( $n, $e, $s, $w ) ) ) { - $coordinate = substr( $coordinate, 0, -1 ); - - if ( in_array( $lastChar, array( $s, $w ) ) ) { - $coordinate = '-' . $coordinate; + foreach ( $this->getParsers() as $parser ) { + try { + return $parser->parse( $value ); + } + catch ( ParseException $parseException ) { + continue; } } - return $coordinate; + throw new ParseException( 'The format of the coordinate could not be determined. Parsing failed.' ); } /** - * Returns a normalized version of the coordinate string. - * * @since 0.1 * - * @param string $coordinates - * - * @return string + * @return StringValueParser[] */ - protected function getNormalizedNotation( $coordinates ) { - $second = $this->getOption( self::OPT_SECOND_SYMBOL ); - $minute = $this->getOption( self::OPT_MINUTE_SYMBOL ); + protected function getParsers() { + $parsers = array(); - $coordinates = str_replace( array( '°', '°' ), $this->getOption( self::OPT_DEGREE_SYMBOL ), $coordinates ); - $coordinates = str_replace( array( '´', '´' ), $second, $coordinates ); - $coordinates = str_replace( array( '′', '′', '´', '′' ), $minute, $coordinates ); - $coordinates = str_replace( array( '″', '″', $minute . $minute, '´´', '′′', '″' ), $second, $coordinates ); + $parsers[] = new FloatCoordinateParser( $this->options ); + $parsers[] = new DmsCoordinateParser( $this->options ); + $parsers[] = new DdCoordinateParser( $this->options ); + $parsers[] = new DmCoordinateParser( $this->options ); - $coordinates = $this->removeInvalidChars( $coordinates ); - - return $coordinates; + return $parsers; } - /** - * Returns a string with whitespace, control characters and characters with ASCII values above 126 removed. - * - * @since 0.1 - * - * @param string $string - * - * @return string - */ - protected function removeInvalidChars( $string ) { - $filtered = array(); - - foreach ( str_split( $string ) as $character ) { - $asciiValue = ord( $character ); - - if ( ( $asciiValue > 32 && $asciiValue < 127 ) || $asciiValue == 194 || $asciiValue == 176 ) { - $filtered[] = $character; - } - } - - return implode( '', $filtered ); - } - - /** - * Takes a set of coordinates in DMS representation, and returns them in float representation. - * - * @since 0.1 - * - * @param string $coordinate - * - * @return float - */ - protected function parseDMSCoordinate( $coordinate ) { - $isNegative = $coordinate{0} == '-'; - - if ( $isNegative ) { - $coordinate = substr( $coordinate, 1 ); - } - - $degreePosition = strpos( $coordinate, $this->getOption( self::OPT_DEGREE_SYMBOL ) ); - $degrees = substr( $coordinate, 0, $degreePosition ); - - $minutePosition = strpos( $coordinate, $this->getOption( self::OPT_MINUTE_SYMBOL ) ); - - if ( $minutePosition === false ) { - $minutes = 0; - } - else { - $degSignLength = strlen( $this->getOption( self::OPT_DEGREE_SYMBOL ) ); - $minuteLength = $minutePosition - $degreePosition - $degSignLength; - $minutes = substr( $coordinate, $degreePosition + $degSignLength, $minuteLength ); - } - - $secondPosition = strpos( $coordinate, $this->getOption( self::OPT_SECOND_SYMBOL ) ); - - if ( $minutePosition === false ) { - $seconds = 0; - } - else { - $secondLength = $secondPosition - $minutePosition - 1; - $seconds = substr( $coordinate, $minutePosition + 1, $secondLength ); - } - - $coordinate = $degrees + ( $minutes + $seconds / 60 ) / 60; - - if ( $isNegative ) { - $coordinate *= -1; - } - - return (float)$coordinate; - } - - /** - * Takes a set of coordinates in Decimal Degree representation, and returns them in float representation. - * - * @since 0.1 - * - * @param string $coordinate - * - * @return float - */ - protected function parseDDCoordinate( $coordinate ) { - return (float)str_replace( $this->getOption( self::OPT_DEGREE_SYMBOL ), '', $coordinate ); - } - - /** - * Takes a set of coordinates in Decimal Minute representation, and returns them in float representation. - * - * @since 0.1 - * - * @param string $coordinate - * - * @return float - */ - protected function parseDMCoordinate( $coordinate ) { - $isNegative = $coordinate{0} == '-'; - - if ( $isNegative ) { - $coordinate = substr( $coordinate, 1 ); - } - - list( $degrees, $minutes ) = explode( $this->getOption( self::OPT_DEGREE_SYMBOL ), $coordinate ); - - $minutes = substr( $minutes, 0, -1 ); - - $coordinate = $degrees + $minutes / 60; - - if ( $isNegative ) { - $coordinate *= -1; - } - - return (float)$coordinate; - } - - /** - * returns whether the coordinates are in float representation. - * TODO: nicify - * - * @since 0.1 - * - * @param string $coordinates - * - * @return boolean - */ - protected function areFloatCoordinates( $coordinates ) { - $sep = $this->getOption( self::OPT_SEPARATOR_SYMBOL ); - - $match = preg_match( '/^(-)?\d{1,3}(\.\d{1,20})?' . $sep . '(-)?\d{1,3}(\.\d{1,20})?$/i', $coordinates ) // Non-directional - || preg_match( '/^\d{1,3}(\.\d{1,20})?(N|S)' . $sep . '\d{1,3}(\.\d{1,20})?(E|W)$/i', $coordinates ); // Directional; - - return $match; - } - - /** - * returns whether the coordinates are in DMS representation. - * TODO: nicify - * - * @since 0.1 - * - * @param string $coordinates - * - * @return boolean - */ - protected function areDMSCoordinates( $coordinates ) { - $sep = $this->getOption( self::OPT_SEPARATOR_SYMBOL ); - - $match = preg_match( '/^(-)?(\d{1,3}°)(\d{1,2}(\′|\'))?((\d{1,2}(″|"))?|(\d{1,2}\.\d{1,20}(″|"))?)' - . $sep . '(-)?(\d{1,3}°)(\d{1,2}(\′|\'))?((\d{1,2}(″|"))?|(\d{1,2}\.\d{1,20}(″|"))?)$/i', $coordinates ) // Non-directional - || preg_match( '/^(\d{1,3}°)(\d{1,2}(\′|\'))?((\d{1,2}(″|"))?|(\d{1,2}\.\d{1,20}(″|"))?)(N|S)' - . $sep . '(\d{1,3}°)(\d{1,2}(\′|\'))?((\d{1,2}(″|"))?|(\d{1,2}\.\d{1,20}(″|"))?)(E|W)$/i', $coordinates ); // Directional - - return $match; - } - - /** - * returns whether the coordinates are in Decimal Degree representation. - * TODO: nicify - * - * @since 0.1 - * - * @param string $coordinates - * - * @return boolean - */ - protected function areDDCoordinates( $coordinates ) { - $sep = $this->getOption( self::OPT_SEPARATOR_SYMBOL ); - - $match = preg_match( '/^(-)?\d{1,3}(|\.\d{1,20})°' . $sep . '(-)?\d{1,3}(|\.\d{1,20})°$/i', $coordinates ) // Non-directional - || preg_match( '/^\d{1,3}(|\.\d{1,20})°(N|S)' . $sep . '\d{1,3}(|\.\d{1,20})°(E|W)?$/i', $coordinates ); // Directional - - return $match; - } - - /** - * returns whether the coordinates are in Decimal Minute representation. - * TODO: nicify - * - * @since 0.1 - * - * @param string $coordinates - * - * @return boolean - */ - protected function areDMCoordinates( $coordinates ) { - $sep = $this->getOption( self::OPT_SEPARATOR_SYMBOL ); - - $match = preg_match( '/(-)?\d{1,3}°(\d{1,2}(\.\d{1,20}\')?)?' . $sep . '(-)?\d{1,3}°(\d{1,2}(\.\d{1,20}\')?)?$/i', $coordinates ) // Non-directional - || preg_match( '/\d{1,3}°(\d{1,2}(\.\d{1,20}\')?)?(N|S)' . $sep . '\d{1,3}°(\d{1,2}(\.\d{1,20}\')?)?(E|W)?$/i', $coordinates ); // Directional - - return $match; - } /** * Convenience function for determining if something is a valid coordinate string. -- To view, visit https://gerrit.wikimedia.org/r/59076 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I30788a3378da3ab3c601c44e5ae0e3c2ad8c80ec Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/DataValues Gerrit-Branch: master Gerrit-Owner: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: Daniel Werner <daniel.wer...@wikimedia.de> Gerrit-Reviewer: John Erling Blad <jeb...@gmail.com> Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits