Completed
Push — newparam ( 72433c...c5fad3 )
by Jeroen De
01:21
created

AreaDescription::getBoundingBox()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

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