Completed
Push — newparam ( 72433c...c5fad3 )
by Jeroen De
01:21
created

CoordinateValue   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 241
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 60.64%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 6
dl 0
loc 241
ccs 57
cts 94
cp 0.6064
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A getQueryDescription() 0 27 4
A parseUserValue() 0 22 3
A findValueParts() 0 8 2
A tryParseAndSetDataItem() 0 15 2
A parserDistance() 0 12 3
A getShortHTMLText() 0 3 1
A getShortWikiText() 0 11 3
A getFormattedCoord() 0 10 1
A getLongHTMLText() 0 3 1
A getLongWikiText() 0 25 3
A getWikiValue() 0 3 1
A loadDataItem() 0 13 3
A getServiceLinkParams() 0 9 1
A getDataItem() 0 3 1
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 SMW\Query\Language\Description;
11
use SMW\Query\Language\ThingDescription;
12
use SMW\Query\QueryComparator;
13
use SMWDataItem;
14
use SMWDataValue;
15
use SMWDIGeoCoord;
16
use SMWOutputs;
17
use ValueParsers\ParseException;
18
19
/**
20
 * @property SMWDIGeoCoord m_dataitem
21
 *
22
 * @licence GNU GPL v2+
23
 * @author Jeroen De Dauw < [email protected] >
24
 * @author Markus Krötzsch
25
 */
26
class CoordinateValue extends SMWDataValue {
27
28
	private $wikiValue;
29
30
	/**
31
	 * Overwrite SMWDataValue::getQueryDescription() to be able to process
32
	 * comparators between all values.
33
	 *
34
	 * @param string $value
35
	 *
36
	 * @return Description
37
	 * @throws InvalidArgumentException
38
	 */
39 6
	public function getQueryDescription( $value ) {
40 6
		if ( !is_string( $value ) ) {
41
			throw new InvalidArgumentException( '$value needs to be a string' );
42
		}
43
44 6
		list( $distance, $comparator ) = $this->parseUserValue( $value );
45 6
		$distance = $this->parserDistance( $distance );
46
47 6
		$this->setUserValue( $value );
48
49
		switch ( true ) {
50 6
			case !$this->isValid():
51
				return new ThingDescription();
52 6
			case $distance !== false:
53 3
				return new \Maps\SemanticMW\ValueDescriptions\AreaDescription(
54 3
					$this->getDataItem(),
55
					$comparator,
56
					$distance
57
				);
58
			default:
59 3
				return new \Maps\SemanticMW\ValueDescriptions\CoordinateDescription(
60 3
					$this->getDataItem(),
61 3
					null,
62
					$comparator
63
				);
64
		}
65
	}
66
67
	/**
68
	 * @see SMWDataValue::parseUserValue
69
	 */
70 7
	protected function parseUserValue( $value ) {
71 7
		if ( !is_string( $value ) ) {
72
			throw new InvalidArgumentException( '$value needs to be a string' );
73
		}
74
75 7
		$this->wikiValue = $value;
76
77 7
		$comparator = SMW_CMP_EQ;
78 7
		$distance = false;
79
80 7
		if ( $value === '' ) {
81
			$this->addError( wfMessage( 'smw_novalues' )->text() );
82
		} else {
83 7
			$comparator = QueryComparator::getInstance()->extractComparatorFromString( $value );
84
85 7
			list( $coordinates, $distance ) = $this->findValueParts( $value );
86
87 7
			$this->tryParseAndSetDataItem( $coordinates );
88
		}
89
90 7
		return [ $distance, $comparator ];
91
	}
92
93 7
	private function findValueParts( string $value ): array {
94 7
		$parts = explode( '(', $value );
95
96 7
		$coordinates = trim( array_shift( $parts ) );
97 7
		$distance = count( $parts ) > 0 ? trim( array_shift( $parts ) ) : false;
98
99 7
		return [ $coordinates, $distance ];
100
	}
101
102 7
	private function tryParseAndSetDataItem( string $coordinates ) {
103 7
		$parser = new LatLongParser();
104
105
		try {
106 7
			$value = $parser->parse( $coordinates );
107 7
			$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 7
	}
117
118 6
	private function parserDistance( $distance ) {
119 6
		if ( $distance !== false ) {
120 3
			$distance = substr( trim( $distance ), 0, -1 );
121
122 3
			if ( !MapsDistanceParser::isDistance( $distance ) ) {
123
				$this->addError( wfMessage( 'semanticmaps-unrecognizeddistance', $distance )->text() );
124
				$distance = false;
125
			}
126
		}
127
128 6
		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 2
	public function getShortWikiText( $linked = null ) {
144 2
		if ( $this->isValid() ) {
145 2
			if ( $this->m_caption === false ) {
146 2
				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 2
	private function getFormattedCoord( SMWDIGeoCoord $dataItem, string $format = null ) {
162 2
		return MapsFactory::globalInstance()->getCoordinateFormatter()->format(
163 2
			new LatLongValue(
164 2
				$dataItem->getLatitude(),
165 2
				$dataItem->getLongitude()
166
			),
167 2
			$format ?? $GLOBALS['smgQPCoodFormat'],
168 2
			$GLOBALS['smgQPCoodDirectional']
169
		);
170
	}
171
172
	/**
173
	 * @see SMWDataValue::getLongHTMLText
174
	 */
175
	public function getLongHTMLText( $linker = null ) {
176
		return $this->getLongWikiText( $linker );
177
	}
178
179
	/**
180
	 * @see SMWDataValue::getLongWikiText
181
	 *
182
	 * @since 0.6
183
	 */
184
	public function getLongWikiText( $linked = null ) {
185
		if ( $this->isValid() ) {
186
			SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP );
187
188
			// TODO: fix lang keys so they include the space and coordinates.
189
			$coordinateSet = $this->m_dataitem->getCoordinateSet();
190
191
			$text = $this->getFormattedCoord( $this->m_dataitem );
192
193
			$lines = [
194
				wfMessage( 'semanticmaps-latitude', $coordinateSet['lat'] )->inContentLanguage()->escaped(),
195
				wfMessage( 'semanticmaps-longitude', $coordinateSet['lon'] )->inContentLanguage()->escaped(),
196
			];
197
198
			if ( array_key_exists( 'alt', $coordinateSet ) ) {
199
				$lines[] = wfMessage( 'semanticmaps-altitude', $coordinateSet['alt'] )->inContentLanguage()->escaped();
200
			}
201
202
			return '<span class="smwttinline">' . htmlspecialchars( $text ) . '<span class="smwttcontent">' .
203
				implode( '<br />', $lines ) .
204
				'</span></span>';
205
		} else {
206
			return $this->getErrorText();
207
		}
208
	}
209
210
	/**
211
	 * @see SMWDataValue::getWikiValue
212
	 */
213
	public function getWikiValue() {
214
		return $this->wikiValue;
215
	}
216
217
	/**
218
	 * @see SMWDataValue::setDataItem
219
	 *
220
	 * @param SMWDataItem $dataItem
221
	 *
222
	 * @return boolean
223
	 */
224 2
	protected function loadDataItem( SMWDataItem $dataItem ) {
225 2
		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...
226 2
			$formattedValue = $this->getFormattedCoord( $dataItem );
227
228 2
			if ( $formattedValue !== null ) {
229 2
				$this->wikiValue = $formattedValue;
230 2
				$this->m_dataitem = $dataItem;
231 2
				return true;
232
			}
233
		}
234
235
		return false;
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
	 * @return SMWDIGeoCoord|\SMWDIError
261
	 */
262 8
	public function getDataItem() {
263 8
		return parent::getDataItem();
264
	}
265
266
}
267