Skip to content

Commit 92461e9

Browse files
committed
Initial commit
0 parents  commit 92461e9

19 files changed

+1982
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vendor
2+
/composer.lock
3+
.phpunit.result.cache

.php-cs-fixer.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
$projectDir = __DIR__;
4+
5+
$finder = PhpCsFixer\Finder::create()->in(["$projectDir/src"]);
6+
$config = new PhpCsFixer\Config();
7+
$config
8+
->setRiskyAllowed(true)
9+
->setRules([
10+
'align_multiline_comment' => true,
11+
'array_syntax' => ['syntax' => 'short'],
12+
'binary_operator_spaces' => [
13+
'default' => 'single_space',
14+
],
15+
'blank_line_after_namespace' => true,
16+
'blank_line_before_statement' => true,
17+
'concat_space' => ['spacing' => 'one'],
18+
'doctrine_annotation_braces' => false,
19+
'linebreak_after_opening_tag' => true,
20+
'phpdoc_add_missing_param_annotation' => true,
21+
'ordered_imports' => true,
22+
'phpdoc_order' => true,
23+
'phpdoc_types_order' => true,
24+
'declare_strict_types' => true,
25+
'no_superfluous_phpdoc_tags' => false,
26+
'yoda_style' => ['equal' => false, 'identical'=>false, 'less_and_greater' => false],
27+
])
28+
->setUsingCache(false)
29+
->setFinder($finder)
30+
;
31+
32+
return $config;

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Pavel Filimonov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

composer.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "pfilsx/postgresql-doctrine",
3+
"type": "library",
4+
"description": "Extended Doctrine DBAL and Doctrine migrations classes for postgresql specific features support",
5+
"license": "MIT",
6+
"keywords": [
7+
"doctrine",
8+
"doctrine-dbal",
9+
"doctrine-migrations",
10+
"migrations",
11+
"postgresql",
12+
"enum",
13+
"php8"
14+
],
15+
"minimum-stability": "stable",
16+
"authors": [
17+
{
18+
"name": "Pavel Filimonov",
19+
"email": "[email protected]"
20+
}
21+
],
22+
"require": {
23+
"php": "^7.4",
24+
"doctrine/dbal": "^3.5.1",
25+
"doctrine/migrations": "^3.5.2"
26+
},
27+
"autoload": {
28+
"psr-4": {
29+
"Pfilsx\\PostgreSQLDoctrine\\": "src/"
30+
}
31+
},
32+
"require-dev": {
33+
"friendsofphp/php-cs-fixer": "^3.13"
34+
}
35+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\DBAL\Contract;
6+
7+
8+
interface EnumInterface
9+
{
10+
/**
11+
* @return array<string|int>
12+
*/
13+
public static function cases(): array;
14+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\DBAL\DriverWrapper;
6+
7+
8+
use Doctrine\DBAL\Connection;
9+
use Doctrine\DBAL\Driver\Connection as DriverConnection;
10+
use Doctrine\DBAL\Driver;
11+
use Doctrine\DBAL\Driver\API\ExceptionConverter;
12+
use Doctrine\DBAL\Platforms\AbstractPlatform;
13+
use Doctrine\DBAL\Schema\AbstractSchemaManager;
14+
use Doctrine\DBAL\VersionAwarePlatformDriver;
15+
use Pfilsx\PostgreSQLDoctrine\DBAL\Platform\PostgreSQLPlatform;
16+
use Pfilsx\PostgreSQLDoctrine\DBAL\Schema\PostgreSQLSchemaManager;
17+
18+
final class PostgreSQLDriverWrapper implements VersionAwarePlatformDriver
19+
{
20+
private Driver $innerDriver;
21+
22+
public function __construct(Driver $innerDriver)
23+
{
24+
$this->innerDriver = $innerDriver;
25+
}
26+
27+
28+
public function connect(array $params): DriverConnection
29+
{
30+
return $this->innerDriver->connect($params);
31+
}
32+
33+
public function getDatabasePlatform(): PostgreSQLPlatform
34+
{
35+
return new PostgreSQLPlatform();
36+
}
37+
38+
public function createDatabasePlatformForVersion($version): PostgreSQLPlatform
39+
{
40+
return new PostgreSQLPlatform();
41+
}
42+
43+
public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager
44+
{
45+
\assert($platform instanceof PostgreSQLPlatform);
46+
47+
return new PostgreSQLSchemaManager($conn, $platform);
48+
}
49+
50+
public function getExceptionConverter(): ExceptionConverter
51+
{
52+
return $this->innerDriver->getExceptionConverter();
53+
}
54+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\DBAL\Middleware;
6+
7+
8+
use Doctrine\DBAL\Driver;
9+
use Doctrine\DBAL\Driver\Middleware;
10+
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
11+
use Pfilsx\PostgreSQLDoctrine\DBAL\DriverWrapper\PostgreSQLDriverWrapper;
12+
13+
final class PostgreSQLDriverMiddleware implements Middleware
14+
{
15+
public function wrap(Driver $driver): Driver
16+
{
17+
return $driver->getDatabasePlatform() instanceof PostgreSQLPlatform
18+
? new PostgreSQLDriverWrapper($driver)
19+
: $driver
20+
;
21+
}
22+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\DBAL\Platform;
6+
7+
use Doctrine\DBAL\Connection;
8+
use Doctrine\DBAL\Exception;
9+
use Doctrine\DBAL\Platforms\PostgreSQLPlatform as BasePlatform;
10+
use Pfilsx\PostgreSQLDoctrine\DBAL\Schema\EnumTypeAsset;
11+
use Pfilsx\PostgreSQLDoctrine\DBAL\Schema\PostgreSQLSchemaManager;
12+
use Pfilsx\PostgreSQLDoctrine\DBAL\Type\EnumType;
13+
14+
final class PostgreSQLPlatform extends BasePlatform
15+
{
16+
public function createSchemaManager(Connection $connection): PostgreSQLSchemaManager
17+
{
18+
return new PostgreSQLSchemaManager($connection, $this);
19+
}
20+
21+
public function getListEnumTypesSQL(): string
22+
{
23+
return 'SELECT pg_type.typname AS name,
24+
pg_enum.enumlabel AS label,
25+
pg_description.description AS comment
26+
FROM pg_type
27+
JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid
28+
LEFT JOIN pg_description on pg_description.objoid = pg_type.oid
29+
ORDER BY pg_enum.enumsortorder';
30+
}
31+
32+
/**
33+
* @param EnumTypeAsset $type
34+
* @return string
35+
* @throws Exception\InvalidArgumentException
36+
*/
37+
public function getCreateTypeSql(EnumTypeAsset $type): string
38+
{
39+
return "CREATE TYPE {$type->getQuotedName($this)} AS ENUM(" . \implode(', ', $type->getQuotedLabels($this)) . ')';
40+
}
41+
42+
public function getCommentOnTypeSql(EnumTypeAsset $type): string
43+
{
44+
return "COMMENT ON TYPE {$type->getQuotedName($this)} IS '{$type->getEnumClass()}'";
45+
}
46+
47+
public function getAlterTypeSql(EnumTypeAsset $from, EnumTypeAsset $to): string
48+
{
49+
throw Exception::notSupported(__METHOD__);
50+
}
51+
52+
public function getDropTypeSql(EnumTypeAsset $type): string
53+
{
54+
return "DROP TYPE {$type->getQuotedName($this)}";
55+
}
56+
57+
protected function initializeDoctrineTypeMappings()
58+
{
59+
parent::initializeDoctrineTypeMappings();
60+
61+
$this->doctrineTypeMapping[EnumType::NAME] = EnumType::NAME;
62+
}
63+
64+
}

src/DBAL/Schema/Column.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\DBAL\Schema;
6+
7+
8+
final class Column extends \Doctrine\DBAL\Schema\Column
9+
{
10+
private ?string $_enumClass = null;
11+
12+
public function getEnumClass(): ?string
13+
{
14+
return $this->_enumClass;
15+
}
16+
17+
public function setEnumClass(?string $enumClass): self
18+
{
19+
$this->_enumClass = $enumClass;
20+
return $this;
21+
}
22+
23+
/**
24+
* @return array<string, mixed>
25+
*/
26+
public function toArray(): array
27+
{
28+
return array_merge([
29+
'name' => $this->_name,
30+
'type' => $this->_type,
31+
'default' => $this->_default,
32+
'notnull' => $this->_notnull,
33+
'length' => $this->_length,
34+
'precision' => $this->_precision,
35+
'scale' => $this->_scale,
36+
'fixed' => $this->_fixed,
37+
'unsigned' => $this->_unsigned,
38+
'autoincrement' => $this->_autoincrement,
39+
'columnDefinition' => $this->_columnDefinition,
40+
'comment' => $this->_comment,
41+
'enumType' => $this->_enumClass,
42+
], $this->_platformOptions, $this->_customSchemaOptions);
43+
}
44+
}

src/DBAL/Schema/Comparator.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\DBAL\Schema;
6+
7+
use Doctrine\DBAL\Schema\Comparator as BaseComparator;
8+
9+
final class Comparator extends BaseComparator
10+
{
11+
public function compareSchemas(Schema $fromSchema, Schema $toSchema): SchemaDiff
12+
{
13+
$baseDiff = parent::compareSchemas($fromSchema, $toSchema);
14+
15+
$createdTypes = [];
16+
$alteredTypes = [];
17+
$droppedTypes = [];
18+
19+
foreach ($toSchema->getEnumTypes() as $type) {
20+
$typeName = $type->getShortestName($toSchema->getName());
21+
if (!$fromSchema->hasEnumType($typeName)) {
22+
$createdTypes[] = $type;
23+
} else {
24+
if ($type->getLabels() !== ($fromType = $fromSchema->getEnumType($typeName))->getLabels()) {
25+
$alteredTypes[] = ['from' => $fromType, 'to' => $type];
26+
}
27+
}
28+
}
29+
30+
foreach ($fromSchema->getEnumTypes() as $type) {
31+
$typeName = $type->getShortestName($fromSchema->getName());
32+
33+
if ($toSchema->hasEnumType($typeName)) {
34+
continue;
35+
}
36+
37+
$droppedTypes[] = $type;
38+
}
39+
40+
$diff = new SchemaDiff(
41+
$baseDiff->getCreatedTables(),
42+
$baseDiff->getAlteredTables(),
43+
$baseDiff->getDroppedTables(),
44+
$baseDiff->fromSchema,
45+
$baseDiff->getCreatedSchemas(),
46+
$baseDiff->getDroppedSchemas(),
47+
$baseDiff->getCreatedSequences(),
48+
$baseDiff->getAlteredSequences(),
49+
$baseDiff->getDroppedSequences(),
50+
$createdTypes,
51+
$alteredTypes,
52+
$droppedTypes
53+
);
54+
55+
$diff->orphanedForeignKeys = $baseDiff->orphanedForeignKeys;
56+
57+
return $diff;
58+
}
59+
}

0 commit comments

Comments
 (0)