Completed
Push — master ( 484b1a...998a69 )
by Jeroen De
03:30
created

CoordinateValue::parserDistance()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 0
cts 10
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 1
crap 12
1
<?php
2
3
namespace Maps\Semantic\DataValues;
4
5
use DataValues\Geo\Formatters\GeoCoordinateFormatter;
6
use DataValues\Geo\Parsers\GeoCoordinateParser;
7
use DataValues\Geo\Values\LatLongValue;
8
use InvalidArgumentException;
9
use MapsDistanceParser;
10
use SMW\Query\Language\Description;
11
use SMW\Query\Language\ThingDescription;
12
use SMWDataItem;
13
use SMWDataValue;
14
use SMWDIGeoCoord;
15
use SMWOutputs;
16
use ValueParsers\ParseException;
17
18
/**
19
 * @licence GNU GPL v2+
20
 * @author Jeroen De Dauw < [email protected] >
21
 * @author Markus Krötzsch
22
 */
23
class CoordinateValue extends SMWDataValue {
24
25
	private $wikiValue;
26
27
	/**
28
	 * @see SMWDataValue::setDataItem
29
	 * 
30
	 * @param SMWDataItem $dataItem
31
	 * 
32
	 * @return boolean
33
	 */
34
	protected function loadDataItem( SMWDataItem $dataItem ) {
35
		if ( $dataItem instanceof SMWDIGeoCoord ) {
0 ignored issues
show
Bug introduced by
The class SMWDIGeoCoord does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
36
			 $formattedValue = $this->getFormattedCoord( $dataItem );
37
38
			if ( $formattedValue !== null ) {
39
				$this->wikiValue = $formattedValue;
40
				$this->m_dataitem = $dataItem;
41
				return true;
42
			}
43
		}
44
45
		return false;
46
	}
47
48
	/**
49
	 * @param SMWDIGeoCoord $dataItem
50
	 * @param string|null $format
51
	 *
52
	 * @return string|null
53
	 */
54
	private function getFormattedCoord( SMWDIGeoCoord $dataItem, $format = null ) {
55
		global $smgQPCoodFormat;
56
57
		$options = new \ValueFormatters\FormatterOptions( [
58
			GeoCoordinateFormatter::OPT_FORMAT => $format === null ? $smgQPCoodFormat : $format, // TODO
59
		] );
60
61
		// TODO: $smgQPCoodDirectional
62
63
		$coordinateFormatter = new GeoCoordinateFormatter( $options );
64
65
		$value = new LatLongValue(
66
			$dataItem->getLatitude(),
67
			$dataItem->getLongitude()
68
		);
69
70
		return $coordinateFormatter->format( $value );
71
	}
72
	
73
	/**
74
	 * Overwrite SMWDataValue::getQueryDescription() to be able to process
75
	 * comparators between all values.
76
	 * 
77
	 * @param string $value
78
	 * 
79
	 * @return Description
80
	 * @throws InvalidArgumentException
81
	 */
82
	public function getQueryDescription( $value ) {
83
		if ( !is_string( $value ) ) {
84
			throw new InvalidArgumentException( '$value needs to be a string' );
85
		}
86
87
		list( $distance, $comparator ) = $this->parseUserValue( $value );
88
		$distance = $this->parserDistance( $distance );
89
90
		$this->setUserValue( $value );
91
92
		switch ( true ) {
93
			case !$this->isValid():
94
				return new ThingDescription();
95
			case $distance !== false:
96
				return new \Maps\Semantic\ValueDescriptions\AreaDescription( $this->getDataItem(), $comparator, $distance );
97
			default:
98
				return new \Maps\Semantic\ValueDescriptions\CoordinateDescription( $this->getDataItem(), null, $comparator );
99
		}
100
	}
101
102
	private function parserDistance( $distance ) {
103
		if ( $distance !== false ) {
104
			$distance = substr( trim( $distance ), 0, -1 );
105
106
			if ( !MapsDistanceParser::isDistance( $distance ) ) {
107
				$this->addError( wfMessage( 'semanticmaps-unrecognizeddistance', $distance )->text() );
108
				$distance = false;
109
			}
110
		}
111
112
		return $distance;
113
	}
114
115
	/**
116
	 * @see SMWDataValue::parseUserValue
117
	 */
118
	protected function parseUserValue( $value ) {
119
		if ( !is_string( $value ) ) {
120
			throw new InvalidArgumentException( '$value needs to be a string' );
121
		}
122
123
		$this->wikiValue = $value;
124
125
		$comparator = SMW_CMP_EQ;
126
		$distance = false;
127
128
		if ( $value === '' ) {
129
			$this->addError( wfMessage( 'smw_novalues' )->text() );
130
		} else {
131
			SMWDataValue::prepareValue( $value, $comparator );
132
133
			list( $coordinates, $distance ) = $this->findValueParts( $value );
134
135
			$this->tryParseAndSetDataItem( $coordinates );
136
		}
137
138
		return [ $distance, $comparator ];
139
	}
140
141
	private function findValueParts( $value ) {
142
		$parts = explode( '(', $value );
143
144
		$coordinates = trim( array_shift( $parts ) );
145
		$distance = count( $parts ) > 0 ? trim( array_shift( $parts ) ) : false;
146
147
		return [ $coordinates, $distance ];
148
	}
149
150
	/**
151
	 * @param string $coordinates
152
	 */
153
	private function tryParseAndSetDataItem( $coordinates ) {
154
		$parser = new GeoCoordinateParser();
155
156
		try {
157
			$value = $parser->parse( $coordinates );
158
			$this->m_dataitem = new SMWDIGeoCoord( $value->getLatitude(), $value->getLongitude() );
159
		}
160
		catch ( ParseException $parseException ) {
161
			$this->addError( wfMessage( 'maps_unrecognized_coords', $coordinates, 1 )->text() );
162
163
			// Make sure this is always set
164
			// TODO: Why is this needed?!
165
			$this->m_dataitem = new SMWDIGeoCoord( [ 'lat' => 0, 'lon' => 0 ] );
166
		}
167
	}
168
169
	/**
170
	 * @see SMWDataValue::getShortWikiText
171
	 */
172
	public function getShortWikiText( $linked = null ) {
173
		if ( $this->isValid() ) {
174
			if ( $this->m_caption === false ) {
175
				return $this->getFormattedCoord( $this->m_dataitem );
176
			}
177
178
			return $this->m_caption;
179
		}
180
181
		return $this->getErrorText();
182
	}
183
	
184
	/**
185
	 * @see SMWDataValue::getShortHTMLText
186
	 * 
187
	 * @since 0.6
188
	 */
189
	public function getShortHTMLText( $linker = null ) {
190
		return $this->getShortWikiText( $linker );
191
	}
192
	
193
	/**
194
	 * @see SMWDataValue::getLongWikiText
195
	 * 
196
	 * @since 0.6
197
	 */
198
	public function getLongWikiText( $linked = null ) {
199
		if ( $this->isValid() ) {
200
			SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP );
201
202
			// TODO: fix lang keys so they include the space and coordinates.
203
			$coordinateSet = $this->m_dataitem->getCoordinateSet();
204
			
205
			$text = $this->getFormattedCoord( $this->m_dataitem );
206
207
			$lines = [
208
				wfMessage( 'semanticmaps-latitude', $coordinateSet['lat'] )->inContentLanguage()->escaped(),
209
				wfMessage( 'semanticmaps-longitude', $coordinateSet['lon'] )->inContentLanguage()->escaped(),
210
			];
211
			
212
			if ( array_key_exists( 'alt', $coordinateSet ) ) {
213
				$lines[] = wfMessage( 'semanticmaps-altitude', $coordinateSet['alt'] )->inContentLanguage()->escaped();
214
			}
215
			
216
			return 	'<span class="smwttinline">' . htmlspecialchars( $text ) . '<span class="smwttcontent">' .
217
		        	 	implode( '<br />', $lines ) .
218
		        	'</span></span>';
219
		} else {
220
			return $this->getErrorText();
221
		}		
222
	}
223
224
	/**
225
	 * @see SMWDataValue::getLongHTMLText
226
	 */
227
	public function getLongHTMLText( $linker = null ) {
228
		return $this->getLongWikiText( $linker );
229
	}
230
231
	/**
232
	 * @see SMWDataValue::getWikiValue
233
	 */
234
	public function getWikiValue() {
235
		return $this->wikiValue;
236
	}
237
238
	/**
239
	 * Create links to mapping services based on a wiki-editable message. The parameters
240
	 * available to the message are:
241
	 * 
242
	 * $1: The location in non-directional float notation.
243
	 * $2: The location in directional DMS notation.
244
	 * $3: The latitude in non-directional float notation.
245
	 * $4 The longitude in non-directional float notation.
246
	 * 
247
	 * @return array
248
	 */
249
	protected function getServiceLinkParams() {
250
		$coordinateSet = $this->m_dataitem->getCoordinateSet();
251
		return [
252
			$this->getFormattedCoord( $this->m_dataitem, 'float' ), // TODO
253
			$this->getFormattedCoord( $this->m_dataitem, 'dms' ), // TODO
254
			$coordinateSet['lat'],
255
			$coordinateSet['lon']
256
		];
257
	}
258
259
}
260