Skip to content

Commit e25baa7

Browse files
committed
feat: add support for point type
1 parent 67265cc commit e25baa7

File tree

13 files changed

+546
-0
lines changed

13 files changed

+546
-0
lines changed

docs/AVAILABLE-TYPES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@
1717
| cidr[] | _cidr | `MartinGeorgiev\Doctrine\DBAL\Types\CidrArray` |
1818
| macaddr | macaddr | `MartinGeorgiev\Doctrine\DBAL\Types\Macaddr` |
1919
| macaddr[] | _macaddr | `MartinGeorgiev\Doctrine\DBAL\Types\MacaddrArray` |
20+
| point | point | `MartinGeorgiev\Doctrine\DBAL\Types\Point` |
21+
| point[] | _point | `MartinGeorgiev\Doctrine\DBAL\Types\PointArray` |

docs/INTEGRATING-WITH-DOCTRINE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Type::addType('bigint[]', "MartinGeorgiev\\Doctrine\\DBAL\\Types\\BigIntArray");
1717
Type::addType('text[]', "MartinGeorgiev\\Doctrine\\DBAL\\Types\\TextArray");
1818
Type::addType('jsonb', "MartinGeorgiev\\Doctrine\\DBAL\\Types\\Jsonb");
1919
Type::addType('jsonb[]', "MartinGeorgiev\\Doctrine\\DBAL\\Types\\JsonbArray");
20+
Type::addType('point', "MartinGeorgiev\\Doctrine\\DBAL\\Types\\Point");
2021
```
2122

2223

@@ -168,6 +169,7 @@ $platform->registerDoctrineTypeMapping('_int8','bigint[]');
168169
$platform->registerDoctrineTypeMapping('text[]','text[]');
169170
$platform->registerDoctrineTypeMapping('_text','text[]');
170171
$platform->registerDoctrineTypeMapping('jsonb','jsonb');
172+
$platform->registerDoctrineTypeMapping('point','point');
171173
...
172174

173175
```

docs/INTEGRATING-WITH-LARAVEL.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ return [
3030
'jsonb' => 'jsonb',
3131
'_jsonb' => 'jsonb[]',
3232
'jsonb[]' => 'jsonb[]',
33+
'point' => 'point',
3334
],
3435
],
3536
],
@@ -53,6 +54,7 @@ return [
5354
'text[]' => MartinGeorgiev\Doctrine\DBAL\Types\TextArray::class,
5455
'jsonb' => MartinGeorgiev\Doctrine\DBAL\Types\Jsonb::class,
5556
'jsonb[]' => MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray::class,
57+
'point' => MartinGeorgiev\Doctrine\DBAL\Types\Point::class,
5658
],
5759
];
5860
```
@@ -242,6 +244,9 @@ class DoctrineEventSubscriber implements Subscriber
242244
if (!Type::hasType('jsonb[]')) {
243245
Type::addType('jsonb[]', \MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray::class);
244246
}
247+
if (!Type::hasType('point')) {
248+
Type::addType('point', \MartinGeorgiev\Doctrine\DBAL\Types\Point::class);
249+
}
245250
}
246251
}
247252
```

docs/INTEGRATING-WITH-SYMFONY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ doctrine:
1717
text[]: MartinGeorgiev\Doctrine\DBAL\Types\TextArray
1818
jsonb: MartinGeorgiev\Doctrine\DBAL\Types\Jsonb
1919
jsonb[]: MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray
20+
point: MartinGeorgiev\Doctrine\DBAL\Types\Point
2021
```
2122
2223
@@ -46,6 +47,7 @@ doctrine:
4647
jsonb: jsonb
4748
jsonb[]: jsonb[]
4849
_jsonb: jsonb[]
50+
point: point
4951
```
5052

5153

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;
6+
7+
use Doctrine\DBAL\Types\ConversionException;
8+
9+
/**
10+
* @since 3.1
11+
*
12+
* @author Martin Georgiev <martin.georgiev@gmail.com>
13+
*/
14+
class InvalidPointArrayItemForDatabaseException extends ConversionException
15+
{
16+
private static function create(string $message, mixed $value): self
17+
{
18+
return new self(\sprintf($message, \var_export($value, true)));
19+
}
20+
21+
public static function isNotAPoint(mixed $value): self
22+
{
23+
return self::create('Given value of %s is not a point.', $value);
24+
}
25+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;
6+
7+
use Doctrine\DBAL\Types\ConversionException;
8+
9+
/**
10+
* @since 3.1
11+
*
12+
* @author Martin Georgiev <martin.georgiev@gmail.com>
13+
*/
14+
class InvalidPointArrayItemForPHPException extends ConversionException
15+
{
16+
private static function create(string $message, mixed $value): self
17+
{
18+
return new self(\sprintf($message, \var_export($value, true)));
19+
}
20+
21+
public static function forInvalidType(mixed $value): self
22+
{
23+
return self::create('Array values must be strings, %s given', $value);
24+
}
25+
26+
public static function forInvalidFormat(mixed $value): self
27+
{
28+
return self::create('Invalid point format in array: %s', $value);
29+
}
30+
31+
public static function forInvalidArrayType(mixed $value): self
32+
{
33+
return self::create('Value must be an array, %s given', $value);
34+
}
35+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;
6+
7+
use Doctrine\DBAL\Types\ConversionException;
8+
9+
/**
10+
* @since 3.1
11+
*
12+
* @author Martin Georgiev <martin.georgiev@gmail.com>
13+
*/
14+
class InvalidPointForDatabaseException extends ConversionException
15+
{
16+
private static function create(string $message, mixed $value): self
17+
{
18+
return new self(\sprintf($message, \var_export($value, true)));
19+
}
20+
21+
public static function forInvalidType(mixed $value): self
22+
{
23+
return self::create('Database value must be a string, %s given', $value);
24+
}
25+
26+
public static function forInvalidFormat(mixed $value): self
27+
{
28+
return self::create('Invalid point format in database: %s', $value);
29+
}
30+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;
6+
7+
use Doctrine\DBAL\Types\ConversionException;
8+
9+
/**
10+
* @since 3.1
11+
*
12+
* @author Martin Georgiev <martin.georgiev@gmail.com>
13+
*/
14+
class InvalidPointForPHPException extends ConversionException
15+
{
16+
private static function create(string $message, mixed $value): self
17+
{
18+
return new self(\sprintf($message, \var_export($value, true)));
19+
}
20+
21+
public static function forInvalidType(mixed $value): self
22+
{
23+
return self::create('Value must be a point, %s given', $value);
24+
}
25+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\DBAL\Types;
6+
7+
use Doctrine\DBAL\Platforms\AbstractPlatform;
8+
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidPointForDatabaseException;
9+
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidPointForPHPException;
10+
use MartinGeorgiev\ValueObject\Point as PointValueObject;
11+
12+
/**
13+
* Implementation of PostgreSQL POINT data type.
14+
*
15+
* @see https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-GEOMETRIC-POINTS
16+
* @since 3.1
17+
*
18+
* @author Martin Georgiev <martin.georgiev@gmail.com>
19+
*/
20+
class Point extends BaseType
21+
{
22+
protected const TYPE_NAME = 'point';
23+
24+
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
25+
{
26+
if ($value === null) {
27+
return null;
28+
}
29+
30+
if (!$value instanceof PointValueObject) {
31+
throw InvalidPointForPHPException::forInvalidType($value);
32+
}
33+
34+
return (string) $value;
35+
}
36+
37+
public function convertToPHPValue($value, AbstractPlatform $platform): ?PointValueObject
38+
{
39+
if ($value === null) {
40+
return null;
41+
}
42+
43+
if (!\is_string($value)) {
44+
throw InvalidPointForDatabaseException::forInvalidType($value);
45+
}
46+
47+
if (!\preg_match('/\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/', $value, $matches)) {
48+
throw InvalidPointForDatabaseException::forInvalidFormat($value);
49+
}
50+
51+
return new PointValueObject((float) $matches[1], (float) $matches[2]);
52+
}
53+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\DBAL\Types;
6+
7+
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidPointArrayItemForDatabaseException;
8+
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidPointArrayItemForPHPException;
9+
use MartinGeorgiev\ValueObject\Point as PointValueObject;
10+
11+
/**
12+
* Implementation of PostgreSQL POINT[] data type.
13+
*
14+
* @see https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-GEOMETRIC-POINTS
15+
* @since 3.1
16+
*
17+
* @author Martin Georgiev <martin.georgiev@gmail.com>
18+
*/
19+
class PointArray extends BaseArray
20+
{
21+
protected const TYPE_NAME = 'point[]';
22+
23+
protected function transformArrayItemForPostgres(mixed $item): string
24+
{
25+
if (!$item instanceof PointValueObject) {
26+
throw InvalidPointArrayItemForDatabaseException::isNotAPoint($item);
27+
}
28+
29+
return '"'.$item.'"';
30+
}
31+
32+
protected function transformPostgresArrayToPHPArray(string $postgresArray): array
33+
{
34+
if (!\str_starts_with($postgresArray, '{"') || !\str_ends_with($postgresArray, '"}')) {
35+
return [];
36+
}
37+
38+
$trimmedPostgresArray = \mb_substr($postgresArray, 2, -2);
39+
if ($trimmedPostgresArray === '') {
40+
return [];
41+
}
42+
43+
return \explode('","', $trimmedPostgresArray);
44+
}
45+
46+
public function transformArrayItemForPHP(mixed $item): ?PointValueObject
47+
{
48+
if ($item === null) {
49+
return null;
50+
}
51+
52+
if (!\is_string($item)) {
53+
$this->throwInvalidTypeException($item);
54+
}
55+
56+
if (!\preg_match('/^\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)$/', $item, $matches)) {
57+
$this->throwInvalidFormatException($item);
58+
}
59+
60+
return new PointValueObject((float) $matches[1], (float) $matches[2]);
61+
}
62+
63+
public function isValidArrayItemForDatabase(mixed $item): bool
64+
{
65+
return $item instanceof PointValueObject;
66+
}
67+
68+
protected function throwInvalidTypeException(mixed $value): never
69+
{
70+
throw InvalidPointArrayItemForPHPException::forInvalidType($value);
71+
}
72+
73+
protected function throwInvalidFormatException(mixed $value): never
74+
{
75+
throw InvalidPointArrayItemForPHPException::forInvalidFormat($value);
76+
}
77+
78+
protected function throwInvalidItemException(): never
79+
{
80+
throw InvalidPointArrayItemForPHPException::forInvalidFormat('Array contains invalid point items');
81+
}
82+
}

0 commit comments

Comments
 (0)