Skip to content

Commit 6508a7f

Browse files
committed
Port of validation when creating spatial collections
1 parent 205e201 commit 6508a7f

13 files changed

+138
-81
lines changed

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
],
1212
"require": {
1313
"php": ">=5.5.9",
14+
"ext-pdo": "*",
15+
"ext-json": "*",
1416
"illuminate/database": "^5.2||^6.0",
1517
"geo-io/wkb-parser": "^1.0",
1618
"jmikola/geojson": "^1.0"

src/Types/GeometryCollection.php

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@
1414

1515
class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAccess, Arrayable, Countable
1616
{
17+
/**
18+
* The minimum number of items required to create this collection.
19+
*
20+
* @var int
21+
*/
22+
protected $minimumCollectionItems = 1;
23+
24+
/**
25+
* The class of the items in the collection.
26+
*
27+
* @var string
28+
*/
29+
protected $collectionItemType = GeometryInterface::class;
30+
1731
/**
1832
* The items contained in the spatial collection.
1933
*
@@ -28,13 +42,7 @@ class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAcc
2842
*/
2943
public function __construct(array $geometries)
3044
{
31-
$validated = array_filter($geometries, function ($value) {
32-
return $value instanceof GeometryInterface;
33-
});
34-
35-
if (count($geometries) !== count($validated)) {
36-
throw new InvalidArgumentException('$geometries must be an array of Geometry objects');
37-
}
45+
$this->validateItems($geometries);
3846

3947
$this->items = $geometries;
4048
}
@@ -89,9 +97,7 @@ public function offsetGet($offset)
8997

9098
public function offsetSet($offset, $value)
9199
{
92-
if (!($value instanceof GeometryInterface)) {
93-
throw new InvalidArgumentException('$value must be an instance of GeometryInterface');
94-
}
100+
$this->validateItemType($value);
95101

96102
if (is_null($offset)) {
97103
$this->items[] = $value;
@@ -142,4 +148,48 @@ public function jsonSerialize()
142148

143149
return new \GeoJson\Geometry\GeometryCollection($geometries);
144150
}
151+
152+
/**
153+
* Checks whether the items are valid to create this collection.
154+
*
155+
* @param array $items
156+
*/
157+
protected function validateItems(array $items) {
158+
$this->validateItemCount($items);
159+
160+
foreach ($items as $item) {
161+
$this->validateItemType($item);
162+
}
163+
}
164+
165+
/**
166+
* Checks whether the array has enough items to generate a valid WKT.
167+
*
168+
* @param array $items
169+
*
170+
* @see $minimumCollectionItems
171+
*/
172+
protected function validateItemCount(array $items) {
173+
if (count($items) < $this->minimumCollectionItems) {
174+
$entries = $this->minimumCollectionItems === 1 ? 'entry' : 'entries';
175+
throw new InvalidArgumentException(sprintf(
176+
'%s must contain at least %d %s', get_class($this), $this->minimumCollectionItems, $entries
177+
));
178+
}
179+
}
180+
181+
/**
182+
* Checks the type of the items in the array.
183+
*
184+
* @param $item
185+
*
186+
* @see $collectionItemType
187+
*/
188+
protected function validateItemType($item) {
189+
if (!$item instanceof $this->collectionItemType) {
190+
throw new InvalidArgumentException(sprintf(
191+
'%s must be a collection of %s', get_class($this), $this->collectionItemType
192+
));
193+
}
194+
}
145195
}

src/Types/LineString.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88

99
class LineString extends PointCollection
1010
{
11+
/**
12+
* The minimum number of items required to create this collection.
13+
*
14+
* @var int
15+
*/
16+
protected $minimumCollectionItems = 2;
17+
1118
public function toWKT()
1219
{
1320
return sprintf('LINESTRING(%s)', $this->toPairList());

src/Types/MultiLineString.php

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,15 @@
55
use GeoJson\GeoJson;
66
use GeoJson\Geometry\MultiLineString as GeoJsonMultiLineString;
77
use Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException;
8-
use InvalidArgumentException;
98

109
class MultiLineString extends GeometryCollection
1110
{
1211
/**
13-
* @param LineString[] $lineStrings
12+
* The class of the items in the collection.
13+
*
14+
* @var string
1415
*/
15-
public function __construct(array $lineStrings)
16-
{
17-
if (count($lineStrings) < 1) {
18-
throw new InvalidArgumentException('$lineStrings must contain at least one entry');
19-
}
20-
21-
$validated = array_filter($lineStrings, function ($value) {
22-
return $value instanceof LineString;
23-
});
24-
25-
if (count($lineStrings) !== count($validated)) {
26-
throw new InvalidArgumentException('$lineStrings must be an array of LineString');
27-
}
28-
29-
parent::__construct($lineStrings);
30-
}
16+
protected $collectionItemType = LineString::class;
3117

3218
public function getLineStrings()
3319
{
@@ -58,9 +44,7 @@ public function __toString()
5844

5945
public function offsetSet($offset, $value)
6046
{
61-
if (!($value instanceof LineString)) {
62-
throw new InvalidArgumentException('$value must be an instance of LineString');
63-
}
47+
$this->validateItemType($value);
6448

6549
parent::offsetSet($offset, $value);
6650
}

src/Types/MultiPolygon.php

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,11 @@
1010
class MultiPolygon extends GeometryCollection
1111
{
1212
/**
13-
* @param Polygon[] $polygons
13+
* The class of the items in the collection.
14+
*
15+
* @var string
1416
*/
15-
public function __construct(array $polygons)
16-
{
17-
$validated = array_filter($polygons, function ($value) {
18-
return $value instanceof Polygon;
19-
});
20-
21-
if (count($polygons) !== count($validated)) {
22-
throw new InvalidArgumentException('$polygons must be an array of Polygon');
23-
}
24-
parent::__construct($polygons);
25-
}
17+
protected $collectionItemType = Polygon::class;
2618

2719
public function toWKT()
2820
{
@@ -93,9 +85,7 @@ protected static function assembleParts(array $parts)
9385

9486
public function offsetSet($offset, $value)
9587
{
96-
if (!($value instanceof Polygon)) {
97-
throw new InvalidArgumentException('$value must be an instance of Polygon');
98-
}
88+
$this->validateItemType($value);
9989

10090
parent::offsetSet($offset, $value);
10191
}

src/Types/PointCollection.php

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,11 @@
88
abstract class PointCollection extends GeometryCollection
99
{
1010
/**
11-
* @param Point[] $points
11+
* The class of the items in the collection.
12+
*
13+
* @var string
1214
*/
13-
public function __construct(array $points)
14-
{
15-
if (count($points) < 2) {
16-
throw new InvalidArgumentException('$points must contain at least two entries');
17-
}
18-
19-
$validated = array_filter($points, function ($value) {
20-
return $value instanceof Point;
21-
});
22-
23-
if (count($points) !== count($validated)) {
24-
throw new InvalidArgumentException('$points must be an array of Points');
25-
}
26-
27-
parent::__construct($points);
28-
}
15+
protected $collectionItemType = Point::class;
2916

3017
public function toPairList()
3118
{
@@ -36,9 +23,7 @@ public function toPairList()
3623

3724
public function offsetSet($offset, $value)
3825
{
39-
if (!($value instanceof Point)) {
40-
throw new InvalidArgumentException('$value must be an instance of Point');
41-
}
26+
$this->validateItemType($value);
4227

4328
parent::offsetSet($offset, $value);
4429
}

tests/Unit/BaseTestCase.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ public function tearDown()
77
Mockery::close();
88
}
99

10-
protected function assertException($exceptionName)
10+
protected function assertException($exceptionName, $exceptionMessage = '', $exceptionCode = 0)
1111
{
1212
if (method_exists(parent::class, 'expectException')) {
1313
parent::expectException($exceptionName);
14+
parent::expectExceptionMessage($exceptionMessage);
15+
parent::expectExceptionCode($exceptionCode);
1416
} else {
15-
$this->setExpectedException($exceptionName);
17+
$this->setExpectedException($exceptionName, $exceptionMessage, $exceptionCode);
1618
}
1719
}
1820
}

tests/Unit/Eloquent/SpatialTraitTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public function testInsertUpdatePointHasCorrectSql()
4646

4747
$this->assertStringStartsWith('update', $this->queries[1]);
4848
$this->assertContains('update `test_models` set `point` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
49+
// TODO: assert bindings in query
4950
}
5051

5152
public function testInsertUpdateLineStringHasCorrectSql()
@@ -421,7 +422,7 @@ class TestModel extends Model
421422
{
422423
use \Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait;
423424

424-
protected $spatialFields = ['point']; // only required when fetching, not saving
425+
protected $spatialFields = ['point']; // TODO: only required when fetching, not saving
425426

426427
public $timestamps = false;
427428

tests/Unit/Types/GeometryCollectionTest.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ public function testJsonSerialize()
3535

3636
public function testInvalidArgumentExceptionNotArrayGeometries()
3737
{
38-
$this->assertException(InvalidArgumentException::class);
38+
$this->assertException(
39+
InvalidArgumentException::class,
40+
'Grimzy\LaravelMysqlSpatial\Types\GeometryCollection must be a collection of Grimzy\LaravelMysqlSpatial\Types\GeometryInterface'
41+
);
3942
$geometrycollection = new GeometryCollection([
4043
$this->getPoint(),
4144
1,
@@ -85,7 +88,10 @@ public function testArrayAccess()
8588
$this->assertEquals($point100, $geometryCollection[100]);
8689

8790
// assert invalid
88-
$this->assertException(InvalidArgumentException::class);
91+
$this->assertException(
92+
InvalidArgumentException::class,
93+
'Grimzy\LaravelMysqlSpatial\Types\GeometryCollection must be a collection of Grimzy\LaravelMysqlSpatial\Types\GeometryInterface'
94+
);
8995
$geometryCollection[] = 1;
9096
}
9197

tests/Unit/Types/GeometryTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ public function testGetWKTClass()
3232
$this->assertEquals(MultiLineString::class, Geometry::getWKTClass('MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))'));
3333
$this->assertEquals(MultiPolygon::class, Geometry::getWKTClass('MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))'));
3434
$this->assertEquals(GeometryCollection::class, Geometry::getWKTClass('GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))'));
35-
$this->assertException(UnknownWKTTypeException::class);
35+
$this->assertException(
36+
UnknownWKTTypeException::class,
37+
'Type was TRIANGLE'
38+
);
3639
Geometry::getWKTClass('TRIANGLE((0 0, 0 9, 9 0, 0 0))');
3740
}
3841

0 commit comments

Comments
 (0)