diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 43ecb01bcc0..90c89e2ed0f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,4 +6,4 @@ updates: interval: "weekly" labels: - "CI" - target-branch: "3.8.x" + target-branch: "3.9.x" diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index e939ea96d8a..d377aab3608 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -25,4 +25,4 @@ on: jobs: coding-standards: name: "Coding Standards" - uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.0.1" + uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.2.0" diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 22d980ff81c..ce3b57a5e81 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -40,6 +40,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" dependencies: - "highest" extension: @@ -107,6 +108,9 @@ jobs: - "18" - "21" - "23" + include: + - php-version: "8.4" + oracle-version: "23" services: oracle: @@ -164,6 +168,9 @@ jobs: - "18" - "21" - "23" + include: + - php-version: "8.4" + oracle-version: "23" services: oracle: @@ -227,6 +234,12 @@ jobs: postgres-version: "16" extension: "pgsql" - php-version: "8.3" + postgres-version: "16" + extension: "pgsql" + - php-version: "8.4" + postgres-version: "16" + extension: "pgsql" + - php-version: "8.4" postgres-version: "16" extension: "pdo_pgsql" @@ -299,6 +312,12 @@ jobs: - php-version: "8.3" mariadb-version: "11.4" extension: "pdo_mysql" + - php-version: "8.4" + mariadb-version: "11.4" + extension: "mysqli" + - php-version: "8.4" + mariadb-version: "11.4" + extension: "pdo_mysql" services: mariadb: @@ -381,6 +400,12 @@ jobs: extension: "pdo_mysql" custom-entrypoint: >- --entrypoint sh mysql:8.4 -c "exec docker-entrypoint.sh mysqld --mysql-native-password=ON" + - php-version: "8.4" + mysql-version: "9.0" + extension: "mysqli" + - php-version: "8.4" + mysql-version: "9.0" + extension: "pdo_mysql" services: mysql: @@ -438,6 +463,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" extension: - "sqlsrv" - "pdo_sqlsrv" @@ -505,6 +531,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" services: ibm_db2: diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000000..bf2ba69d770 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,20 @@ +name: "Documentation" + +on: + pull_request: + branches: + - "*.x" + paths: + - ".github/workflows/documentation.yml" + - "docs/**" + push: + branches: + - "*.x" + paths: + - ".github/workflows/documentation.yml" + - "docs/**" + +jobs: + documentation: + name: "Documentation" + uses: "doctrine/.github/.github/workflows/documentation.yml@5.2.0" diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml index 4c1e99c4c7c..75f7febb7fa 100644 --- a/.github/workflows/release-on-milestone-closed.yml +++ b/.github/workflows/release-on-milestone-closed.yml @@ -15,7 +15,7 @@ jobs: uses: "actions/checkout@v4" - name: "Release" - uses: "laminas/automatic-releases@1.24.0" + uses: "laminas/automatic-releases@1.25.0" with: command-name: "laminas:automatic-releases:release" env: diff --git a/composer.json b/composer.json index 596ec02eec8..3ba2e6f56dc 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.2", - "phpstan/phpstan": "1.12.0", + "phpstan/phpstan": "1.12.6", "phpstan/phpstan-phpunit": "1.4.0", "phpstan/phpstan-strict-rules": "^1.6", "phpunit/phpunit": "10.5.30", diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index c17fb079a95..eb236b22634 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -409,7 +409,7 @@ Connect to your Postgres server and run the ``SHOW server_version`` query:: (1 row) In the example above, ``15.2 (Debian 15.2-1.pgdg110+1)`` is the correct value for -``server Version``. +``serverVersion``. Other Platforms ^^^^^^^^^^^^^^^ diff --git a/docs/en/reference/testing.rst b/docs/en/reference/testing.rst index fdde5b238ff..87f6956700b 100644 --- a/docs/en/reference/testing.rst +++ b/docs/en/reference/testing.rst @@ -85,7 +85,7 @@ We do not currently have specific instructions on how to run a Database server, but we do recommend Docker as a convenient way to do so. We do not recommend running against a particular version of the chosen RDBMS either, as long as you pick one of the -:doc:`officially supported versions `. +:doc:`officially supported versions `. Recommendations on Writing Tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/en/sidebar.rst b/docs/en/sidebar.rst index 6dbc0dfeaf2..e74e4ca2f9e 100644 --- a/docs/en/sidebar.rst +++ b/docs/en/sidebar.rst @@ -1,41 +1,36 @@ -.. toc:: - - .. tocheader:: Reference - - .. toctree:: - :depth: 3 - - /reference/introduction - /reference/architecture - /reference/configuration - /reference/data-retrieval-and-manipulation - /reference/query-builder - /reference/transactions - /reference/platforms - /reference/types - /reference/schema-manager - /reference/schema-representation - /reference/security - /reference/supporting-other-databases - /reference/portability - /reference/caching - /reference/known-vendor-issues - /reference/testing - -.. toc:: - - .. tocheader:: Explanation - - .. toctree:: - :depth: 3 - - /explanation/implicit-indexes - -.. toc:: - - .. tocheader:: How To - - .. toctree:: - :depth: 3 - - /how-to/postgresql-identity-migration +:orphan: + +.. toctree:: + :caption: Reference + :depth: 3 + + /reference/introduction + /reference/architecture + /reference/configuration + /reference/data-retrieval-and-manipulation + /reference/query-builder + /reference/transactions + /reference/platforms + /reference/types + /reference/schema-manager + /reference/schema-representation + /reference/security + /reference/supporting-other-databases + /reference/portability + /reference/caching + /reference/known-vendor-issues + /reference/cli-tools + /reference/testing + + +.. toctree:: + :caption: Explanation + :depth: 3 + + /explanation/implicit-indexes + +.. toctree:: + :caption: How To + :depth: 3 + + /how-to/postgresql-identity-migration diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 164caf3ae56..2a04d32d39c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -63,6 +63,9 @@ parameters: - message: '~^Parameter #1 \$driverOptions of method Doctrine\\DBAL\\Tests\\Functional\\Driver\\Mysqli\\ConnectionTest\:\:getConnection\(\) expects array, .* given\.$~' path: tests/Functional/Driver/Mysqli/ConnectionTest.php + - + message: '~^Parameter #1 \$params of method Doctrine\\DBAL\\Driver\:\:connect\(\) expects array~' + path: tests/Driver/PDO/*/DriverTest.php # DriverManagerTest::testDatabaseUrl() should be refactored as it's too dynamic. - diff --git a/psalm.xml.dist b/psalm.xml.dist index 56d83d38e34..af28777385c 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -134,6 +134,7 @@ + diff --git a/src/Driver/PDO/Exception/InvalidConfiguration.php b/src/Driver/PDO/Exception/InvalidConfiguration.php new file mode 100644 index 00000000000..4f9d9c2d415 --- /dev/null +++ b/src/Driver/PDO/Exception/InvalidConfiguration.php @@ -0,0 +1,23 @@ +constructPdoDsn(array_intersect_key($params, ['path' => true, 'memory' => true])), diff --git a/src/Schema/AbstractSchemaManager.php b/src/Schema/AbstractSchemaManager.php index 97307979a96..8b6aa51af4f 100644 --- a/src/Schema/AbstractSchemaManager.php +++ b/src/Schema/AbstractSchemaManager.php @@ -17,6 +17,7 @@ use function array_map; use function array_values; use function count; +use function preg_match; use function strtolower; /** @@ -129,6 +130,21 @@ public function listTableIndexes(string $table): array ); } + /** + * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns + * the type given as default. + * + * @internal This method should be only used from within the AbstractSchemaManager class hierarchy. + */ + public function extractDoctrineTypeFromComment(?string $comment, string $currentType): string + { + if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match) === 1) { + return $match[1]; + } + + return $currentType; + } + /** * Returns true if all the given tables exist. * diff --git a/src/Schema/MySQLSchemaManager.php b/src/Schema/MySQLSchemaManager.php index 1c0915905fa..8db5bd4393e 100644 --- a/src/Schema/MySQLSchemaManager.php +++ b/src/Schema/MySQLSchemaManager.php @@ -133,6 +133,7 @@ protected function _getPortableTableColumnDefinition(array $tableColumn): Column $precision = null; $type = $this->platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'] ?? null, $type); switch ($dbType) { case 'char': diff --git a/src/Schema/OracleSchemaManager.php b/src/Schema/OracleSchemaManager.php index 3de6892c81c..c34d011c903 100644 --- a/src/Schema/OracleSchemaManager.php +++ b/src/Schema/OracleSchemaManager.php @@ -135,6 +135,7 @@ protected function _getPortableTableColumnDefinition(array $tableColumn): Column } $type = $this->platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'] ?? null, $type); switch ($dbType) { case 'number': diff --git a/src/Schema/PostgreSQLSchemaManager.php b/src/Schema/PostgreSQLSchemaManager.php index db27815c551..be4a9b76f30 100644 --- a/src/Schema/PostgreSQLSchemaManager.php +++ b/src/Schema/PostgreSQLSchemaManager.php @@ -273,6 +273,7 @@ protected function _getPortableTableColumnDefinition(array $tableColumn): Column } $type = $this->platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'] ?? null, $type); switch ($dbType) { case 'smallint': diff --git a/src/Schema/SQLServerSchemaManager.php b/src/Schema/SQLServerSchemaManager.php index e0a74ce2a81..b0f0fa92150 100644 --- a/src/Schema/SQLServerSchemaManager.php +++ b/src/Schema/SQLServerSchemaManager.php @@ -118,6 +118,7 @@ protected function _getPortableTableColumnDefinition(array $tableColumn): Column } $type = $this->platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'] ?? null, $type); $options = [ 'fixed' => $fixed, diff --git a/src/Schema/SQLiteSchemaManager.php b/src/Schema/SQLiteSchemaManager.php index 86f2cbe99aa..1b1a727af1d 100644 --- a/src/Schema/SQLiteSchemaManager.php +++ b/src/Schema/SQLiteSchemaManager.php @@ -244,7 +244,9 @@ protected function _getPortableTableColumnDefinition(array $tableColumn): Column $unsigned = true; } - $type = $this->platform->getDoctrineTypeMapping($dbType); + $type = $this->platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'] ?? null, $type); + $default = $tableColumn['dflt_value']; if ($default === 'NULL') { $default = null; diff --git a/tests/Driver/PDO/MySQL/DriverTest.php b/tests/Driver/PDO/MySQL/DriverTest.php index f56bad7f904..82168baac6f 100644 --- a/tests/Driver/PDO/MySQL/DriverTest.php +++ b/tests/Driver/PDO/MySQL/DriverTest.php @@ -4,13 +4,31 @@ namespace Doctrine\DBAL\Tests\Driver\PDO\MySQL; -use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\PDO\Exception\InvalidConfiguration; use Doctrine\DBAL\Driver\PDO\MySQL\Driver; use Doctrine\DBAL\Tests\Driver\AbstractMySQLDriverTestCase; class DriverTest extends AbstractMySQLDriverTestCase { - protected function createDriver(): DriverInterface + public function testUserIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The user configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['user' => false]); + } + + public function testPasswordIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The password configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['password' => false]); + } + + protected function createDriver(): Driver { return new Driver(); } diff --git a/tests/Driver/PDO/OCI/DriverTest.php b/tests/Driver/PDO/OCI/DriverTest.php index 9cf86eaf9fa..3d16b288e79 100644 --- a/tests/Driver/PDO/OCI/DriverTest.php +++ b/tests/Driver/PDO/OCI/DriverTest.php @@ -4,13 +4,31 @@ namespace Doctrine\DBAL\Tests\Driver\PDO\OCI; -use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\PDO\Exception\InvalidConfiguration; use Doctrine\DBAL\Driver\PDO\OCI\Driver; use Doctrine\DBAL\Tests\Driver\AbstractOracleDriverTestCase; class DriverTest extends AbstractOracleDriverTestCase { - protected function createDriver(): DriverInterface + public function testUserIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The user configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['user' => false]); + } + + public function testPasswordIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The password configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['password' => false]); + } + + protected function createDriver(): Driver { return new Driver(); } diff --git a/tests/Driver/PDO/PgSQL/DriverTest.php b/tests/Driver/PDO/PgSQL/DriverTest.php index cb4b3ad9aa0..5f6cdbc71a1 100644 --- a/tests/Driver/PDO/PgSQL/DriverTest.php +++ b/tests/Driver/PDO/PgSQL/DriverTest.php @@ -4,9 +4,9 @@ namespace Doctrine\DBAL\Tests\Driver\PDO\PgSQL; -use Doctrine\DBAL\Driver as DriverInterface; use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\PDO; +use Doctrine\DBAL\Driver\PDO\Exception\InvalidConfiguration; use Doctrine\DBAL\Driver\PDO\PgSQL\Driver; use Doctrine\DBAL\Tests\Driver\AbstractPostgreSQLDriverTestCase; use Doctrine\DBAL\Tests\TestUtil; @@ -60,7 +60,25 @@ public function testConnectionDisablePreparesWhenDisablePreparesIsExplicitlyDefi ); } - protected function createDriver(): DriverInterface + public function testUserIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The user configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['user' => false]); + } + + public function testPasswordIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The password configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['password' => false]); + } + + protected function createDriver(): Driver { return new Driver(); } diff --git a/tests/Driver/PDO/SQLSrv/DriverTest.php b/tests/Driver/PDO/SQLSrv/DriverTest.php index 3d3fda54699..37b8d57fb7b 100644 --- a/tests/Driver/PDO/SQLSrv/DriverTest.php +++ b/tests/Driver/PDO/SQLSrv/DriverTest.php @@ -4,13 +4,31 @@ namespace Doctrine\DBAL\Tests\Driver\PDO\SQLSrv; -use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\PDO\Exception\InvalidConfiguration; use Doctrine\DBAL\Driver\PDO\SQLSrv\Driver; use Doctrine\DBAL\Tests\Driver\AbstractSQLServerDriverTestCase; class DriverTest extends AbstractSQLServerDriverTestCase { - protected function createDriver(): DriverInterface + public function testUserIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The user configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['user' => false]); + } + + public function testPasswordIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The password configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['password' => false]); + } + + protected function createDriver(): Driver { return new Driver(); } diff --git a/tests/Driver/PDO/SQLite/DriverTest.php b/tests/Driver/PDO/SQLite/DriverTest.php index 88bc29d20c5..b75e9f4ba6e 100644 --- a/tests/Driver/PDO/SQLite/DriverTest.php +++ b/tests/Driver/PDO/SQLite/DriverTest.php @@ -4,13 +4,31 @@ namespace Doctrine\DBAL\Tests\Driver\PDO\SQLite; -use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\PDO\Exception\InvalidConfiguration; use Doctrine\DBAL\Driver\PDO\SQLite\Driver; use Doctrine\DBAL\Tests\Driver\AbstractSQLiteDriverTestCase; class DriverTest extends AbstractSQLiteDriverTestCase { - protected function createDriver(): DriverInterface + public function testUserIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The user configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['user' => false]); + } + + public function testPasswordIsFalse(): void + { + $this->expectException(InvalidConfiguration::class); + $this->expectExceptionMessage( + 'The password configuration parameter is expected to be either a string or null, got bool.', + ); + $this->driver->connect(['password' => false]); + } + + protected function createDriver(): Driver { return new Driver(); }