Completed
Push — leaflet-attribution ( 0121c0 )
by Peter
04:35
created

CoordinateValue::getQueryDescription()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 27
rs 8.5806
c 1
b 0
f 0
cc 4
eloc 19
nc 4
nop 1
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
		} else {
80
			SMWDataValue::prepareValue( $value, $comparator );
81
82
			list( $coordinates, $distance ) = $this->findValueParts( $value );
83
84
			$this->tryParseAndSetDataItem( $coordinates );
85
		}
86
87
		return [ $distance, $comparator ];
88
	}
89
90
	private function findValueParts( $value ) {
91
		$parts = explode( '(', $value );
92
93
		$coordinates = trim( array_shift( $parts ) );
94
		$distance = count( $parts ) > 0 ? trim( array_shift( $parts ) ) : false;
95
96
		return [ $coordinates, $distance ];
97
	}
98
99
	/**
100
	 * @param string $coordinates
101
	 */
102
	private function tryParseAndSetDataItem( $coordinates ) {
103
		$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...
104
105
		try {
106
			$value = $parser->parse( $coordinates );
107
			$this->m_dataitem = new SMWDIGeoCoord( $value->getLatitude(), $value->getLongitude() );
108
		}
109
		catch ( ParseException $parseException ) {
110
			$this->addError( wfMessage( 'maps_unrecognized_coords', $coordinates, 1 )->text() );
111
112
			// Make sure this is always set
113
			// TODO: Why is this needed?!
114
			$this->m_dataitem = new SMWDIGeoCoord( [ 'lat' => 0, 'lon' => 0 ] );
115
		}
116
	}
117
118
	private function parserDistance( $distance ) {
119
		if ( $distance !== false ) {
120
			$distance = substr( trim( $distance ), 0, -1 );
121
122
			if ( !MapsDistanceParser::isDistance( $distance ) ) {
123
				$this->addError( wfMessage( 'semanticmaps-unrecognizeddistance', $distance )->text() );
124
				$distance = false;
125
			}
126
		}
127
128
		return $distance;
129
	}
130
131
	/**
132
	 * @see SMWDataValue::getShortHTMLText
133
	 *
134
	 * @since 0.6
135
	 */
136
	public function getShortHTMLText( $linker = null ) {
137
		return $this->getShortWikiText( $linker );
138
	}
139
140
	/**
141
	 * @see SMWDataValue::getShortWikiText
142
	 */
143
	public function getShortWikiText( $linked = null ) {
144
		if ( $this->isValid() ) {
145
			if ( $this->m_caption === false ) {
146
				return $this->getFormattedCoord( $this->m_dataitem );
147
			}
148
149
			return $this->m_caption;
150
		}
151
152
		return $this->getErrorText();
153
	}
154
155
	/**
156
	 * @param SMWDIGeoCoord $dataItem
157
	 * @param string|null $format
158
	 *
159
	 * @return string|null
160
	 */
161
	private function getFormattedCoord( SMWDIGeoCoord $dataItem, $format = null ) {
162
		global $smgQPCoodFormat;
163
164
		$options = new \ValueFormatters\FormatterOptions(
165
			[
166
				GeoCoordinateFormatter::OPT_FORMAT => $format === null ? $smgQPCoodFormat : $format, // TODO
167
			]
168
		);
169
170
		// TODO: $smgQPCoodDirectional
171
172
		$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...
173
174
		$value = new LatLongValue(
175
			$dataItem->getLatitude(),
176
			$dataItem->getLongitude()
177
		);
178
179
		return $coordinateFormatter->format( $value );
180
	}
181
182
	/**
183
	 * @see SMWDataValue::getLongHTMLText
184
	 */
185
	public function getLongHTMLText( $linker = null ) {
186
		return $this->getLongWikiText( $linker );
187
	}
188
189
	/**
190
	 * @see SMWDataValue::getLongWikiText
191
	 *
192
	 * @since 0.6
193
	 */
194
	public function getLongWikiText( $linked = null ) {
195
		if ( $this->isValid() ) {
196
			SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP );
197
198
			// TODO: fix lang keys so they include the space and coordinates.
199
			$coordinateSet = $this->m_dataitem->getCoordinateSet();
200
201
			$text = $this->getFormattedCoord( $this->m_dataitem );
202
203
			$lines = [
204
				wfMessage( 'semanticmaps-latitude', $coordinateSet['lat'] )->inContentLanguage()->escaped(),
205
				wfMessage( 'semanticmaps-longitude', $coordinateSet['lon'] )->inContentLanguage()->escaped(),
206
			];
207
208
			if ( array_key_exists( 'alt', $coordinateSet ) ) {
209
				$lines[] = wfMessage( 'semanticmaps-altitude', $coordinateSet['alt'] )->inContentLanguage()->escaped();
210
			}
211
212
			return '<span class="smwttinline">' . htmlspecialchars( $text ) . '<span class="smwttcontent">' .
213
				implode( '<br />', $lines ) .
214
				'</span></span>';
215
		} else {
216
			return $this->getErrorText();
217
		}
218
	}
219
220
	/**
221
	 * @see SMWDataValue::getWikiValue
222
	 */
223
	public function getWikiValue() {
224
		return $this->wikiValue;
225
	}
226
227
	/**
228
	 * @see SMWDataValue::setDataItem
229
	 *
230
	 * @param SMWDataItem $dataItem
231
	 *
232
	 * @return boolean
233
	 */
234
	protected function loadDataItem( SMWDataItem $dataItem ) {
235
		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...
236
			$formattedValue = $this->getFormattedCoord( $dataItem );
237
238
			if ( $formattedValue !== null ) {
239
				$this->wikiValue = $formattedValue;
240
				$this->m_dataitem = $dataItem;
241
				return true;
242
			}
243
		}
244
245
		return false;
246
	}
247
248
	/**
249
	 * Create links to mapping services based on a wiki-editable message. The parameters
250
	 * available to the message are:
251
	 *
252
	 * $1: The location in non-directional float notation.
253
	 * $2: The location in directional DMS notation.
254
	 * $3: The latitude in non-directional float notation.
255
	 * $4 The longitude in non-directional float notation.
256
	 *
257
	 * @return array
258
	 */
259
	protected function getServiceLinkParams() {
260
		$coordinateSet = $this->m_dataitem->getCoordinateSet();
261
		return [
262
			$this->getFormattedCoord( $this->m_dataitem, 'float' ), // TODO
263
			$this->getFormattedCoord( $this->m_dataitem, 'dms' ), // TODO
264
			$coordinateSet['lat'],
265
			$coordinateSet['lon']
266
		];
267
	}
268
269
}
270