SMAreaValueDescription   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 21
lcom 2
cbo 6
dl 0
loc 177
rs 10
c 0
b 0
f 0
ccs 0
cts 20
cp 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 2
A getPropertyCompat() 0 3 2
A getQueryString() 0 8 4
A prune() 0 14 3
A getBounds() 0 3 1
B getSQLCondition() 0 31 7
A getBoundingBox() 0 18 1
A geoFunctionsAreAvailable() 0 3 1
1
<?php
2
3
use DataValues\Geo\Values\LatLongValue;
4
use SMW\DataValueFactory;
5
6
/**
7
 * Description of a geographical area defined by a coordinates set and a distance to the bounds.
8
 * The bounds are a 'rectangle' (but bend due to the earths curvature), as the resulting query
9
 * would otherwise be to resource intensive.
10
 *
11
 * @since 0.6
12
 *
13
 * @licence GNU GPL v2+
14
 * @author Jeroen De Dauw < [email protected]
15
 * 
16
 * TODO: would be awesome to use Spatial Extensions to select coordinates
17
 */
18
class SMAreaValueDescription extends SMWValueDescription {
19
	
20
	/**
21
	 * Associative array containing the bounds of the area, or false when not set.
22
	 * 
23
	 * @since 0.6
24
	 * 
25
	 * @var mixed
26
	 */
27
	protected $bounds = false;
28
29
	/**
30
	 * @since 3.0
31
	 *
32
	 * @var SMWDIGeoCoord
33
	 */
34
	protected $center;
35
36
	/**
37
	 * @since 3.0
38
	 *
39
	 * @var string
40
	 */
41
	protected $radius;
42
43
	/**
44
	 * @param SMWDataItem $areaCenter
45
	 * @param string $comparator
46
	 * @param string $radius
47
	 * @param SMWDIProperty $property
48
	 *
49
	 * @throws InvalidArgumentException
50
	 */
51
	public function __construct( SMWDataItem $areaCenter, $comparator, $radius, SMWDIProperty $property = null ) {
52
		if ( !( $areaCenter instanceof SMWDIGeoCoord ) ) {
53
			throw new InvalidArgumentException( '$areaCenter needs to be a SMWDIGeoCoord' );
54
		}
55
56
		parent::__construct( $areaCenter, $property, $comparator );
57
58
		$this->radius = MapsDistanceParser::parseDistance( $radius );
0 ignored issues
show
Documentation Bug introduced by
It seems like \MapsDistanceParser::parseDistance($radius) of type false or double is incompatible with the declared type string of property $radius.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
59
		$this->center = $areaCenter;
60
61
		$this->bounds = $this->getBoundingBox();
62
	}
63
64
	private function getPropertyCompat() {
65
		return method_exists( $this, 'getProperty' ) ? $this->getProperty() : $this->m_property;
66
	}
67
68
	/**
69
	 * @see SMWDescription:getQueryString
70
	 * 
71
	 * @since 0.6
72
	 * 
73
	 * @param boolean $asValue
74
	 * @return string
75
	 */
76
	public function getQueryString( $asValue = false ) {
77
		if ( $this->getDataItem() !== null ) {
78
			$queryString = DataValueFactory::newDataItemValue( $this->getDataItem(), $this->getPropertyCompat() )->getWikiValue();
0 ignored issues
show
Deprecated Code introduced by
The method SMW\DataValueFactory::newDataItemValue() has been deprecated with message: since 2.4, use DataValueFactory::newDataValueByItem

This method has been deprecated. The supplier of the class has supplied an explanatory message.

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

Loading history...
79
			return $asValue ? $queryString : "[[$queryString]]";
80
		} else {
81
			return $asValue ? '+' : '';
82
		}
83
	}
84
85
	/**
86
	 * @see SMWDescription:prune
87
	 * 
88
	 * @since 0.6
89
	 */
90
    public function prune( &$maxsize, &$maxdepth, &$log ) {
91
    	if ( ( $maxsize < $this->getSize() ) || ( $maxdepth < $this->getDepth() ) ) {
92
			$log[] = $this->getQueryString();
93
			
94
			$result = new SMWThingDescription();
95
			$result->setPrintRequests( $this->getPrintRequests() );
96
			
97
			return $result;
98
		} else {
99
			$maxsize = $maxsize - $this->getSize();
100
			$maxdepth = $maxdepth - $this->getDepth();
101
			return $this;
102
		}
103
    }
104
    
105
    /**
106
     * Returns the bounds of the area.
107
     * 
108
     * @since 0.6
109
     * 
110
     * @return array
111
     */
112
    public function getBounds() {
113
    	return $this->bounds;
114
    }    
115
	
116
	/**
117
	 * @see SMWDescription::getSQLCondition
118
	 *
119
	 * FIXME: store specific code should be in the store component
120
	 *
121
	 * @since 0.6
122
	 * 
123
	 * @param string $tableName
124
	 * @param array $fieldNames
125
	 * @param DatabaseBase $dbs
126
	 * 
127
	 * @return string or false
128
	 */
129
	public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) {
130
		// Only execute the query when the description's type is geographical coordinates,
131
		// the description is valid, and the near comparator is used.
132
		if ( $this->getDataItem()->getDIType() != SMWDataItem::TYPE_GEO
133
			|| ( $this->getComparator() != SMW_CMP_EQ && $this->getComparator() != SMW_CMP_NEQ )
134
			) {
135
			return false;
136
		}
137
		
138
		$north = $dbs->addQuotes( $this->bounds['north'] );
139
		$east = $dbs->addQuotes( $this->bounds['east'] );
140
		$south = $dbs->addQuotes( $this->bounds['south'] );
141
		$west = $dbs->addQuotes( $this->bounds['west'] );
142
143
		$isEq = $this->getComparator() == SMW_CMP_EQ;
144
		
145
        $conditions = [];
146
147
        $smallerThen = $isEq ? '<' : '>=';
148
        $biggerThen = $isEq ? '>' : '<=';
149
        $joinCond = $isEq ? 'AND' : 'OR';
150
151
        $conditions[] = "{$tableName}.$fieldNames[1] $smallerThen $north";
152
        $conditions[] = "{$tableName}.$fieldNames[1] $biggerThen $south";
153
        $conditions[] = "{$tableName}.$fieldNames[2] $smallerThen $east";
154
        $conditions[] = "{$tableName}.$fieldNames[2] $biggerThen $west";
155
156
        $sql = implode( " $joinCond ", $conditions );
157
158
		return $sql;
159
	}
160
161
	/**
162
	 * @return float[] An associative array containing the limits with keys north, east, south and west.
163
	 */
164
	protected function getBoundingBox() {
165
		$center = new LatLongValue(
166
			$this->center->getLatitude(),
167
			$this->center->getLongitude()
168
		);
169
170
		$north = MapsGeoFunctions::findDestination( $center, 0, $this->radius );
171
		$east = MapsGeoFunctions::findDestination( $center, 90, $this->radius );
172
		$south = MapsGeoFunctions::findDestination( $center, 180, $this->radius );
173
		$west = MapsGeoFunctions::findDestination( $center, 270, $this->radius );
174
175
		return [
176
			'north' => $north['lat'],
177
			'east' => $east['lon'],
178
			'south' => $south['lat'],
179
			'west' => $west['lon'],
180
		];
181
	}
182
	
183
	/**
184
	 * Returns a boolean indicating if MapsGeoFunctions is available. 
185
	 * 
186
	 * @since 0.6
187
	 * 
188
	 * @return boolean
189
	 */
190
	protected function geoFunctionsAreAvailable() {
191
		return class_exists( 'MapsGeoFunctions' );
192
	}	
193
	
194
}