Completed
Push — master ( abf8df...70f9cf )
by Jeroen De
04:26
created

AreaDescription::getSQLCondition()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 31
Code Lines 20

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.439
c 0
b 0
f 0
cc 6
eloc 20
nc 10
nop 3
crap 42
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
	 * @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::getQueryString
58
	 *
59
	 * @param boolean $asValue
60
	 * @return string
61
	 */
62
	public function getQueryString( $asValue = false ) {
63
		$centerString = DataValueFactory::newDataItemValue( $this->center, $this->getPropertyCompat() )->getWikiValue();
64
65
		$queryString = "$centerString ({$this->radius})";
66
67
		return $asValue ? $queryString : "[[$queryString]]";
68
	}
69
70
	private function getPropertyCompat() {
71
		return method_exists( $this, 'getProperty' ) ? $this->getProperty() : $this->m_property;
72
	}
73
74
	/**
75
	 * @see \SMW\Query\Language\Description::prune
76
	 */
77
    public function prune( &$maxsize, &$maxdepth, &$log ) {
78
    	if ( ( $maxsize < $this->getSize() ) || ( $maxdepth < $this->getDepth() ) ) {
79
			$log[] = $this->getQueryString();
80
81
			$result = new SMWThingDescription();
82
			$result->setPrintRequests( $this->getPrintRequests() );
83
84
			return $result;
85
		}
86
87
		$maxsize = $maxsize - $this->getSize();
88
		$maxdepth = $maxdepth - $this->getDepth();
89
90
		return $this;
91
    }
92
93
	/**
94
	 * @see \SMW\Query\Language\Description::getSQLCondition
95
	 *
96
	 * FIXME: store specific code should be in the store component
97
	 *
98
	 * @param string $tableName
99
	 * @param array $fieldNames
100
	 * @param DatabaseBase $dbs
101
	 *
102
	 * @return string|false
103
	 */
104
	public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) {
105
		if ( $this->center->getDIType() != SMWDataItem::TYPE_GEO ) {
106
			throw new \LogicException( 'Constructor should have prevented this' );
107
		}
108
109
		if ( !$this->comparatorIsSupported() ) {
110
			return false;
111
		}
112
113
		$bounds = $this->getBoundingBox();
114
115
		$north = $dbs->addQuotes( $bounds['north'] );
116
		$east = $dbs->addQuotes( $bounds['east'] );
117
		$south = $dbs->addQuotes( $bounds['south'] );
118
		$west = $dbs->addQuotes( $bounds['west'] );
119
120
		$isEq = $this->getComparator() == SMW_CMP_EQ;
121
122
		$smallerThen = $isEq ? '<' : '>=';
123
		$biggerThen = $isEq ? '>' : '<=';
124
		$joinCond = $isEq ? 'AND' : 'OR';
125
126
		$conditions = [];
127
128
		$conditions[] = "{$tableName}.$fieldNames[1] $smallerThen $north";
129
        $conditions[] = "{$tableName}.$fieldNames[1] $biggerThen $south";
130
        $conditions[] = "{$tableName}.$fieldNames[2] $smallerThen $east";
131
        $conditions[] = "{$tableName}.$fieldNames[2] $biggerThen $west";
132
133
		return implode( " $joinCond ", $conditions );
134
	}
135
136
	private function comparatorIsSupported() {
137
		return $this->getComparator() === SMW_CMP_EQ || $this->getComparator() === SMW_CMP_NEQ;
138
	}
139
140
	/**
141
	 * @return float[] An associative array containing the limits with keys north, east, south and west.
142
	 */
143
	public function getBoundingBox() {
144
		$center = new LatLongValue(
145
			$this->center->getLatitude(),
146
			$this->center->getLongitude()
147
		);
148
149
		$radiusInMeters = MapsDistanceParser::parseDistance( $this->radius ); // TODO: this can return false
150
151
		$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 149 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
		$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 149 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...
153
		$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 149 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...
154
		$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 149 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...
155
156
		return [
157
			'north' => $north['lat'],
158
			'east' => $east['lon'],
159
			'south' => $south['lat'],
160
			'west' => $west['lon'],
161
		];
162
	}
163
164
}