Skip to content

Commit 6cb9154

Browse files
committed
Fixed validation when creating GeometryCollections
1 parent 6841f18 commit 6cb9154

12 files changed

+135
-78
lines changed

src/Types/GeometryCollection.php

Lines changed: 45 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,33 @@ public function jsonSerialize()
142148

143149
return new \GeoJson\Geometry\GeometryCollection($geometries);
144150
}
151+
152+
/**
153+
* Checks
154+
* @param array $items
155+
*/
156+
protected function validateItems(array $items) {
157+
$this->validateItemCount($items);
158+
159+
foreach ($items as $item) {
160+
$this->validateItemType($item);
161+
}
162+
}
163+
164+
protected function validateItemCount(array $items) {
165+
if (count($items) < $this->minimumCollectionItems) {
166+
$entries = $this->minimumCollectionItems === 1 ? 'entry' : 'entries';
167+
throw new InvalidArgumentException(sprintf(
168+
'%s must contain at least %d %s', get_class($this), $this->minimumCollectionItems, $entries
169+
));
170+
}
171+
}
172+
173+
protected function validateItemType($item) {
174+
if (!$item instanceof $this->collectionItemType) {
175+
throw new InvalidArgumentException(sprintf(
176+
'%s must be a collection of %s', get_class($this), $this->collectionItemType
177+
));
178+
}
179+
}
145180
}

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: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,18 @@
1010
class MultiLineString extends GeometryCollection
1111
{
1212
/**
13-
* @param LineString[] $lineStrings
13+
* The minimum number of items required to create this collection.
14+
*
15+
* @var int
1416
*/
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-
}
17+
protected $minimumCollectionItems = 1;
2818

29-
parent::__construct($lineStrings);
30-
}
19+
/**
20+
* The class of the items in the collection.
21+
*
22+
* @var string
23+
*/
24+
protected $collectionItemType = LineString::class;
3125

3226
public function getLineStrings()
3327
{
@@ -58,9 +52,7 @@ public function __toString()
5852

5953
public function offsetSet($offset, $value)
6054
{
61-
if (!($value instanceof LineString)) {
62-
throw new InvalidArgumentException('$value must be an instance of LineString');
63-
}
55+
$this::validateItemType($value);
6456

6557
parent::offsetSet($offset, $value);
6658
}

src/Types/MultiPolygon.php

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@
1010
class MultiPolygon extends GeometryCollection
1111
{
1212
/**
13-
* @param Polygon[] $polygons
13+
* The minimum number of items required to create this collection.
14+
*
15+
* @var int
1416
*/
15-
public function __construct(array $polygons)
16-
{
17-
$validated = array_filter($polygons, function ($value) {
18-
return $value instanceof Polygon;
19-
});
17+
protected $minimumCollectionItems = 0;
2018

21-
if (count($polygons) !== count($validated)) {
22-
throw new InvalidArgumentException('$polygons must be an array of Polygon');
23-
}
24-
parent::__construct($polygons);
25-
}
19+
/**
20+
* The class of the items in the collection.
21+
*
22+
* @var string
23+
*/
24+
protected $collectionItemType = Polygon::class;
2625

2726
public function toWKT()
2827
{
@@ -93,9 +92,7 @@ protected static function assembleParts(array $parts)
9392

9493
public function offsetSet($offset, $value)
9594
{
96-
if (!($value instanceof Polygon)) {
97-
throw new InvalidArgumentException('$value must be an instance of Polygon');
98-
}
95+
self::validateItemType($value);
9996

10097
parent::offsetSet($offset, $value);
10198
}

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+
self::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 = 'uoioi', $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: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,10 @@ public function testScopeDoesTouch()
484484
public function testScopeOrderBySpatialThrowsExceptionWhenFunctionNotRegistered()
485485
{
486486
$point = new Point(1, 2);
487-
$this->assertException(\Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException::class);
487+
$this->assertException(
488+
\Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException::class,
489+
'does-not-exist'
490+
);
488491
TestModel::orderBySpatial('point', $point, 'does-not-exist');
489492
}
490493

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

tests/Unit/Types/MultiLineStringTest.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,19 @@ public function testJsonSerialize()
5959

6060
public function testInvalidArgumentExceptionAtLeastOneEntry()
6161
{
62-
$this->assertException(InvalidArgumentException::class);
62+
$this->assertException(
63+
InvalidArgumentException::class,
64+
'Grimzy\LaravelMysqlSpatial\Types\MultiLineString must contain at least 1 entry'
65+
);
6366
$multilinestring = new MultiLineString([]);
6467
}
6568

6669
public function testInvalidArgumentExceptionNotArrayOfLineString()
6770
{
68-
$this->assertException(InvalidArgumentException::class);
71+
$this->assertException(
72+
InvalidArgumentException::class,
73+
'Grimzy\LaravelMysqlSpatial\Types\MultiLineString must be a collection of Grimzy\LaravelMysqlSpatial\Types\LineString'
74+
);
6975
$multilinestring = new MultiLineString([
7076
new LineString([new Point(0, 0), new Point(1, 1)]),
7177
new Point(0, 1),
@@ -98,7 +104,10 @@ public function testArrayAccess()
98104
$this->assertEquals($linestring2, $multilinestring[2]);
99105

100106
// assert invalid
101-
$this->assertException(InvalidArgumentException::class);
107+
$this->assertException(
108+
InvalidArgumentException::class,
109+
'Grimzy\LaravelMysqlSpatial\Types\MultiLineString must be a collection of Grimzy\LaravelMysqlSpatial\Types\LineString'
110+
);
102111
$multilinestring[] = 1;
103112
}
104113
}

0 commit comments

Comments
 (0)