Completed
Push — master ( 484b1a...998a69 )
by Jeroen De
03:30
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
	 * @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
	private function getPropertyCompat() {
57
		return method_exists( $this, 'getProperty' ) ? $this->getProperty() : $this->m_property;
58
	}
59
60
	/**
61
	 * @see \SMW\Query\Language\Description::getQueryString
62
	 *
63
	 * @param boolean $asValue
64
	 * @return string
65
	 */
66
	public function getQueryString( $asValue = false ) {
67
		if ( $this->getDataItem() === null ) { // TODO: dead code? should never be null
68
			return $asValue ? '+' : '';
69
		}
70
71
		$queryString = DataValueFactory::newDataItemValue( $this->getDataItem(), $this->getPropertyCompat() )->getWikiValue();
72
		return $asValue ? $queryString : "[[$queryString]]";
73
	}
74
75
	/**
76
	 * @see \SMW\Query\Language\Description::prune
77
	 */
78
    public function prune( &$maxsize, &$maxdepth, &$log ) {
79
    	if ( ( $maxsize < $this->getSize() ) || ( $maxdepth < $this->getDepth() ) ) {
80
			$log[] = $this->getQueryString();
81
82
			$result = new SMWThingDescription();
83
			$result->setPrintRequests( $this->getPrintRequests() );
84
85
			return $result;
86
		}
87
88
		$maxsize = $maxsize - $this->getSize();
89
		$maxdepth = $maxdepth - $this->getDepth();
90
91
		return $this;
92
    }
93
94
	/**
95
	 * @see \SMW\Query\Language\Description::getSQLCondition
96
	 *
97
	 * FIXME: store specific code should be in the store component
98
	 *
99
	 * @param string $tableName
100
	 * @param array $fieldNames
101
	 * @param DatabaseBase $dbs
102
	 *
103
	 * @return string or false
104
	 */
105
	public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) {
106
		// Only execute the query when the description's type is geographical coordinates,
107
		// the description is valid, and the near comparator is used.
108
		if ( $this->getDataItem()->getDIType() != SMWDataItem::TYPE_GEO
109
			|| ( $this->getComparator() != SMW_CMP_EQ && $this->getComparator() != SMW_CMP_NEQ )
110
			) {
111
			return false;
112
		}
113
114
		$bounds = $this->getBoundingBox();
115
116
		$north = $dbs->addQuotes( $bounds['north'] );
117
		$east = $dbs->addQuotes( $bounds['east'] );
118
		$south = $dbs->addQuotes( $bounds['south'] );
119
		$west = $dbs->addQuotes( $bounds['west'] );
120
121
		$isEq = $this->getComparator() == SMW_CMP_EQ;
122
123
		$smallerThen = $isEq ? '<' : '>=';
124
		$biggerThen = $isEq ? '>' : '<=';
125
		$joinCond = $isEq ? 'AND' : 'OR';
126
127
		$conditions = [];
128
129
		$conditions[] = "{$tableName}.$fieldNames[1] $smallerThen $north";
130
        $conditions[] = "{$tableName}.$fieldNames[1] $biggerThen $south";
131
        $conditions[] = "{$tableName}.$fieldNames[2] $smallerThen $east";
132
        $conditions[] = "{$tableName}.$fieldNames[2] $biggerThen $west";
133
134
		return implode( " $joinCond ", $conditions );
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
}