Completed
Push — master ( 29eae5...484b1a )
by Jeroen De
03:27
created

AreaDescription::getSQLCondition()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 0
cts 22
cp 0
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 19
nc 9
nop 3
crap 56
1
<?php
2
3
namespace Maps\Semantic\ValueDescriptions;
4
5
use DatabaseBase;
6
use DataValues\Geo\Values\LatLongValue;
7
use InvalidArgumentException;
8
use MapsDistanceParser;
9
use MapsGeoFunctions;
10
use SMW\DataValueFactory;
11
use SMW\DIProperty;
12
use SMW\Query\Language\ValueDescription;
13
use SMWDataItem;
14
use SMWDIGeoCoord;
15
use SMWThingDescription;
16
17
/**
18
 * Description of a geographical area defined by a coordinates set and a distance to the bounds.
19
 * The bounds are a 'rectangle' (but bend due to the earths curvature), as the resulting query
20
 * would otherwise be to resource intensive.
21
 *
22
 * @licence GNU GPL v2+
23
 * @author Jeroen De Dauw < [email protected] >
24
 */
25
class AreaDescription extends ValueDescription {
26
27
	/**
28
	 * Associative array containing the bounds of the area, or false when not set.
29
	 *
30
	 * @var float[]|false
31
	 */
32
	private $bounds = false;
33
34
	/**
35
	 * @var SMWDIGeoCoord
36
	 */
37
	private $center;
38
39
	/**
40
	 * @var string
41
	 */
42
	private $radius;
43
44
	/**
45
	 * @param SMWDataItem $areaCenter
46
	 * @param string $comparator
47
	 * @param string $radius
48
	 * @param DIProperty|null $property
49
	 *
50
	 * @throws InvalidArgumentException
51
	 */
52
	public function __construct( SMWDataItem $areaCenter, $comparator, $radius, DIProperty $property = null ) {
53
		if ( !( $areaCenter 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...
54
			throw new InvalidArgumentException( '$areaCenter needs to be a SMWDIGeoCoord' );
55
		}
56
57
		parent::__construct( $areaCenter, $property, $comparator );
58
59
		$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...
60
		$this->center = $areaCenter;
61
62
		$this->bounds = $this->createBoundingBox();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createBoundingBox() of type array<string,double,{"no...uble","west":"double"}> is incompatible with the declared type array<integer,double>|false of property $bounds.

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...
63
	}
64
65
	/**
66
	 * @return float[] An associative array containing the limits with keys north, east, south and west.
67
	 */
68
	private function createBoundingBox() {
69
		$center = new LatLongValue(
70
			$this->center->getLatitude(),
71
			$this->center->getLongitude()
72
		);
73
74
		$north = MapsGeoFunctions::findDestination( $center, 0, $this->radius );
75
		$east = MapsGeoFunctions::findDestination( $center, 90, $this->radius );
76
		$south = MapsGeoFunctions::findDestination( $center, 180, $this->radius );
77
		$west = MapsGeoFunctions::findDestination( $center, 270, $this->radius );
78
79
		return [
80
			'north' => $north['lat'],
81
			'east' => $east['lon'],
82
			'south' => $south['lat'],
83
			'west' => $west['lon'],
84
		];
85
	}
86
87
	private function getPropertyCompat() {
88
		return method_exists( $this, 'getProperty' ) ? $this->getProperty() : $this->m_property;
89
	}
90
91
	/**
92
	 * @see \SMW\Query\Language\Description::getQueryString
93
	 *
94
	 * @param boolean $asValue
95
	 * @return string
96
	 */
97
	public function getQueryString( $asValue = false ) {
98
		if ( $this->getDataItem() === null ) {
99
			return $asValue ? '+' : '';
100
		}
101
102
		$queryString = DataValueFactory::newDataItemValue( $this->getDataItem(), $this->getPropertyCompat() )->getWikiValue();
103
		return $asValue ? $queryString : "[[$queryString]]";
104
	}
105
106
	/**
107
	 * @see \SMW\Query\Language\Description::prune
108
	 */
109
    public function prune( &$maxsize, &$maxdepth, &$log ) {
110
    	if ( ( $maxsize < $this->getSize() ) || ( $maxdepth < $this->getDepth() ) ) {
111
			$log[] = $this->getQueryString();
112
113
			$result = new SMWThingDescription();
114
			$result->setPrintRequests( $this->getPrintRequests() );
115
116
			return $result;
117
		}
118
119
		$maxsize = $maxsize - $this->getSize();
120
		$maxdepth = $maxdepth - $this->getDepth();
121
122
		return $this;
123
    }
124
125
	/**
126
     * Returns the bounds of the area.
127
     *
128
     * @since 0.6
129
     *
130
     * @return array
131
     */
132
    public function getBounds() {
133
    	return $this->bounds;
134
    }
135
136
	/**
137
	 * @see \SMW\Query\Language\Description::getSQLCondition
138
	 *
139
	 * FIXME: store specific code should be in the store component
140
	 *
141
	 * @param string $tableName
142
	 * @param array $fieldNames
143
	 * @param DatabaseBase $dbs
144
	 *
145
	 * @return string or false
146
	 */
147
	public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) {
148
		// Only execute the query when the description's type is geographical coordinates,
149
		// the description is valid, and the near comparator is used.
150
		if ( $this->getDataItem()->getDIType() != SMWDataItem::TYPE_GEO
151
			|| ( $this->getComparator() != SMW_CMP_EQ && $this->getComparator() != SMW_CMP_NEQ )
152
			) {
153
			return false;
154
		}
155
156
		$north = $dbs->addQuotes( $this->bounds['north'] );
157
		$east = $dbs->addQuotes( $this->bounds['east'] );
158
		$south = $dbs->addQuotes( $this->bounds['south'] );
159
		$west = $dbs->addQuotes( $this->bounds['west'] );
160
161
		$isEq = $this->getComparator() == SMW_CMP_EQ;
162
163
        $conditions = [];
164
165
        $smallerThen = $isEq ? '<' : '>=';
166
        $biggerThen = $isEq ? '>' : '<=';
167
        $joinCond = $isEq ? 'AND' : 'OR';
168
169
        $conditions[] = "{$tableName}.$fieldNames[1] $smallerThen $north";
170
        $conditions[] = "{$tableName}.$fieldNames[1] $biggerThen $south";
171
        $conditions[] = "{$tableName}.$fieldNames[2] $smallerThen $east";
172
        $conditions[] = "{$tableName}.$fieldNames[2] $biggerThen $west";
173
174
        $sql = implode( " $joinCond ", $conditions );
175
176
		return $sql;
177
	}
178
179
}