Passed
Push — php73 ( 4b71d8 )
by Jeroen De
05:36
created

FloatCoordinateParser::splitString()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 4

Importance

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