Passed
Push — master ( 954049...2e99dd )
by Leszek
07:28
created

FloatCoordinateParser   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 95.74%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 12
lcom 0
cbo 2
dl 0
loc 121
ccs 45
cts 47
cp 0.9574
rs 10
c 1
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getParsedCoordinate() 0 3 1
C areValidCoordinates() 0 45 7
B splitString() 0 43 4
1
<?php
2
3
namespace DataValues\Geo\Parsers;
4
5
use ValueParsers\ParseException;
6
7
/**
8
 * @since 0.1
9
 *
10
 * @license GPL-2.0+
11
 * @author Jeroen De Dauw < [email protected] >
12
 * @author H. Snater < [email protected] >
13
 */
14
class FloatCoordinateParser extends LatLongParserBase {
15
16
	const FORMAT_NAME = 'float-coordinate';
17
18
	/**
19
	 * @see LatLongParserBase::getParsedCoordinate
20
	 *
21
	 * @param string $coordinateSegment
22
	 *
23
	 * @return float
24
	 */
25 18
	protected function getParsedCoordinate( $coordinateSegment ) {
26 18
		return (float)$this->resolveDirection( str_replace( ' ', '', $coordinateSegment ) );
27
	}
28
29
	/**
30
	 * @see LatLongParserBase::areValidCoordinates
31
	 *
32
	 * @param string[] $normalizedCoordinateSegments
33
	 *
34
	 * @return bool
35
	 */
36 18
	protected function areValidCoordinates( array $normalizedCoordinateSegments ) {
37
		// TODO: Implement localized decimal separator.
38 18
		$baseRegExp = '\d{1,3}(\.\d{1,20})?';
39
40
		// Cache whether the coordinates are specified in directional format (a mixture of
41
		// directional and non-directional is regarded invalid).
42 18
		$directional = false;
43
44 18
		$match = false;
45
46 18
		foreach ( $normalizedCoordinateSegments as $i => $segment ) {
47 18
			$segment = str_replace( ' ', '', $segment );
48
49
			$direction = '('
50 18
				. $this->getOption( self::OPT_NORTH_SYMBOL ) . '|'
51 18
				. $this->getOption( self::OPT_SOUTH_SYMBOL ) . ')';
52
53 18
			if ( $i === 1 ) {
54
				$direction = '('
55 18
					. $this->getOption( self::OPT_EAST_SYMBOL ) . '|'
56 18
					. $this->getOption( self::OPT_WEST_SYMBOL ) . ')';
57
			}
58
59 18
			$match = preg_match(
60 18
				'/^(' . $baseRegExp . $direction . '|' . $direction . $baseRegExp . ')$/i',
61 18
				$segment
62
			);
63
64 18
			if ( $directional && !$match ) {
65
				// Latitude is directional, longitude not.
66
				break;
67 18
			} elseif ( $match ) {
68 10
				continue;
69
			}
70
71 8
			$match = preg_match( '/^(-)?' . $baseRegExp . '$/i', $segment );
72
73 8
			if ( !$match ) {
74
				// Does neither match directional nor non-directional.
75
				break;
76
			}
77
		}
78
79 18
		return ( 1 === $match );
80
	}
81
82
	/**
83
	 * @see LatLongParserBase::splitString
84
	 *
85
	 * @param string $normalizedCoordinateString
86
	 *
87
	 * @throws ParseException if unable to split input string into two segments
88
	 * @return string[]
89
	 */
90 20
	protected function splitString( $normalizedCoordinateString ) {
91 20
		$separator = $this->getOption( self::OPT_SEPARATOR_SYMBOL );
92
93 20
		$normalizedCoordinateSegments = explode( $separator, $normalizedCoordinateString );
94
95 20
		if ( count( $normalizedCoordinateSegments ) !== 2 ) {
96
			// Separator not present within the string, trying to figure out the segments by
97
			// splitting at the the first SPACE after the first direction character or digit:
98 13
			$numberRegEx = '-?\d{1,3}(\.\d{1,20})?';
99
100
			$ns = '('
101 13
				. $this->getOption( self::OPT_NORTH_SYMBOL ) . '|'
102 13
				. $this->getOption( self::OPT_SOUTH_SYMBOL ) .')';
103
104 13
			$latitudeRegEx = '(' . $ns . '\s*)?' . $numberRegEx . '(\s*' . $ns . ')?';
105
106
			$ew = '('
107 13
				. $this->getOption( self::OPT_EAST_SYMBOL ) . '|'
108 13
				. $this->getOption( self::OPT_WEST_SYMBOL ) .')';
109
110 13
			$longitudeRegEx = '(' . $ew . '\s*)?' . $numberRegEx . '(\s*' . $ew . ')?';
111
112 13
			$match = preg_match(
113 13
				'/^(' . $latitudeRegEx . ') (' . $longitudeRegEx . ')$/i',
114 13
				$normalizedCoordinateString,
115 13
				$matches
116
			);
117
118 13
			if ( $match ) {
119 11
				$normalizedCoordinateSegments = array( $matches[1], $matches[7] );
120
			}
121
		}
122
123 20
		if ( count( $normalizedCoordinateSegments ) !== 2 ) {
124 2
			throw new ParseException(
125 2
				'Unable to split input into two coordinate segments',
126 2
				$normalizedCoordinateString,
127 2
				self::FORMAT_NAME
128
			);
129
		}
130
131 18
		return $normalizedCoordinateSegments;
132
	}
133
134
}
135