Skip to content

Commit ffafedd

Browse files
no message
1 parent 001d36c commit ffafedd

File tree

9 files changed

+337
-0
lines changed

9 files changed

+337
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
/**
8+
* Implementation of PostGIS spatial bounding box contained by operator (using @).
9+
*
10+
* Returns TRUE if A's bounding box is contained by B's.
11+
* This is the spatial version of the @ operator, distinct from the array/JSON version.
12+
*
13+
* @see https://postgis.net/docs/reference.html#Operators_Geometry
14+
* @since 3.5
15+
*
16+
* @author Martin Georgiev <martin.georgiev@gmail.com>
17+
*
18+
* @example Using it in DQL with boolean comparison: "WHERE SPATIAL_CONTAINED_BY(g1.geometry, g2.geometry) = TRUE"
19+
* Returns boolean, must be used with "= TRUE" or "= FALSE" in DQL.
20+
*/
21+
class SpatialContainedBy extends BaseFunction
22+
{
23+
protected function customizeFunction(): void
24+
{
25+
$this->setFunctionPrototype('(%s @ %s)');
26+
$this->addNodeMapping('StringPrimary');
27+
$this->addNodeMapping('StringPrimary');
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
/**
8+
* Implementation of PostGIS spatial bounding box contains operator (using ~).
9+
*
10+
* Returns TRUE if A's bounding box contains B's.
11+
* This is the spatial version of the ~ operator, distinct from the array/JSON version.
12+
*
13+
* @see https://postgis.net/docs/reference.html#Operators_Geometry
14+
* @since 3.5
15+
*
16+
* @author Martin Georgiev <martin.georgiev@gmail.com>
17+
*
18+
* @example Using it in DQL with boolean comparison: "WHERE SPATIAL_CONTAINS(g1.geometry, g2.geometry) = TRUE"
19+
* Returns boolean, must be used with "= TRUE" or "= FALSE" in DQL.
20+
*/
21+
class SpatialContains extends BaseFunction
22+
{
23+
protected function customizeFunction(): void
24+
{
25+
$this->setFunctionPrototype('(%s ~ %s)');
26+
$this->addNodeMapping('StringPrimary');
27+
$this->addNodeMapping('StringPrimary');
28+
}
29+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
/**
8+
* Implementation of PostGIS bounding box same as operator (using ~=).
9+
*
10+
* Returns TRUE if A's bounding box is the same as B's.
11+
*
12+
* @see https://postgis.net/docs/reference.html#Operators_Geometry
13+
* @since 3.5
14+
*
15+
* @author Martin Georgiev <martin.georgiev@gmail.com>
16+
*
17+
* @example Using it in DQL with boolean comparison: "WHERE SPATIAL_SAME(g1.geometry, g2.geometry) = TRUE"
18+
* Returns boolean, must be used with "= TRUE" or "= FALSE" in DQL.
19+
*/
20+
class SpatialSame extends BaseFunction
21+
{
22+
protected function customizeFunction(): void
23+
{
24+
$this->setFunctionPrototype('(%s ~= %s)');
25+
$this->addNodeMapping('StringPrimary');
26+
$this->addNodeMapping('StringPrimary');
27+
}
28+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialContainedBy;
8+
use PHPUnit\Framework\Attributes\Test;
9+
10+
class SpatialContainedByTest extends SpatialOperatorTestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'SPATIAL_CONTAINED_BY' => SpatialContainedBy::class,
16+
];
17+
}
18+
19+
#[Test]
20+
public function returns_false_with_overlapping_polygons(): void
21+
{
22+
$dql = 'SELECT SPATIAL_CONTAINED_BY(g.geometry1, g.geometry2) as result
23+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
24+
WHERE g.id = 2';
25+
26+
$result = $this->executeDqlQuery($dql);
27+
$this->assertFalse($result[0]['result']);
28+
}
29+
30+
#[Test]
31+
public function returns_false_with_separate_points(): void
32+
{
33+
$dql = 'SELECT SPATIAL_CONTAINED_BY(g.geometry1, g.geometry2) as result
34+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
35+
WHERE g.id = 1';
36+
37+
$result = $this->executeDqlQuery($dql);
38+
$this->assertFalse($result[0]['result']);
39+
}
40+
41+
#[Test]
42+
public function returns_true_when_comparing_identical_geometries(): void
43+
{
44+
$dql = 'SELECT SPATIAL_CONTAINED_BY(g.geometry1, g.geometry1) as result
45+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
46+
WHERE g.id = 1';
47+
48+
$result = $this->executeDqlQuery($dql);
49+
$this->assertTrue($result[0]['result']);
50+
}
51+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialContains;
8+
use PHPUnit\Framework\Attributes\Test;
9+
10+
class SpatialContainsTest extends SpatialOperatorTestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'SPATIAL_CONTAINS' => SpatialContains::class,
16+
];
17+
}
18+
19+
#[Test]
20+
public function returns_false_when_comparing_separate_point_geometries(): void
21+
{
22+
$dql = 'SELECT SPATIAL_CONTAINS(g.geometry1, g.geometry2) as result
23+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
24+
WHERE g.id = 1';
25+
26+
$result = $this->executeDqlQuery($dql);
27+
$this->assertFalse($result[0]['result']);
28+
}
29+
30+
#[Test]
31+
public function returns_false_when_first_polygon_does_not_fully_contain_second(): void
32+
{
33+
$dql = 'SELECT SPATIAL_CONTAINS(g.geometry1, g.geometry2) as result
34+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
35+
WHERE g.id = 2';
36+
37+
$result = $this->executeDqlQuery($dql);
38+
$this->assertFalse($result[0]['result']);
39+
}
40+
41+
#[Test]
42+
public function returns_true_when_comparing_identical_geometries(): void
43+
{
44+
$dql = 'SELECT SPATIAL_CONTAINS(g.geometry1, g.geometry1) as result
45+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
46+
WHERE g.id = 1';
47+
48+
$result = $this->executeDqlQuery($dql);
49+
$this->assertTrue($result[0]['result']);
50+
}
51+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialSame;
8+
use PHPUnit\Framework\Attributes\Test;
9+
10+
class SpatialSameTest extends SpatialOperatorTestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'SPATIAL_SAME' => SpatialSame::class,
16+
];
17+
}
18+
19+
#[Test]
20+
public function returns_true_when_comparing_identical_geometries(): void
21+
{
22+
$dql = 'SELECT SPATIAL_SAME(g.geometry1, g.geometry1) as result
23+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
24+
WHERE g.id = 1';
25+
26+
$result = $this->executeDqlQuery($dql);
27+
$this->assertTrue($result[0]['result']);
28+
}
29+
30+
#[Test]
31+
public function returns_false_when_comparing_different_point_geometries(): void
32+
{
33+
$dql = 'SELECT SPATIAL_SAME(g.geometry1, g.geometry2) as result
34+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
35+
WHERE g.id = 1';
36+
37+
$result = $this->executeDqlQuery($dql);
38+
$this->assertFalse($result[0]['result']);
39+
}
40+
41+
#[Test]
42+
public function returns_false_when_comparing_overlapping_polygons(): void
43+
{
44+
$dql = 'SELECT SPATIAL_SAME(g.geometry1, g.geometry2) as result
45+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries g
46+
WHERE g.id = 2';
47+
48+
$result = $this->executeDqlQuery($dql);
49+
$this->assertFalse($result[0]['result']);
50+
}
51+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries;
8+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialContainedBy;
9+
10+
class SpatialContainedByTest extends TestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'SPATIAL_CONTAINED_BY' => SpatialContainedBy::class,
16+
];
17+
}
18+
19+
protected function getExpectedSqlStatements(): array
20+
{
21+
return [
22+
'checks if geometry is spatially contained by another' => 'SELECT (c0_.geometry1 @ c0_.geometry2) AS sclr_0 FROM ContainsGeometries c0_',
23+
];
24+
}
25+
26+
protected function getDqlStatements(): array
27+
{
28+
return [
29+
'checks if geometry is spatially contained by another' => \sprintf('SELECT SPATIAL_CONTAINED_BY(e.geometry1, e.geometry2) FROM %s e', ContainsGeometries::class),
30+
];
31+
}
32+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries;
8+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialContains;
9+
10+
class SpatialContainsTest extends TestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'SPATIAL_CONTAINS' => SpatialContains::class,
16+
];
17+
}
18+
19+
protected function getExpectedSqlStatements(): array
20+
{
21+
return [
22+
'checks if geometry spatially contains another' => 'SELECT (c0_.geometry1 ~ c0_.geometry2) AS sclr_0 FROM ContainsGeometries c0_',
23+
'checks if geometry spatially contains literal' => "SELECT (c0_.geometry1 ~ 'POINT(1 2)') AS sclr_0 FROM ContainsGeometries c0_",
24+
];
25+
}
26+
27+
protected function getDqlStatements(): array
28+
{
29+
return [
30+
'checks if geometry spatially contains another' => \sprintf('SELECT SPATIAL_CONTAINS(e.geometry1, e.geometry2) FROM %s e', ContainsGeometries::class),
31+
'checks if geometry spatially contains literal' => \sprintf("SELECT SPATIAL_CONTAINS(e.geometry1, 'POINT(1 2)') FROM %s e", ContainsGeometries::class),
32+
];
33+
}
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsGeometries;
8+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialSame;
9+
10+
class SpatialSameTest extends TestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'SPATIAL_SAME' => SpatialSame::class,
16+
];
17+
}
18+
19+
protected function getExpectedSqlStatements(): array
20+
{
21+
return [
22+
'checks if geometries have same bounding box' => 'SELECT (c0_.geometry1 ~= c0_.geometry2) AS sclr_0 FROM ContainsGeometries c0_',
23+
];
24+
}
25+
26+
protected function getDqlStatements(): array
27+
{
28+
return [
29+
'checks if geometries have same bounding box' => \sprintf('SELECT SPATIAL_SAME(e.geometry1, e.geometry2) FROM %s e', ContainsGeometries::class),
30+
];
31+
}
32+
}

0 commit comments

Comments
 (0)