Completed
Push — move ( 875a6f )
by Jeroen De
04:17
created

AreaDescription::getSQLCondition()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 0
cts 23
cp 0
rs 8.8017
c 0
b 0
f 0
cc 6
nc 10
nop 3
crap 42
1
<?php
2
3
namespace Maps\SemanticMW\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
	 * @var SMWDIGeoCoord
29
	 */
30
	private $center;
31
32
	/**
33
	 * @var string
34
	 */
35
	private $radius;
36
37
	/**
38
	 * @param SMWDataItem $areaCenter
39
	 * @param string $comparator
40
	 * @param string $radius
41
	 * @param DIProperty|null $property
42
	 *
43
	 * @throws InvalidArgumentException
44
	 */
45
	public function __construct( SMWDataItem $areaCenter, $comparator, $radius, DIProperty $property = null ) {
46
		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...
47
			throw new InvalidArgumentException( '$areaCenter needs to be a SMWDIGeoCoord' );
48
		}
49
50
		parent::__construct( $areaCenter, $property, $comparator );
51
52
		$this->center = $areaCenter;
53
		$this->radius = $radius;
54
	}
55
56
	/**
57
	 * @see \SMW\Query\Language\Description::prune
58
	 */
59
	public function prune( &$maxsize, &$maxdepth, &$log ) {
60
		if ( ( $maxsize < $this->getSize() ) || ( $maxdepth < $this->getDepth() ) ) {
61
			$log[] = $this->getQueryString();
62
63
			$result = new SMWThingDescription();
64
			$result->setPrintRequests( $this->getPrintRequests() );
65
66
			return $result;
67
		}
68
69
		$maxsize = $maxsize - $this->getSize();
70
		$maxdepth = $maxdepth - $this->getDepth();
71
72
		return $this;
73
	}
74
75
	/**
76
	 * @see \SMW\Query\Language\Description::getQueryString
77
	 *
78
	 * @param boolean $asValue
79
	 *
80
	 * @return string
81
	 */
82
	public function getQueryString( $asValue = false ) {
83
		$centerString = DataValueFactory::newDataItemValue( $this->center, $this->getProperty() )->getWikiValue();
84
85
		$queryString = "$centerString ({$this->radius})";
86
87
		return $asValue ? $queryString : "[[$queryString]]";
88
	}
89
90
	/**
91
	 * @see \SMW\Query\Language\Description::getSQLCondition
92
	 *
93
	 * FIXME: store specific code should be in the store component
94
	 *
95
	 * @param string $tableName
96
	 * @param array $fieldNames
97
	 * @param DatabaseBase $dbs
98
	 *
99
	 * @return string|false
100
	 */
101
	public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) {
102
		if ( $this->center->getDIType() != SMWDataItem::TYPE_GEO ) {
103
			throw new \LogicException( 'Constructor should have prevented this' );
104
		}
105
106
		if ( !$this->comparatorIsSupported() ) {
107
			return false;
108
		}
109
110
		$bounds = $this->getBoundingBox();
111
112
		$north = $dbs->addQuotes( $bounds['north'] );
113
		$east = $dbs->addQuotes( $bounds['east'] );
114
		$south = $dbs->addQuotes( $bounds['south'] );
115
		$west = $dbs->addQuotes( $bounds['west'] );
116
117
		$isEq = $this->getComparator() == SMW_CMP_EQ;
118
119
		$smallerThen = $isEq ? '<' : '>=';
120
		$biggerThen = $isEq ? '>' : '<=';
121
		$joinCond = $isEq ? 'AND' : 'OR';
122
123
		$conditions = [];
124
125
		$conditions[] = "{$tableName}.$fieldNames[1] $smallerThen $north";
126
		$conditions[] = "{$tableName}.$fieldNames[1] $biggerThen $south";
127
		$conditions[] = "{$tableName}.$fieldNames[2] $smallerThen $east";
128
		$conditions[] = "{$tableName}.$fieldNames[2] $biggerThen $west";
129
130
		return implode( " $joinCond ", $conditions );
131
	}
132
133
	private function comparatorIsSupported() {
134
		return $this->getComparator() === SMW_CMP_EQ || $this->getComparator() === SMW_CMP_NEQ;
135
	}
136
137
	/**
138
	 * @return float[] An associative array containing the limits with keys north, east, south and west.
139
	 */
140
	public function getBoundingBox() {
141
		$center = new LatLongValue(
142
			$this->center->getLatitude(),
143
			$this->center->getLongitude()
144
		);
145
146
		$radiusInMeters = MapsDistanceParser::parseDistance( $this->radius ); // TODO: this can return false
147
148
		$north = MapsGeoFunctions::findDestination( $center, 0, $radiusInMeters );
0 ignored issues
show
Security Bug introduced by
It seems like $radiusInMeters defined by \MapsDistanceParser::parseDistance($this->radius) on line 146 can also be of type false; however, MapsGeoFunctions::findDestination() does only seem to accept double, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
149
		$east = MapsGeoFunctions::findDestination( $center, 90, $radiusInMeters );
0 ignored issues
show
Security Bug introduced by
It seems like $radiusInMeters defined by \MapsDistanceParser::parseDistance($this->radius) on line 146 can also be of type false; however, MapsGeoFunctions::findDestination() does only seem to accept double, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
150
		$south = MapsGeoFunctions::findDestination( $center, 180, $radiusInMeters );
0 ignored issues
show
Security Bug introduced by
It seems like $radiusInMeters defined by \MapsDistanceParser::parseDistance($this->radius) on line 146 can also be of type false; however, MapsGeoFunctions::findDestination() does only seem to accept double, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
151
		$west = MapsGeoFunctions::findDestination( $center, 270, $radiusInMeters );
0 ignored issues
show
Security Bug introduced by
It seems like $radiusInMeters defined by \MapsDistanceParser::parseDistance($this->radius) on line 146 can also be of type false; however, MapsGeoFunctions::findDestination() does only seem to accept double, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
152
153
		return [
154
			'north' => $north['lat'],
155
			'east' => $east['lon'],
156
			'south' => $south['lat'],
157
			'west' => $west['lon'],
158
		];
159
	}
160
161
}