Completed
Push — master ( af1f28...b949e2 )
by Jeroen De
10:06
created

CoordinateValue::getDataItem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Maps\SemanticMW\DataValues;
4
5
use DataValues\Geo\Parsers\LatLongParser;
6
use DataValues\Geo\Values\LatLongValue;
7
use InvalidArgumentException;
8
use Maps\MapsFactory;
9
use Maps\Presentation\MapsDistanceParser;
10
use phpDocumentor\Reflection\Types\Parent_;
11
use SMW\Query\Language\Description;
12
use SMW\Query\Language\ThingDescription;
13
use SMW\Query\QueryComparator;
14
use SMWDataItem;
15
use SMWDataValue;
16
use SMWDIGeoCoord;
17
use SMWOutputs;
18
use ValueParsers\ParseException;
19
20
/**
21
 * @property SMWDIGeoCoord m_dataitem
22
 *
23
 * @licence GNU GPL v2+
24
 * @author Jeroen De Dauw < [email protected] >
25
 * @author Markus Krötzsch
26
 */
27
class CoordinateValue extends SMWDataValue {
28
29
	private $wikiValue;
30
31
	/**
32
	 * Overwrite SMWDataValue::getQueryDescription() to be able to process
33
	 * comparators between all values.
34
	 *
35
	 * @param string $value
36
	 *
37
	 * @return Description
38
	 * @throws InvalidArgumentException
39
	 */
40
	public function getQueryDescription( $value ) {
41
		if ( !is_string( $value ) ) {
42
			throw new InvalidArgumentException( '$value needs to be a string' );
43
		}
44
45
		list( $distance, $comparator ) = $this->parseUserValue( $value );
46
		$distance = $this->parserDistance( $distance );
47
48
		$this->setUserValue( $value );
49
50
		switch ( true ) {
51
			case !$this->isValid():
52
				return new ThingDescription();
53
			case $distance !== false:
54
				return new \Maps\SemanticMW\ValueDescriptions\AreaDescription(
55
					$this->getDataItem(),
56
					$comparator,
57
					$distance
58
				);
59
			default:
60
				return new \Maps\SemanticMW\ValueDescriptions\CoordinateDescription(
61
					$this->getDataItem(),
62
					null,
63
					$comparator
64
				);
65
		}
66
	}
67
68
	/**
69
	 * @see SMWDataValue::parseUserValue
70
	 */
71
	protected function parseUserValue( $value ) {
72
		if ( !is_string( $value ) ) {
73
			throw new InvalidArgumentException( '$value needs to be a string' );
74
		}
75
76
		$this->wikiValue = $value;
77
78
		$comparator = SMW_CMP_EQ;
79
		$distance = false;
80
81
		if ( $value === '' ) {
82
			$this->addError( wfMessage( 'smw_novalues' )->text() );
83
		} else {
84
			$comparator = QueryComparator::getInstance()->extractComparatorFromString( $value );
85
86
			list( $coordinates, $distance ) = $this->findValueParts( $value );
87
88
			$this->tryParseAndSetDataItem( $coordinates );
89
		}
90
91
		return [ $distance, $comparator ];
92
	}
93
94
	private function findValueParts( string $value ): array {
95
		$parts = explode( '(', $value );
96
97
		$coordinates = trim( array_shift( $parts ) );
98
		$distance = count( $parts ) > 0 ? trim( array_shift( $parts ) ) : false;
99
100
		return [ $coordinates, $distance ];
101
	}
102
103
	private function tryParseAndSetDataItem( string $coordinates ) {
104
		$parser = new LatLongParser();
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
	 * @param SMWDIGeoCoord $dataItem
158
	 * @param string|null $format
159
	 *
160
	 * @return string|null
161
	 */
162
	private function getFormattedCoord( SMWDIGeoCoord $dataItem, string $format = null ) {
163
		return MapsFactory::globalInstance()->getCoordinateFormatter()->format(
164
			new LatLongValue(
165
				$dataItem->getLatitude(),
166
				$dataItem->getLongitude()
167
			),
168
			$format ?? $GLOBALS['smgQPCoodFormat'],
169
			$GLOBALS['smgQPCoodDirectional']
170
		);
171
	}
172
173
	/**
174
	 * @see SMWDataValue::getLongHTMLText
175
	 */
176
	public function getLongHTMLText( $linker = null ) {
177
		return $this->getLongWikiText( $linker );
178
	}
179
180
	/**
181
	 * @see SMWDataValue::getLongWikiText
182
	 *
183
	 * @since 0.6
184
	 */
185
	public function getLongWikiText( $linked = null ) {
186
		if ( $this->isValid() ) {
187
			SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP );
188
189
			// TODO: fix lang keys so they include the space and coordinates.
190
			$coordinateSet = $this->m_dataitem->getCoordinateSet();
191
192
			$text = $this->getFormattedCoord( $this->m_dataitem );
193
194
			$lines = [
195
				wfMessage( 'semanticmaps-latitude', $coordinateSet['lat'] )->inContentLanguage()->escaped(),
196
				wfMessage( 'semanticmaps-longitude', $coordinateSet['lon'] )->inContentLanguage()->escaped(),
197
			];
198
199
			if ( array_key_exists( 'alt', $coordinateSet ) ) {
200
				$lines[] = wfMessage( 'semanticmaps-altitude', $coordinateSet['alt'] )->inContentLanguage()->escaped();
201
			}
202
203
			return '<span class="smwttinline">' . htmlspecialchars( $text ) . '<span class="smwttcontent">' .
204
				implode( '<br />', $lines ) .
205
				'</span></span>';
206
		} else {
207
			return $this->getErrorText();
208
		}
209
	}
210
211
	/**
212
	 * @see SMWDataValue::getWikiValue
213
	 */
214
	public function getWikiValue() {
215
		return $this->wikiValue;
216
	}
217
218
	/**
219
	 * @see SMWDataValue::setDataItem
220
	 *
221
	 * @param SMWDataItem $dataItem
222
	 *
223
	 * @return boolean
224
	 */
225
	protected function loadDataItem( SMWDataItem $dataItem ) {
226
		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...
227
			$formattedValue = $this->getFormattedCoord( $dataItem );
228
229
			if ( $formattedValue !== null ) {
230
				$this->wikiValue = $formattedValue;
231
				$this->m_dataitem = $dataItem;
232
				return true;
233
			}
234
		}
235
236
		return false;
237
	}
238
239
	/**
240
	 * Create links to mapping services based on a wiki-editable message. The parameters
241
	 * available to the message are:
242
	 *
243
	 * $1: The location in non-directional float notation.
244
	 * $2: The location in directional DMS notation.
245
	 * $3: The latitude in non-directional float notation.
246
	 * $4 The longitude in non-directional float notation.
247
	 *
248
	 * @return array
249
	 */
250
	protected function getServiceLinkParams() {
251
		$coordinateSet = $this->m_dataitem->getCoordinateSet();
252
		return [
253
			$this->getFormattedCoord( $this->m_dataitem, 'float' ), // TODO
254
			$this->getFormattedCoord( $this->m_dataitem, 'dms' ), // TODO
255
			$coordinateSet['lat'],
256
			$coordinateSet['lon']
257
		];
258
	}
259
260
	/**
261
	 * @return SMWDIGeoCoord|\SMWDIError
262
	 */
263
	public function getDataItem() {
264
		return parent::getDataItem();
265
	}
266
267
}
268