Completed
Push — cs ( 148090 )
by Jeroen De
03:24
created

CoordinateValue::getQueryDescription()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 27
ccs 0
cts 24
cp 0
rs 8.5806
c 1
b 0
f 0
cc 4
eloc 19
nc 4
nop 1
crap 20
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
	 * Overwrite SMWDataValue::getQueryDescription() to be able to process
29
	 * comparators between all values.
30
	 *
31
	 * @param string $value
32
	 *
33
	 * @return Description
34
	 * @throws InvalidArgumentException
35
	 */
36
	public function getQueryDescription( $value ) {
37
		if ( !is_string( $value ) ) {
38
			throw new InvalidArgumentException( '$value needs to be a string' );
39
		}
40
41
		list( $distance, $comparator ) = $this->parseUserValue( $value );
42
		$distance = $this->parserDistance( $distance );
43
44
		$this->setUserValue( $value );
45
46
		switch ( true ) {
47
			case !$this->isValid():
48
				return new ThingDescription();
49
			case $distance !== false:
50
				return new \Maps\Semantic\ValueDescriptions\AreaDescription(
51
					$this->getDataItem(),
52
					$comparator,
53
					$distance
54
				);
55
			default:
56
				return new \Maps\Semantic\ValueDescriptions\CoordinateDescription(
57
					$this->getDataItem(),
58
					null,
59
					$comparator
60
				);
61
		}
62
	}
63
64
	/**
65
	 * @see SMWDataValue::parseUserValue
66
	 */
67
	protected function parseUserValue( $value ) {
68
		if ( !is_string( $value ) ) {
69
			throw new InvalidArgumentException( '$value needs to be a string' );
70
		}
71
72
		$this->wikiValue = $value;
73
74
		$comparator = SMW_CMP_EQ;
75
		$distance = false;
76
77
		if ( $value === '' ) {
78
			$this->addError( wfMessage( 'smw_novalues' )->text() );
79
		}
80
		else {
81
			SMWDataValue::prepareValue( $value, $comparator );
82
83
			list( $coordinates, $distance ) = $this->findValueParts( $value );
84
85
			$this->tryParseAndSetDataItem( $coordinates );
86
		}
87
88
		return [ $distance, $comparator ];
89
	}
90
91
	private function findValueParts( $value ) {
92
		$parts = explode( '(', $value );
93
94
		$coordinates = trim( array_shift( $parts ) );
95
		$distance = count( $parts ) > 0 ? trim( array_shift( $parts ) ) : false;
96
97
		return [ $coordinates, $distance ];
98
	}
99
100
	/**
101
	 * @param string $coordinates
102
	 */
103
	private function tryParseAndSetDataItem( $coordinates ) {
104
		$parser = new GeoCoordinateParser();
0 ignored issues
show
Deprecated Code introduced by
The class DataValues\Geo\Parsers\GeoCoordinateParser has been deprecated with message: since 2.0, use the base class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
105
106
		try {
107
			$value = $parser->parse( $coordinates );
108
			$this->m_dataitem = new SMWDIGeoCoord( $value->getLatitude(), $value->getLongitude() );
109
		}
110
		catch ( ParseException $parseException ) {
111
			$this->addError( wfMessage( 'maps_unrecognized_coords', $coordinates, 1 )->text() );
112
113
			// Make sure this is always set
114
			// TODO: Why is this needed?!
115
			$this->m_dataitem = new SMWDIGeoCoord( [ 'lat' => 0, 'lon' => 0 ] );
116
		}
117
	}
118
119
	private function parserDistance( $distance ) {
120
		if ( $distance !== false ) {
121
			$distance = substr( trim( $distance ), 0, -1 );
122
123
			if ( !MapsDistanceParser::isDistance( $distance ) ) {
124
				$this->addError( wfMessage( 'semanticmaps-unrecognizeddistance', $distance )->text() );
125
				$distance = false;
126
			}
127
		}
128
129
		return $distance;
130
	}
131
132
	/**
133
	 * @see SMWDataValue::getShortHTMLText
134
	 *
135
	 * @since 0.6
136
	 */
137
	public function getShortHTMLText( $linker = null ) {
138
		return $this->getShortWikiText( $linker );
139
	}
140
141
	/**
142
	 * @see SMWDataValue::getShortWikiText
143
	 */
144
	public function getShortWikiText( $linked = null ) {
145
		if ( $this->isValid() ) {
146
			if ( $this->m_caption === false ) {
147
				return $this->getFormattedCoord( $this->m_dataitem );
148
			}
149
150
			return $this->m_caption;
151
		}
152
153
		return $this->getErrorText();
154
	}
155
156
	/**
157
	 * @see SMWDataValue::getLongHTMLText
158
	 */
159
	public function getLongHTMLText( $linker = null ) {
160
		return $this->getLongWikiText( $linker );
161
	}
162
163
	/**
164
	 * @see SMWDataValue::getLongWikiText
165
	 *
166
	 * @since 0.6
167
	 */
168
	public function getLongWikiText( $linked = null ) {
169
		if ( $this->isValid() ) {
170
			SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP );
171
172
			// TODO: fix lang keys so they include the space and coordinates.
173
			$coordinateSet = $this->m_dataitem->getCoordinateSet();
174
175
			$text = $this->getFormattedCoord( $this->m_dataitem );
176
177
			$lines = [
178
				wfMessage( 'semanticmaps-latitude', $coordinateSet['lat'] )->inContentLanguage()->escaped(),
179
				wfMessage( 'semanticmaps-longitude', $coordinateSet['lon'] )->inContentLanguage()->escaped(),
180
			];
181
182
			if ( array_key_exists( 'alt', $coordinateSet ) ) {
183
				$lines[] = wfMessage( 'semanticmaps-altitude', $coordinateSet['alt'] )->inContentLanguage()->escaped();
184
			}
185
186
			return '<span class="smwttinline">' . htmlspecialchars( $text ) . '<span class="smwttcontent">' .
187
				implode( '<br />', $lines ) .
188
				'</span></span>';
189
		}
190
		else {
191
			return $this->getErrorText();
192
		}
193
	}
194
195
	/**
196
	 * @see SMWDataValue::getWikiValue
197
	 */
198
	public function getWikiValue() {
199
		return $this->wikiValue;
200
	}
201
202
	/**
203
	 * @see SMWDataValue::setDataItem
204
	 *
205
	 * @param SMWDataItem $dataItem
206
	 *
207
	 * @return boolean
208
	 */
209
	protected function loadDataItem( SMWDataItem $dataItem ) {
210
		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...
211
			$formattedValue = $this->getFormattedCoord( $dataItem );
212
213
			if ( $formattedValue !== null ) {
214
				$this->wikiValue = $formattedValue;
215
				$this->m_dataitem = $dataItem;
216
				return true;
217
			}
218
		}
219
220
		return false;
221
	}
222
223
	/**
224
	 * @param SMWDIGeoCoord $dataItem
225
	 * @param string|null $format
226
	 *
227
	 * @return string|null
228
	 */
229
	private function getFormattedCoord( SMWDIGeoCoord $dataItem, $format = null ) {
230
		global $smgQPCoodFormat;
231
232
		$options = new \ValueFormatters\FormatterOptions(
233
			[
234
				GeoCoordinateFormatter::OPT_FORMAT => $format === null ? $smgQPCoodFormat : $format, // TODO
235
			]
236
		);
237
238
		// TODO: $smgQPCoodDirectional
239
240
		$coordinateFormatter = new GeoCoordinateFormatter( $options );
0 ignored issues
show
Deprecated Code introduced by
The class DataValues\Geo\Formatters\GeoCoordinateFormatter has been deprecated with message: since 2.0, use the base class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
241
242
		$value = new LatLongValue(
243
			$dataItem->getLatitude(),
244
			$dataItem->getLongitude()
245
		);
246
247
		return $coordinateFormatter->format( $value );
248
	}
249
250
	/**
251
	 * Create links to mapping services based on a wiki-editable message. The parameters
252
	 * available to the message are:
253
	 *
254
	 * $1: The location in non-directional float notation.
255
	 * $2: The location in directional DMS notation.
256
	 * $3: The latitude in non-directional float notation.
257
	 * $4 The longitude in non-directional float notation.
258
	 *
259
	 * @return array
260
	 */
261
	protected function getServiceLinkParams() {
262
		$coordinateSet = $this->m_dataitem->getCoordinateSet();
263
		return [
264
			$this->getFormattedCoord( $this->m_dataitem, 'float' ), // TODO
265
			$this->getFormattedCoord( $this->m_dataitem, 'dms' ), // TODO
266
			$coordinateSet['lat'],
267
			$coordinateSet['lon']
268
		];
269
	}
270
271
}
272