├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── phpstan-baseline.neon └── src ├── ArrayParameterType.php ├── ArrayParameters ├── Exception.php └── Exception │ ├── MissingNamedParameter.php │ └── MissingPositionalParameter.php ├── Cache ├── ArrayResult.php ├── CacheException.php ├── Exception │ ├── NoCacheKey.php │ └── NoResultDriverConfigured.php └── QueryCacheProfile.php ├── ColumnCase.php ├── Configuration.php ├── Connection.php ├── Connection └── StaticServerVersionProvider.php ├── ConnectionException.php ├── Connections └── PrimaryReadReplicaConnection.php ├── Driver.php ├── Driver ├── API │ ├── ExceptionConverter.php │ ├── IBMDB2 │ │ └── ExceptionConverter.php │ ├── MySQL │ │ └── ExceptionConverter.php │ ├── OCI │ │ └── ExceptionConverter.php │ ├── PostgreSQL │ │ └── ExceptionConverter.php │ ├── SQLSrv │ │ └── ExceptionConverter.php │ └── SQLite │ │ └── ExceptionConverter.php ├── AbstractDB2Driver.php ├── AbstractException.php ├── AbstractMySQLDriver.php ├── AbstractOracleDriver.php ├── AbstractOracleDriver │ └── EasyConnectString.php ├── AbstractPostgreSQLDriver.php ├── AbstractSQLServerDriver.php ├── AbstractSQLServerDriver │ └── Exception │ │ └── PortWithoutHost.php ├── AbstractSQLiteDriver.php ├── AbstractSQLiteDriver │ └── Middleware │ │ └── EnableForeignKeys.php ├── Connection.php ├── Exception.php ├── Exception │ ├── IdentityColumnsNotSupported.php │ └── NoIdentityValue.php ├── FetchUtils.php ├── IBMDB2 │ ├── Connection.php │ ├── DataSourceName.php │ ├── Driver.php │ ├── Exception │ │ ├── CannotCopyStreamToStream.php │ │ ├── CannotCreateTemporaryFile.php │ │ ├── ConnectionError.php │ │ ├── ConnectionFailed.php │ │ ├── Factory.php │ │ ├── PrepareFailed.php │ │ └── StatementError.php │ ├── Result.php │ └── Statement.php ├── Middleware.php ├── Middleware │ ├── AbstractConnectionMiddleware.php │ ├── AbstractDriverMiddleware.php │ ├── AbstractResultMiddleware.php │ └── AbstractStatementMiddleware.php ├── Mysqli │ ├── Connection.php │ ├── Driver.php │ ├── Exception │ │ ├── ConnectionError.php │ │ ├── ConnectionFailed.php │ │ ├── FailedReadingStreamOffset.php │ │ ├── HostRequired.php │ │ ├── InvalidCharset.php │ │ ├── InvalidOption.php │ │ ├── NonStreamResourceUsedAsLargeObject.php │ │ └── StatementError.php │ ├── Initializer.php │ ├── Initializer │ │ ├── Charset.php │ │ ├── Options.php │ │ └── Secure.php │ ├── Result.php │ └── Statement.php ├── OCI8 │ ├── Connection.php │ ├── ConvertPositionalToNamedPlaceholders.php │ ├── Driver.php │ ├── Exception │ │ ├── ConnectionFailed.php │ │ ├── Error.php │ │ ├── InvalidConfiguration.php │ │ ├── NonTerminatedStringLiteral.php │ │ └── UnknownParameterIndex.php │ ├── ExecutionMode.php │ ├── Middleware │ │ └── InitializeSession.php │ ├── Result.php │ └── Statement.php ├── PDO │ ├── Connection.php │ ├── Exception.php │ ├── Exception │ │ └── InvalidConfiguration.php │ ├── MySQL │ │ └── Driver.php │ ├── OCI │ │ └── Driver.php │ ├── PDOConnect.php │ ├── PgSQL │ │ └── Driver.php │ ├── Result.php │ ├── SQLSrv │ │ ├── Connection.php │ │ ├── Driver.php │ │ └── Statement.php │ ├── SQLite │ │ └── Driver.php │ └── Statement.php ├── PgSQL │ ├── Connection.php │ ├── ConvertParameters.php │ ├── Driver.php │ ├── Exception.php │ ├── Exception │ │ ├── UnexpectedValue.php │ │ └── UnknownParameter.php │ ├── Result.php │ └── Statement.php ├── Result.php ├── SQLSrv │ ├── Connection.php │ ├── Driver.php │ ├── Exception │ │ └── Error.php │ ├── Result.php │ └── Statement.php ├── SQLite3 │ ├── Connection.php │ ├── Driver.php │ ├── Exception.php │ ├── Result.php │ └── Statement.php └── Statement.php ├── DriverManager.php ├── Exception.php ├── Exception ├── CommitFailedRollbackOnly.php ├── ConnectionException.php ├── ConnectionLost.php ├── ConstraintViolationException.php ├── DatabaseDoesNotExist.php ├── DatabaseObjectExistsException.php ├── DatabaseObjectNotFoundException.php ├── DatabaseRequired.php ├── DeadlockException.php ├── DriverException.php ├── DriverRequired.php ├── ForeignKeyConstraintViolationException.php ├── InvalidArgumentException.php ├── InvalidColumnDeclaration.php ├── InvalidColumnIndex.php ├── InvalidColumnType.php ├── InvalidColumnType │ ├── ColumnLengthRequired.php │ ├── ColumnPrecisionRequired.php │ ├── ColumnScaleRequired.php │ └── ColumnValuesRequired.php ├── InvalidDriverClass.php ├── InvalidFieldNameException.php ├── InvalidWrapperClass.php ├── LockWaitTimeoutException.php ├── MalformedDsnException.php ├── NoActiveTransaction.php ├── NoKeyValue.php ├── NonUniqueFieldNameException.php ├── NotNullConstraintViolationException.php ├── ReadOnlyException.php ├── RetryableException.php ├── SavepointsNotSupported.php ├── SchemaDoesNotExist.php ├── ServerException.php ├── SyntaxErrorException.php ├── TableExistsException.php ├── TableNotFoundException.php ├── TransactionRolledBack.php ├── UniqueConstraintViolationException.php └── UnknownDriver.php ├── ExpandArrayParameters.php ├── LockMode.php ├── Logging ├── Connection.php ├── Driver.php ├── Middleware.php └── Statement.php ├── ParameterType.php ├── Platforms ├── AbstractMySQLPlatform.php ├── AbstractPlatform.php ├── DB2Platform.php ├── DateIntervalUnit.php ├── Exception │ ├── InvalidPlatformVersion.php │ ├── NoColumnsSpecifiedForTable.php │ ├── NotSupported.php │ └── PlatformException.php ├── Keywords │ ├── DB2Keywords.php │ ├── KeywordList.php │ ├── MariaDBKeywords.php │ ├── MySQL80Keywords.php │ ├── MySQL84Keywords.php │ ├── MySQLKeywords.php │ ├── OracleKeywords.php │ ├── PostgreSQLKeywords.php │ ├── SQLServerKeywords.php │ └── SQLiteKeywords.php ├── MariaDB1010Platform.php ├── MariaDB1052Platform.php ├── MariaDB1060Platform.php ├── MariaDBPlatform.php ├── MySQL │ ├── CharsetMetadataProvider.php │ ├── CharsetMetadataProvider │ │ ├── CachingCharsetMetadataProvider.php │ │ └── ConnectionCharsetMetadataProvider.php │ ├── CollationMetadataProvider.php │ ├── CollationMetadataProvider │ │ ├── CachingCollationMetadataProvider.php │ │ └── ConnectionCollationMetadataProvider.php │ ├── Comparator.php │ └── DefaultTableOptions.php ├── MySQL80Platform.php ├── MySQL84Platform.php ├── MySQLPlatform.php ├── OraclePlatform.php ├── PostgreSQL120Platform.php ├── PostgreSQLPlatform.php ├── SQLServer │ ├── Comparator.php │ └── SQL │ │ └── Builder │ │ └── SQLServerSelectSQLBuilder.php ├── SQLServerPlatform.php ├── SQLite │ └── Comparator.php ├── SQLitePlatform.php └── TrimMode.php ├── Portability ├── Connection.php ├── Converter.php ├── Driver.php ├── Middleware.php ├── OptimizeFlags.php ├── Result.php └── Statement.php ├── Query.php ├── Query ├── Exception │ ├── NonUniqueAlias.php │ └── UnknownAlias.php ├── Expression │ ├── CompositeExpression.php │ └── ExpressionBuilder.php ├── ForUpdate.php ├── ForUpdate │ └── ConflictResolutionMode.php ├── From.php ├── Join.php ├── Limit.php ├── QueryBuilder.php ├── QueryException.php ├── QueryType.php ├── SelectQuery.php ├── Union.php ├── UnionQuery.php └── UnionType.php ├── Result.php ├── SQL ├── Builder │ ├── CreateSchemaObjectsSQLBuilder.php │ ├── DefaultSelectSQLBuilder.php │ ├── DefaultUnionSQLBuilder.php │ ├── DropSchemaObjectsSQLBuilder.php │ ├── SelectSQLBuilder.php │ └── UnionSQLBuilder.php ├── Parser.php └── Parser │ ├── Exception.php │ ├── Exception │ └── RegularExpressionError.php │ └── Visitor.php ├── Schema ├── AbstractAsset.php ├── AbstractSchemaManager.php ├── Column.php ├── ColumnDiff.php ├── Comparator.php ├── DB2SchemaManager.php ├── DefaultSchemaManagerFactory.php ├── Exception │ ├── ColumnAlreadyExists.php │ ├── ColumnDoesNotExist.php │ ├── ForeignKeyDoesNotExist.php │ ├── IndexAlreadyExists.php │ ├── IndexDoesNotExist.php │ ├── IndexNameInvalid.php │ ├── InvalidTableName.php │ ├── NamespaceAlreadyExists.php │ ├── SequenceAlreadyExists.php │ ├── SequenceDoesNotExist.php │ ├── TableAlreadyExists.php │ ├── TableDoesNotExist.php │ ├── UniqueConstraintDoesNotExist.php │ └── UnknownColumnOption.php ├── ForeignKeyConstraint.php ├── Identifier.php ├── Index.php ├── MySQLSchemaManager.php ├── OracleSchemaManager.php ├── PostgreSQLSchemaManager.php ├── SQLServerSchemaManager.php ├── SQLiteSchemaManager.php ├── Schema.php ├── SchemaConfig.php ├── SchemaDiff.php ├── SchemaException.php ├── SchemaManagerFactory.php ├── Sequence.php ├── Table.php ├── TableDiff.php ├── UniqueConstraint.php └── View.php ├── ServerVersionProvider.php ├── Statement.php ├── Tools ├── Console │ ├── Command │ │ └── RunSqlCommand.php │ ├── ConnectionNotFound.php │ ├── ConnectionProvider.php │ └── ConnectionProvider │ │ └── SingleConnectionProvider.php └── DsnParser.php ├── TransactionIsolationLevel.php └── Types ├── AsciiStringType.php ├── BigIntType.php ├── BinaryType.php ├── BlobType.php ├── BooleanType.php ├── ConversionException.php ├── DateImmutableType.php ├── DateIntervalType.php ├── DateTimeImmutableType.php ├── DateTimeType.php ├── DateTimeTzImmutableType.php ├── DateTimeTzType.php ├── DateType.php ├── DecimalType.php ├── EnumType.php ├── Exception ├── InvalidFormat.php ├── InvalidType.php ├── SerializationFailed.php ├── TypeAlreadyRegistered.php ├── TypeNotFound.php ├── TypeNotRegistered.php ├── TypesAlreadyExists.php ├── TypesException.php ├── UnknownColumnType.php └── ValueNotConvertible.php ├── FloatType.php ├── GuidType.php ├── IntegerType.php ├── JsonType.php ├── PhpDateMappingType.php ├── PhpDateTimeMappingType.php ├── PhpIntegerMappingType.php ├── PhpTimeMappingType.php ├── SimpleArrayType.php ├── SmallFloatType.php ├── SmallIntType.php ├── StringType.php ├── TextType.php ├── TimeImmutableType.php ├── TimeType.php ├── Type.php ├── TypeRegistry.php ├── Types.php ├── VarDateTimeImmutableType.php └── VarDateTimeType.php /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This repository has [guidelines specific to testing][testing guidelines], and 2 | Doctrine has [general contributing guidelines][contributor workflow], make 3 | sure you follow both. 4 | 5 | [contributor workflow]: https://www.doctrine-project.org/contribute/index.html 6 | [testing guidelines]: https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/testing.html 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2018 Doctrine Project 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/ArrayParameterType.php: -------------------------------------------------------------------------------- 1 | ParameterType::INTEGER, 34 | self::STRING => ParameterType::STRING, 35 | self::ASCII => ParameterType::ASCII, 36 | self::BINARY => ParameterType::BINARY, 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/ArrayParameters/Exception.php: -------------------------------------------------------------------------------- 1 | version; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ConnectionException.php: -------------------------------------------------------------------------------- 1 | $params All connection parameters. 25 | * @phpstan-param Params $params All connection parameters. 26 | * 27 | * @return DriverConnection The database connection. 28 | * 29 | * @throws Exception 30 | */ 31 | public function connect( 32 | #[SensitiveParameter] 33 | array $params, 34 | ): DriverConnection; 35 | 36 | /** 37 | * Gets the DatabasePlatform instance that provides all the metadata about 38 | * the platform this driver connects to. 39 | * 40 | * @return AbstractPlatform The database platform. 41 | */ 42 | public function getDatabasePlatform(ServerVersionProvider $versionProvider): AbstractPlatform; 43 | 44 | /** 45 | * Gets the ExceptionConverter that can be used to convert driver-level exceptions into DBAL exceptions. 46 | */ 47 | public function getExceptionConverter(): ExceptionConverter; 48 | } 49 | -------------------------------------------------------------------------------- /src/Driver/API/ExceptionConverter.php: -------------------------------------------------------------------------------- 1 | getCode()) { 31 | -104 => new SyntaxErrorException($exception, $query), 32 | -203 => new NonUniqueFieldNameException($exception, $query), 33 | -204 => new TableNotFoundException($exception, $query), 34 | -206 => new InvalidFieldNameException($exception, $query), 35 | -407 => new NotNullConstraintViolationException($exception, $query), 36 | -530, 37 | -531, 38 | -532, 39 | -20356 => new ForeignKeyConstraintViolationException($exception, $query), 40 | -601 => new TableExistsException($exception, $query), 41 | -803 => new UniqueConstraintViolationException($exception, $query), 42 | -1336, 43 | -30082 => new ConnectionException($exception, $query), 44 | default => new DriverException($exception, $query), 45 | }; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Driver/AbstractDB2Driver.php: -------------------------------------------------------------------------------- 1 | sqlState; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Driver/AbstractOracleDriver.php: -------------------------------------------------------------------------------- 1 | $params The connection parameters to return the Easy Connect String for. 33 | */ 34 | protected function getEasyConnectString(array $params): string 35 | { 36 | return (string) EasyConnectString::fromConnectionParameters($params); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Driver/AbstractPostgreSQLDriver.php: -------------------------------------------------------------------------------- 1 | getServerVersion(); 27 | 28 | if (preg_match('/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $version, $versionParts) !== 1) { 29 | throw InvalidPlatformVersion::new( 30 | $version, 31 | '..', 32 | ); 33 | } 34 | 35 | $majorVersion = $versionParts['major']; 36 | $minorVersion = $versionParts['minor'] ?? 0; 37 | $patchVersion = $versionParts['patch'] ?? 0; 38 | $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; 39 | 40 | if (version_compare($version, '12.0', '>=')) { 41 | return new PostgreSQL120Platform(); 42 | } 43 | 44 | Deprecation::trigger( 45 | 'doctrine/dbal', 46 | 'https://github.com/doctrine/dbal/pull/6495', 47 | 'Support for Postgres < 12 is deprecated and will be removed in DBAL 5', 48 | ); 49 | 50 | return new PostgreSQLPlatform(); 51 | } 52 | 53 | public function getExceptionConverter(): ExceptionConverterInterface 54 | { 55 | return new ExceptionConverter(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Driver/AbstractSQLServerDriver.php: -------------------------------------------------------------------------------- 1 | exec('PRAGMA foreign_keys=ON'); 28 | 29 | return $connection; 30 | } 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Driver/Exception.php: -------------------------------------------------------------------------------- 1 | fetchNumeric(); 14 | 15 | if ($row === false) { 16 | return false; 17 | } 18 | 19 | return $row[0]; 20 | } 21 | 22 | /** 23 | * @return list> 24 | * 25 | * @throws Exception 26 | */ 27 | public static function fetchAllNumeric(Result $result): array 28 | { 29 | $rows = []; 30 | 31 | while (($row = $result->fetchNumeric()) !== false) { 32 | $rows[] = $row; 33 | } 34 | 35 | return $rows; 36 | } 37 | 38 | /** 39 | * @return list> 40 | * 41 | * @throws Exception 42 | */ 43 | public static function fetchAllAssociative(Result $result): array 44 | { 45 | $rows = []; 46 | 47 | while (($row = $result->fetchAssociative()) !== false) { 48 | $rows[] = $row; 49 | } 50 | 51 | return $rows; 52 | } 53 | 54 | /** 55 | * @return list 56 | * 57 | * @throws Exception 58 | */ 59 | public static function fetchFirstColumn(Result $result): array 60 | { 61 | $rows = []; 62 | 63 | while (($row = $result->fetchOne()) !== false) { 64 | $rows[] = $row; 65 | } 66 | 67 | return $rows; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Driver/IBMDB2/DataSourceName.php: -------------------------------------------------------------------------------- 1 | string; 27 | } 28 | 29 | /** 30 | * Creates the object from an array representation 31 | * 32 | * @param array $params 33 | */ 34 | public static function fromArray( 35 | #[SensitiveParameter] 36 | array $params, 37 | ): self { 38 | $chunks = []; 39 | 40 | foreach ($params as $key => $value) { 41 | $chunks[] = sprintf('%s=%s', $key, $value); 42 | } 43 | 44 | return new self(implode(';', $chunks)); 45 | } 46 | 47 | /** 48 | * Creates the object from the given DBAL connection parameters. 49 | * 50 | * @param array $params 51 | */ 52 | public static function fromConnectionParameters(#[SensitiveParameter] 53 | array $params,): self 54 | { 55 | if (isset($params['dbname']) && str_contains($params['dbname'], '=')) { 56 | return new self($params['dbname']); 57 | } 58 | 59 | $dsnParams = []; 60 | 61 | foreach ( 62 | [ 63 | 'host' => 'HOSTNAME', 64 | 'port' => 'PORT', 65 | 'protocol' => 'PROTOCOL', 66 | 'dbname' => 'DATABASE', 67 | 'user' => 'UID', 68 | 'password' => 'PWD', 69 | ] as $dbalParam => $dsnParam 70 | ) { 71 | if (! isset($params[$dbalParam])) { 72 | continue; 73 | } 74 | 75 | $dsnParams[$dsnParam] = $params[$dbalParam]; 76 | } 77 | 78 | return self::fromArray($dsnParams); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Driver/IBMDB2/Driver.php: -------------------------------------------------------------------------------- 1 | toString(); 24 | 25 | $username = $params['user'] ?? ''; 26 | $password = $params['password'] ?? ''; 27 | $driverOptions = $params['driverOptions'] ?? []; 28 | 29 | if (! empty($params['persistent'])) { 30 | $connection = db2_pconnect($dataSourceName, $username, $password, $driverOptions); 31 | } else { 32 | $connection = db2_connect($dataSourceName, $username, $password, $driverOptions); 33 | } 34 | 35 | if ($connection === false) { 36 | throw ConnectionFailed::new(); 37 | } 38 | 39 | return new Connection($connection); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php: -------------------------------------------------------------------------------- 1 | wrappedConnection->prepare($sql); 20 | } 21 | 22 | public function query(string $sql): Result 23 | { 24 | return $this->wrappedConnection->query($sql); 25 | } 26 | 27 | public function quote(string $value): string 28 | { 29 | return $this->wrappedConnection->quote($value); 30 | } 31 | 32 | public function exec(string $sql): int|string 33 | { 34 | return $this->wrappedConnection->exec($sql); 35 | } 36 | 37 | public function lastInsertId(): int|string 38 | { 39 | return $this->wrappedConnection->lastInsertId(); 40 | } 41 | 42 | public function beginTransaction(): void 43 | { 44 | $this->wrappedConnection->beginTransaction(); 45 | } 46 | 47 | public function commit(): void 48 | { 49 | $this->wrappedConnection->commit(); 50 | } 51 | 52 | public function rollBack(): void 53 | { 54 | $this->wrappedConnection->rollBack(); 55 | } 56 | 57 | public function getServerVersion(): string 58 | { 59 | return $this->wrappedConnection->getServerVersion(); 60 | } 61 | 62 | /** 63 | * {@inheritDoc} 64 | */ 65 | public function getNativeConnection() 66 | { 67 | return $this->wrappedConnection->getNativeConnection(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Driver/Middleware/AbstractDriverMiddleware.php: -------------------------------------------------------------------------------- 1 | wrappedDriver->connect($params); 28 | } 29 | 30 | public function getDatabasePlatform(ServerVersionProvider $versionProvider): AbstractPlatform 31 | { 32 | return $this->wrappedDriver->getDatabasePlatform($versionProvider); 33 | } 34 | 35 | public function getExceptionConverter(): ExceptionConverter 36 | { 37 | return $this->wrappedDriver->getExceptionConverter(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Driver/Middleware/AbstractStatementMiddleware.php: -------------------------------------------------------------------------------- 1 | wrappedStatement->bindValue($param, $value, $type); 20 | } 21 | 22 | public function execute(): Result 23 | { 24 | return $this->wrappedStatement->execute(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Exception/ConnectionError.php: -------------------------------------------------------------------------------- 1 | error, $connection->sqlstate, $connection->errno); 18 | } 19 | 20 | public static function upcast(mysqli_sql_exception $exception): self 21 | { 22 | $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); 23 | 24 | return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Exception/ConnectionFailed.php: -------------------------------------------------------------------------------- 1 | connect_error; 20 | assert($error !== null); 21 | 22 | return new self($error, 'HY000', $connection->connect_errno); 23 | } 24 | 25 | public static function upcast(mysqli_sql_exception $exception): self 26 | { 27 | $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); 28 | 29 | return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php: -------------------------------------------------------------------------------- 1 | error), 21 | $connection->sqlstate, 22 | $connection->errno, 23 | ); 24 | } 25 | 26 | public static function upcast(mysqli_sql_exception $exception, string $charset): self 27 | { 28 | $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); 29 | 30 | return new self( 31 | sprintf('Failed to set charset "%s": %s', $charset, $exception->getMessage()), 32 | $p->getValue($exception), 33 | $exception->getCode(), 34 | $exception, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Exception/InvalidOption.php: -------------------------------------------------------------------------------- 1 | error, $statement->sqlstate, $statement->errno); 18 | } 19 | 20 | public static function upcast(mysqli_sql_exception $exception): self 21 | { 22 | $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); 23 | 24 | return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Initializer.php: -------------------------------------------------------------------------------- 1 | set_charset($this->charset); 22 | } catch (mysqli_sql_exception $e) { 23 | throw InvalidCharset::upcast($e, $this->charset); 24 | } 25 | 26 | if ($success) { 27 | return; 28 | } 29 | 30 | throw InvalidCharset::fromCharset($connection, $this->charset); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Initializer/Options.php: -------------------------------------------------------------------------------- 1 | $options */ 16 | public function __construct(private readonly array $options) 17 | { 18 | } 19 | 20 | public function initialize(mysqli $connection): void 21 | { 22 | foreach ($this->options as $option => $value) { 23 | if (! mysqli_options($connection, $option, $value)) { 24 | throw InvalidOption::fromOption($option, $value); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Driver/Mysqli/Initializer/Secure.php: -------------------------------------------------------------------------------- 1 | ssl_set($this->key, $this->cert, $this->ca, $this->capath, $this->cipher); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Driver/OCI8/ConvertPositionalToNamedPlaceholders.php: -------------------------------------------------------------------------------- 1 | ). 14 | * 15 | * Oracle does not support positional parameters, hence this method converts all 16 | * positional parameters into artificially named parameters. 17 | * 18 | * @internal This class is not covered by the backward compatibility promise 19 | */ 20 | final class ConvertPositionalToNamedPlaceholders implements Visitor 21 | { 22 | /** @var list */ 23 | private array $buffer = []; 24 | 25 | /** @var array */ 26 | private array $parameterMap = []; 27 | 28 | public function acceptOther(string $sql): void 29 | { 30 | $this->buffer[] = $sql; 31 | } 32 | 33 | public function acceptPositionalParameter(string $sql): void 34 | { 35 | $position = count($this->parameterMap) + 1; 36 | $param = ':param' . $position; 37 | 38 | $this->parameterMap[$position] = $param; 39 | 40 | $this->buffer[] = $param; 41 | } 42 | 43 | public function acceptNamedParameter(string $sql): void 44 | { 45 | $this->buffer[] = $sql; 46 | } 47 | 48 | public function getSQL(): string 49 | { 50 | return implode('', $this->buffer); 51 | } 52 | 53 | /** @return array */ 54 | public function getParameterMap(): array 55 | { 56 | return $this->parameterMap; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Driver/OCI8/Driver.php: -------------------------------------------------------------------------------- 1 | getEasyConnectString($params); 36 | 37 | $persistent = ! empty($params['persistent']); 38 | $exclusive = ! empty($params['driverOptions']['exclusive']); 39 | 40 | if ($persistent && $exclusive) { 41 | throw InvalidConfiguration::forPersistentAndExclusive(); 42 | } 43 | 44 | if ($persistent) { 45 | $connection = @oci_pconnect($username, $password, $connectionString, $charset, $sessionMode); 46 | } elseif ($exclusive) { 47 | $connection = @oci_new_connect($username, $password, $connectionString, $charset, $sessionMode); 48 | } else { 49 | $connection = @oci_connect($username, $password, $connectionString, $charset, $sessionMode); 50 | } 51 | 52 | if ($connection === false) { 53 | throw ConnectionFailed::new(); 54 | } 55 | 56 | return new Connection($connection); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Driver/OCI8/Exception/ConnectionFailed.php: -------------------------------------------------------------------------------- 1 | isAutoCommitEnabled = true; 19 | } 20 | 21 | public function disableAutoCommit(): void 22 | { 23 | $this->isAutoCommitEnabled = false; 24 | } 25 | 26 | public function isAutoCommitEnabled(): bool 27 | { 28 | return $this->isAutoCommitEnabled; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Driver/OCI8/Middleware/InitializeSession.php: -------------------------------------------------------------------------------- 1 | exec( 28 | 'ALTER SESSION SET' 29 | . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" 30 | . " NLS_TIME_FORMAT = 'HH24:MI:SS'" 31 | . " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" 32 | . " NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZH:TZM'" 33 | . " NLS_NUMERIC_CHARACTERS = '.,'", 34 | ); 35 | 36 | return $connection; 37 | } 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Driver/PDO/Exception.php: -------------------------------------------------------------------------------- 1 | errorInfo !== null) { 16 | [$sqlState, $code] = $exception->errorInfo; 17 | 18 | $code ??= 0; 19 | } else { 20 | $code = $exception->getCode(); 21 | $sqlState = null; 22 | } 23 | 24 | return new self($exception->getMessage(), $sqlState, $code, $exception); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Driver/PDO/Exception/InvalidConfiguration.php: -------------------------------------------------------------------------------- 1 | doConnect( 46 | $this->constructPdoDsn($params), 47 | $params['user'] ?? '', 48 | $params['password'] ?? '', 49 | $driverOptions, 50 | ); 51 | } catch (PDOException $exception) { 52 | throw Exception::new($exception); 53 | } 54 | 55 | return new Connection($pdo); 56 | } 57 | 58 | /** 59 | * Constructs the Oracle PDO DSN. 60 | * 61 | * @param mixed[] $params 62 | */ 63 | private function constructPdoDsn(array $params): string 64 | { 65 | $dsn = 'oci:dbname=' . $this->getEasyConnectString($params); 66 | 67 | if (isset($params['charset'])) { 68 | $dsn .= ';charset=' . $params['charset']; 69 | } 70 | 71 | return $dsn; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Driver/PDO/PDOConnect.php: -------------------------------------------------------------------------------- 1 | $options */ 15 | private function doConnect( 16 | string $dsn, 17 | string $username, 18 | string $password, 19 | array $options, 20 | ): PDO { 21 | if (PHP_VERSION_ID < 80400) { 22 | return new PDO($dsn, $username, $password, $options); 23 | } 24 | 25 | return PDO::connect($dsn, $username, $password, $options); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Driver/PDO/SQLSrv/Connection.php: -------------------------------------------------------------------------------- 1 | connection->prepare($sql), 22 | ); 23 | } 24 | 25 | public function getNativeConnection(): PDO 26 | { 27 | return $this->connection->getNativeConnection(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Driver/PDO/SQLSrv/Statement.php: -------------------------------------------------------------------------------- 1 | statement->bindParamWithDriverOptions( 26 | $param, 27 | $value, 28 | $type, 29 | PDO::SQLSRV_ENCODING_BINARY, 30 | ); 31 | break; 32 | 33 | case ParameterType::ASCII: 34 | $this->statement->bindParamWithDriverOptions( 35 | $param, 36 | $value, 37 | ParameterType::STRING, 38 | PDO::SQLSRV_ENCODING_SYSTEM, 39 | ); 40 | break; 41 | 42 | default: 43 | $this->statement->bindValue($param, $value, $type); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Driver/PDO/SQLite/Driver.php: -------------------------------------------------------------------------------- 1 | doConnect( 37 | $this->constructPdoDsn(array_intersect_key($params, ['path' => true, 'memory' => true])), 38 | $params['user'] ?? '', 39 | $params['password'] ?? '', 40 | $params['driverOptions'] ?? [], 41 | ); 42 | } catch (PDOException $exception) { 43 | throw Exception::new($exception); 44 | } 45 | 46 | return new Connection($pdo); 47 | } 48 | 49 | /** 50 | * Constructs the Sqlite PDO DSN. 51 | * 52 | * @param array $params 53 | */ 54 | private function constructPdoDsn(array $params): string 55 | { 56 | $dsn = 'sqlite:'; 57 | if (isset($params['path'])) { 58 | $dsn .= $params['path']; 59 | } elseif (isset($params['memory'])) { 60 | $dsn .= ':memory:'; 61 | } 62 | 63 | return $dsn; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Driver/PgSQL/ConvertParameters.php: -------------------------------------------------------------------------------- 1 | */ 15 | private array $buffer = []; 16 | 17 | /** @var array */ 18 | private array $parameterMap = []; 19 | 20 | public function acceptPositionalParameter(string $sql): void 21 | { 22 | $position = count($this->parameterMap) + 1; 23 | $this->parameterMap[$position] = $position; 24 | $this->buffer[] = '$' . $position; 25 | } 26 | 27 | public function acceptNamedParameter(string $sql): void 28 | { 29 | $position = count($this->parameterMap) + 1; 30 | $this->parameterMap[$sql] = $position; 31 | $this->buffer[] = '$' . $position; 32 | } 33 | 34 | public function acceptOther(string $sql): void 35 | { 36 | $this->buffer[] = $sql; 37 | } 38 | 39 | public function getSQL(): string 40 | { 41 | return implode('', $this->buffer); 42 | } 43 | 44 | /** @return array */ 45 | public function getParameterMap(): array 46 | { 47 | return $this->parameterMap; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Driver/PgSQL/Exception.php: -------------------------------------------------------------------------------- 1 | enableExceptions(true); 45 | 46 | return new Connection($connection); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Driver/SQLite3/Exception.php: -------------------------------------------------------------------------------- 1 | getMessage(), null, (int) $exception->getCode(), $exception); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Driver/SQLite3/Statement.php: -------------------------------------------------------------------------------- 1 | statement->bindValue($param, $value, $this->convertParamType($type)); 36 | } 37 | 38 | public function execute(): Result 39 | { 40 | try { 41 | $result = $this->statement->execute(); 42 | } catch (\Exception $e) { 43 | throw Exception::new($e); 44 | } 45 | 46 | assert($result !== false); 47 | 48 | return new Result($result, $this->connection->changes()); 49 | } 50 | 51 | /** @phpstan-return self::TYPE_* */ 52 | private function convertParamType(ParameterType $type): int 53 | { 54 | return match ($type) { 55 | ParameterType::NULL => self::TYPE_NULL, 56 | ParameterType::INTEGER, ParameterType::BOOLEAN => self::TYPE_INTEGER, 57 | ParameterType::STRING, ParameterType::ASCII => self::TYPE_TEXT, 58 | ParameterType::BINARY, ParameterType::LARGE_OBJECT => self::TYPE_BLOB, 59 | }; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Driver/Statement.php: -------------------------------------------------------------------------------- 1 | getMessage(); 28 | } else { 29 | $message = 'An exception occurred in the driver: ' . $driverException->getMessage(); 30 | } 31 | 32 | parent::__construct($message, $driverException->getCode(), $driverException); 33 | } 34 | 35 | public function getSQLState(): ?string 36 | { 37 | $previous = $this->getPrevious(); 38 | assert($previous instanceof Driver\Exception); 39 | 40 | return $previous->getSQLState(); 41 | } 42 | 43 | public function getQuery(): ?Query 44 | { 45 | return $this->query; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Exception/DriverRequired.php: -------------------------------------------------------------------------------- 1 | logger->info('Disconnecting'); 24 | } 25 | 26 | public function prepare(string $sql): DriverStatement 27 | { 28 | return new Statement( 29 | parent::prepare($sql), 30 | $this->logger, 31 | $sql, 32 | ); 33 | } 34 | 35 | public function query(string $sql): Result 36 | { 37 | $this->logger->debug('Executing query: {sql}', ['sql' => $sql]); 38 | 39 | return parent::query($sql); 40 | } 41 | 42 | public function exec(string $sql): int|string 43 | { 44 | $this->logger->debug('Executing statement: {sql}', ['sql' => $sql]); 45 | 46 | return parent::exec($sql); 47 | } 48 | 49 | public function beginTransaction(): void 50 | { 51 | $this->logger->debug('Beginning transaction'); 52 | 53 | parent::beginTransaction(); 54 | } 55 | 56 | public function commit(): void 57 | { 58 | $this->logger->debug('Committing transaction'); 59 | 60 | parent::commit(); 61 | } 62 | 63 | public function rollBack(): void 64 | { 65 | $this->logger->debug('Rolling back transaction'); 66 | 67 | parent::rollBack(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Logging/Driver.php: -------------------------------------------------------------------------------- 1 | logger->info('Connecting with parameters {params}', ['params' => $this->maskPassword($params)]); 28 | 29 | return new Connection( 30 | parent::connect($params), 31 | $this->logger, 32 | ); 33 | } 34 | 35 | /** 36 | * @param array $params Connection parameters 37 | * 38 | * @return array 39 | */ 40 | private function maskPassword( 41 | #[SensitiveParameter] 42 | array $params, 43 | ): array { 44 | if (isset($params['password'])) { 45 | $params['password'] = ''; 46 | } 47 | 48 | return $params; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Logging/Middleware.php: -------------------------------------------------------------------------------- 1 | logger); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Logging/Statement.php: -------------------------------------------------------------------------------- 1 | |array */ 16 | private array $params = []; 17 | 18 | /** @var array|array */ 19 | private array $types = []; 20 | 21 | /** @internal This statement can be only instantiated by its connection. */ 22 | public function __construct( 23 | StatementInterface $statement, 24 | private readonly LoggerInterface $logger, 25 | private readonly string $sql, 26 | ) { 27 | parent::__construct($statement); 28 | } 29 | 30 | public function bindValue(int|string $param, mixed $value, ParameterType $type): void 31 | { 32 | $this->params[$param] = $value; 33 | $this->types[$param] = $type; 34 | 35 | parent::bindValue($param, $value, $type); 36 | } 37 | 38 | public function execute(): ResultInterface 39 | { 40 | $this->logger->debug('Executing statement: {sql} (parameters: {params}, types: {types})', [ 41 | 'sql' => $this->sql, 42 | 'params' => $this->params, 43 | 'types' => $this->types, 44 | ]); 45 | 46 | return parent::execute(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/ParameterType.php: -------------------------------------------------------------------------------- 1 | keywords === null) { 25 | $this->initializeKeywords(); 26 | } 27 | 28 | return isset($this->keywords[strtoupper($word)]); 29 | } 30 | 31 | protected function initializeKeywords(): void 32 | { 33 | $this->keywords = array_flip(array_map('strtoupper', $this->getKeywords())); 34 | } 35 | 36 | /** 37 | * Returns the list of keywords. 38 | * 39 | * @return string[] 40 | */ 41 | abstract protected function getKeywords(): array; 42 | } 43 | -------------------------------------------------------------------------------- /src/Platforms/Keywords/MySQL80Keywords.php: -------------------------------------------------------------------------------- 1 | getQuotedName($this)]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Platforms/MariaDB1060Platform.php: -------------------------------------------------------------------------------- 1 | */ 15 | private array $cache = []; 16 | 17 | public function __construct(private readonly CharsetMetadataProvider $charsetMetadataProvider) 18 | { 19 | } 20 | 21 | public function getDefaultCharsetCollation(string $charset): ?string 22 | { 23 | if (array_key_exists($charset, $this->cache)) { 24 | return $this->cache[$charset]; 25 | } 26 | 27 | return $this->cache[$charset] = $this->charsetMetadataProvider->getDefaultCharsetCollation($charset); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Platforms/MySQL/CharsetMetadataProvider/ConnectionCharsetMetadataProvider.php: -------------------------------------------------------------------------------- 1 | connection->fetchOne( 22 | <<<'SQL' 23 | SELECT DEFAULT_COLLATE_NAME 24 | FROM information_schema.CHARACTER_SETS 25 | WHERE CHARACTER_SET_NAME = ?; 26 | SQL 27 | , 28 | [$charset], 29 | ); 30 | 31 | if ($collation !== false) { 32 | return $collation; 33 | } 34 | 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Platforms/MySQL/CollationMetadataProvider.php: -------------------------------------------------------------------------------- 1 | */ 15 | private array $cache = []; 16 | 17 | public function __construct(private readonly CollationMetadataProvider $collationMetadataProvider) 18 | { 19 | } 20 | 21 | public function getCollationCharset(string $collation): ?string 22 | { 23 | if (array_key_exists($collation, $this->cache)) { 24 | return $this->cache[$collation]; 25 | } 26 | 27 | return $this->cache[$collation] = $this->collationMetadataProvider->getCollationCharset($collation); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Platforms/MySQL/CollationMetadataProvider/ConnectionCollationMetadataProvider.php: -------------------------------------------------------------------------------- 1 | connection->fetchOne( 22 | <<<'SQL' 23 | SELECT CHARACTER_SET_NAME 24 | FROM information_schema.COLLATIONS 25 | WHERE COLLATION_NAME = ?; 26 | SQL 27 | , 28 | [$collation], 29 | ); 30 | 31 | if ($charset !== false) { 32 | return $charset; 33 | } 34 | 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Platforms/MySQL/DefaultTableOptions.php: -------------------------------------------------------------------------------- 1 | charset; 17 | } 18 | 19 | public function getCollation(): string 20 | { 21 | return $this->collation; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Platforms/MySQL80Platform.php: -------------------------------------------------------------------------------- 1 | getQuotedName($this)]; 43 | } 44 | 45 | protected function createReservedKeywordsList(): KeywordList 46 | { 47 | return new MySQLKeywords(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Platforms/PostgreSQL120Platform.php: -------------------------------------------------------------------------------- 1 | normalizeColumns($oldTable), 29 | $this->normalizeColumns($newTable), 30 | ); 31 | } 32 | 33 | private function normalizeColumns(Table $table): Table 34 | { 35 | $table = clone $table; 36 | 37 | foreach ($table->getColumns() as $column) { 38 | $options = $column->getPlatformOptions(); 39 | 40 | if (! isset($options['collation']) || $options['collation'] !== $this->databaseCollation) { 41 | continue; 42 | } 43 | 44 | unset($options['collation']); 45 | $column->setPlatformOptions($options); 46 | } 47 | 48 | return $table; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Platforms/SQLite/Comparator.php: -------------------------------------------------------------------------------- 1 | normalizeColumns($oldTable), 31 | $this->normalizeColumns($newTable), 32 | ); 33 | } 34 | 35 | private function normalizeColumns(Table $table): Table 36 | { 37 | $table = clone $table; 38 | 39 | foreach ($table->getColumns() as $column) { 40 | $options = $column->getPlatformOptions(); 41 | 42 | if (! isset($options['collation']) || strcasecmp($options['collation'], 'binary') !== 0) { 43 | continue; 44 | } 45 | 46 | unset($options['collation']); 47 | $column->setPlatformOptions($options); 48 | } 49 | 50 | return $table; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Platforms/TrimMode.php: -------------------------------------------------------------------------------- 1 | converter, 31 | ); 32 | } 33 | 34 | public function query(string $sql): Result 35 | { 36 | return new Result( 37 | parent::query($sql), 38 | $this->converter, 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Portability/Middleware.php: -------------------------------------------------------------------------------- 1 | mode !== 0) { 20 | return new Driver($driver, $this->mode, $this->case); 21 | } 22 | 23 | return $driver; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Portability/OptimizeFlags.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | private static array $platforms = [ 23 | DB2Platform::class => 0, 24 | OraclePlatform::class => Connection::PORTABILITY_EMPTY_TO_NULL, 25 | PostgreSQLPlatform::class => 0, 26 | SQLitePlatform::class => 0, 27 | SQLServerPlatform::class => 0, 28 | ]; 29 | 30 | public function __invoke(AbstractPlatform $platform, int $flags): int 31 | { 32 | foreach (self::$platforms as $class => $mask) { 33 | if ($platform instanceof $class) { 34 | $flags &= ~$mask; 35 | 36 | break; 37 | } 38 | } 39 | 40 | return $flags; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Portability/Result.php: -------------------------------------------------------------------------------- 1 | converter->convertNumeric( 21 | parent::fetchNumeric(), 22 | ); 23 | } 24 | 25 | public function fetchAssociative(): array|false 26 | { 27 | return $this->converter->convertAssociative( 28 | parent::fetchAssociative(), 29 | ); 30 | } 31 | 32 | public function fetchOne(): mixed 33 | { 34 | return $this->converter->convertOne( 35 | parent::fetchOne(), 36 | ); 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | public function fetchAllNumeric(): array 43 | { 44 | return $this->converter->convertAllNumeric( 45 | parent::fetchAllNumeric(), 46 | ); 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | public function fetchAllAssociative(): array 53 | { 54 | return $this->converter->convertAllAssociative( 55 | parent::fetchAllAssociative(), 56 | ); 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | public function fetchFirstColumn(): array 63 | { 64 | return $this->converter->convertFirstColumn( 65 | parent::fetchFirstColumn(), 66 | ); 67 | } 68 | 69 | public function getColumnName(int $index): string 70 | { 71 | return $this->converter->convertColumnName( 72 | parent::getColumnName($index), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Portability/Statement.php: -------------------------------------------------------------------------------- 1 | Statement and applies portability measures. 18 | */ 19 | public function __construct(DriverStatement $stmt, private readonly Converter $converter) 20 | { 21 | parent::__construct($stmt); 22 | } 23 | 24 | public function execute(): ResultInterface 25 | { 26 | return new Result( 27 | parent::execute(), 28 | $this->converter, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Query.php: -------------------------------------------------------------------------------- 1 | $params 16 | * @phpstan-param array $types 17 | */ 18 | public function __construct( 19 | private readonly string $sql, 20 | private readonly array $params, 21 | private readonly array $types, 22 | ) { 23 | } 24 | 25 | public function getSQL(): string 26 | { 27 | return $this->sql; 28 | } 29 | 30 | /** @return array */ 31 | public function getParams(): array 32 | { 33 | return $this->params; 34 | } 35 | 36 | /** @phpstan-return array */ 37 | public function getTypes(): array 38 | { 39 | return $this->types; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Query/Exception/NonUniqueAlias.php: -------------------------------------------------------------------------------- 1 | conflictResolutionMode; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Query/ForUpdate/ConflictResolutionMode.php: -------------------------------------------------------------------------------- 1 | maxResults !== null || $this->firstResult !== 0; 18 | } 19 | 20 | public function getMaxResults(): ?int 21 | { 22 | return $this->maxResults; 23 | } 24 | 25 | public function getFirstResult(): int 26 | { 27 | return $this->firstResult; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Query/QueryException.php: -------------------------------------------------------------------------------- 1 | distinct; 33 | } 34 | 35 | /** @return string[] */ 36 | public function getColumns(): array 37 | { 38 | return $this->columns; 39 | } 40 | 41 | /** @return string[] */ 42 | public function getFrom(): array 43 | { 44 | return $this->from; 45 | } 46 | 47 | public function getWhere(): ?string 48 | { 49 | return $this->where; 50 | } 51 | 52 | /** @return string[] */ 53 | public function getGroupBy(): array 54 | { 55 | return $this->groupBy; 56 | } 57 | 58 | public function getHaving(): ?string 59 | { 60 | return $this->having; 61 | } 62 | 63 | /** @return string[] */ 64 | public function getOrderBy(): array 65 | { 66 | return $this->orderBy; 67 | } 68 | 69 | public function getLimit(): Limit 70 | { 71 | return $this->limit; 72 | } 73 | 74 | public function getForUpdate(): ?ForUpdate 75 | { 76 | return $this->forUpdate; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Query/Union.php: -------------------------------------------------------------------------------- 1 | unionParts; 26 | } 27 | 28 | /** @return string[] */ 29 | public function getOrderBy(): array 30 | { 31 | return $this->orderBy; 32 | } 33 | 34 | public function getLimit(): Limit 35 | { 36 | return $this->limit; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Query/UnionType.php: -------------------------------------------------------------------------------- 1 | */ 21 | public function buildSQL(Schema $schema): array 22 | { 23 | return array_merge( 24 | $this->buildNamespaceStatements($schema->getNamespaces()), 25 | $this->buildSequenceStatements($schema->getSequences()), 26 | $this->buildTableStatements($schema->getTables()), 27 | ); 28 | } 29 | 30 | /** 31 | * @param string[] $namespaces 32 | * 33 | * @return list 34 | */ 35 | private function buildNamespaceStatements(array $namespaces): array 36 | { 37 | $statements = []; 38 | 39 | if ($this->platform->supportsSchemas()) { 40 | foreach ($namespaces as $namespace) { 41 | $statements[] = $this->platform->getCreateSchemaSQL($namespace); 42 | } 43 | } 44 | 45 | return $statements; 46 | } 47 | 48 | /** 49 | * @param Table[] $tables 50 | * 51 | * @return list 52 | */ 53 | private function buildTableStatements(array $tables): array 54 | { 55 | return $this->platform->getCreateTablesSQL($tables); 56 | } 57 | 58 | /** 59 | * @param Sequence[] $sequences 60 | * 61 | * @return list 62 | */ 63 | private function buildSequenceStatements(array $sequences): array 64 | { 65 | $statements = []; 66 | 67 | foreach ($sequences as $sequence) { 68 | $statements[] = $this->platform->getCreateSequenceSQL($sequence); 69 | } 70 | 71 | return $statements; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/SQL/Builder/DefaultUnionSQLBuilder.php: -------------------------------------------------------------------------------- 1 | getUnionParts() as $union) { 25 | if ($union->type !== null) { 26 | $parts[] = $union->type === UnionType::ALL 27 | ? $this->platform->getUnionAllSQL() 28 | : $this->platform->getUnionDistinctSQL(); 29 | } 30 | 31 | $parts[] = $this->platform->getUnionSelectPartSQL((string) $union->query); 32 | } 33 | 34 | $orderBy = $query->getOrderBy(); 35 | if (count($orderBy) > 0) { 36 | $parts[] = 'ORDER BY ' . implode(', ', $orderBy); 37 | } 38 | 39 | $sql = implode(' ', $parts); 40 | $limit = $query->getLimit(); 41 | 42 | if ($limit->isDefined()) { 43 | $sql = $this->platform->modifyLimitQuery($sql, $limit->getMaxResults(), $limit->getFirstResult()); 44 | } 45 | 46 | return $sql; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/SQL/Builder/DropSchemaObjectsSQLBuilder.php: -------------------------------------------------------------------------------- 1 | */ 21 | public function buildSQL(Schema $schema): array 22 | { 23 | return array_merge( 24 | $this->buildSequenceStatements($schema->getSequences()), 25 | $this->buildTableStatements($schema->getTables()), 26 | ); 27 | } 28 | 29 | /** 30 | * @param list $tables 31 | * 32 | * @return list 33 | */ 34 | private function buildTableStatements(array $tables): array 35 | { 36 | return $this->platform->getDropTablesSQL($tables); 37 | } 38 | 39 | /** 40 | * @param list $sequences 41 | * 42 | * @return list 43 | */ 44 | private function buildSequenceStatements(array $sequences): array 45 | { 46 | $statements = []; 47 | 48 | foreach ($sequences as $sequence) { 49 | $statements[] = $this->platform->getDropSequenceSQL($sequence->getQuotedName($this->platform)); 50 | } 51 | 52 | return $statements; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/SQL/Builder/SelectSQLBuilder.php: -------------------------------------------------------------------------------- 1 | getDatabasePlatform()->createSchemaManager($connection); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Schema/Exception/ColumnAlreadyExists.php: -------------------------------------------------------------------------------- 1 | _setName($identifier); 22 | 23 | if (! $quote || $this->_quoted) { 24 | return; 25 | } 26 | 27 | $this->_setName('"' . $this->getName() . '"'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Schema/SchemaConfig.php: -------------------------------------------------------------------------------- 1 | */ 17 | protected array $defaultTableOptions = []; 18 | 19 | public function setMaxIdentifierLength(int $length): void 20 | { 21 | $this->maxIdentifierLength = $length; 22 | } 23 | 24 | public function getMaxIdentifierLength(): int 25 | { 26 | return $this->maxIdentifierLength; 27 | } 28 | 29 | /** 30 | * Gets the default namespace of schema objects. 31 | */ 32 | public function getName(): ?string 33 | { 34 | return $this->name; 35 | } 36 | 37 | /** 38 | * Sets the default namespace name of schema objects. 39 | */ 40 | public function setName(?string $name): void 41 | { 42 | $this->name = $name; 43 | } 44 | 45 | /** 46 | * Gets the default options that are passed to Table instances created with 47 | * Schema#createTable(). 48 | * 49 | * @return array 50 | */ 51 | public function getDefaultTableOptions(): array 52 | { 53 | return $this->defaultTableOptions; 54 | } 55 | 56 | /** @param array $defaultTableOptions */ 57 | public function setDefaultTableOptions(array $defaultTableOptions): void 58 | { 59 | $this->defaultTableOptions = $defaultTableOptions; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Schema/SchemaException.php: -------------------------------------------------------------------------------- 1 | _setName($name); 15 | } 16 | 17 | public function getSql(): string 18 | { 19 | return $this->sql; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ServerVersionProvider.php: -------------------------------------------------------------------------------- 1 | connection; 24 | } 25 | 26 | public function getConnection(string $name): Connection 27 | { 28 | if ($name !== $this->defaultConnectionName) { 29 | throw new ConnectionNotFound(sprintf('Connection with name "%s" does not exist.', $name)); 30 | } 31 | 32 | return $this->connection; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/TransactionIsolationLevel.php: -------------------------------------------------------------------------------- 1 | getAsciiStringTypeDeclarationSQL($column); 18 | } 19 | 20 | public function getBindingType(): ParameterType 21 | { 22 | return ParameterType::ASCII; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Types/BigIntType.php: -------------------------------------------------------------------------------- 1 | getBigIntTypeDeclarationSQL($column); 30 | } 31 | 32 | public function getBindingType(): ParameterType 33 | { 34 | return ParameterType::STRING; 35 | } 36 | 37 | /** 38 | * @param T $value 39 | * 40 | * @return (T is null ? null : int|string) 41 | * 42 | * @template T 43 | */ 44 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): int|string|null 45 | { 46 | if ($value === null || is_int($value)) { 47 | return $value; 48 | } 49 | 50 | assert( 51 | is_string($value), 52 | 'DBAL assumes values outside of the integer range to be returned as string by the database driver.', 53 | ); 54 | 55 | if ( 56 | ($value > PHP_INT_MIN && $value < PHP_INT_MAX) 57 | || $value === (string) (int) $value 58 | ) { 59 | return (int) $value; 60 | } 61 | 62 | return $value; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Types/BinaryType.php: -------------------------------------------------------------------------------- 1 | getBinaryTypeDeclarationSQL($column); 26 | } 27 | 28 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?string 29 | { 30 | if ($value === null) { 31 | return null; 32 | } 33 | 34 | if (is_resource($value)) { 35 | $value = stream_get_contents($value); 36 | } 37 | 38 | if (! is_string($value)) { 39 | throw ValueNotConvertible::new($value, Types::BINARY); 40 | } 41 | 42 | return $value; 43 | } 44 | 45 | public function getBindingType(): ParameterType 46 | { 47 | return ParameterType::BINARY; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Types/BlobType.php: -------------------------------------------------------------------------------- 1 | getBlobTypeDeclarationSQL($column); 29 | } 30 | 31 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed 32 | { 33 | if ($value === null) { 34 | return null; 35 | } 36 | 37 | if (is_string($value)) { 38 | $fp = fopen('php://temp', 'rb+'); 39 | assert(is_resource($fp)); 40 | fwrite($fp, $value); 41 | fseek($fp, 0); 42 | $value = $fp; 43 | } 44 | 45 | if (! is_resource($value)) { 46 | throw ValueNotConvertible::new($value, Types::BLOB); 47 | } 48 | 49 | return $value; 50 | } 51 | 52 | public function getBindingType(): ParameterType 53 | { 54 | return ParameterType::LARGE_OBJECT; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Types/BooleanType.php: -------------------------------------------------------------------------------- 1 | getBooleanTypeDeclarationSQL($column); 21 | } 22 | 23 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed 24 | { 25 | return $platform->convertBooleansToDatabaseValue($value); 26 | } 27 | 28 | /** 29 | * @param T $value 30 | * 31 | * @return (T is null ? null : bool) 32 | * 33 | * @template T 34 | */ 35 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?bool 36 | { 37 | return $platform->convertFromBoolean($value); 38 | } 39 | 40 | public function getBindingType(): ParameterType 41 | { 42 | return ParameterType::BOOLEAN; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Types/ConversionException.php: -------------------------------------------------------------------------------- 1 | getDateTypeDeclarationSQL($column); 23 | } 24 | 25 | /** 26 | * @param T $value 27 | * 28 | * @return (T is null ? null : string) 29 | * 30 | * @template T 31 | */ 32 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string 33 | { 34 | if ($value === null) { 35 | return $value; 36 | } 37 | 38 | if ($value instanceof DateTimeImmutable) { 39 | return $value->format($platform->getDateFormatString()); 40 | } 41 | 42 | throw InvalidType::new( 43 | $value, 44 | static::class, 45 | ['null', DateTimeImmutable::class], 46 | ); 47 | } 48 | 49 | /** 50 | * @param T $value 51 | * 52 | * @return (T is null ? null : DateTimeImmutable) 53 | * 54 | * @template T 55 | */ 56 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTimeImmutable 57 | { 58 | if ($value === null || $value instanceof DateTimeImmutable) { 59 | return $value; 60 | } 61 | 62 | $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getDateFormatString(), $value); 63 | 64 | if ($dateTime === false) { 65 | throw InvalidFormat::new( 66 | $value, 67 | static::class, 68 | $platform->getDateFormatString(), 69 | ); 70 | } 71 | 72 | return $dateTime; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Types/DateType.php: -------------------------------------------------------------------------------- 1 | getDateTypeDeclarationSQL($column); 23 | } 24 | 25 | /** 26 | * @phpstan-param T $value 27 | * 28 | * @return (T is null ? null : string) 29 | * 30 | * @template T 31 | */ 32 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed 33 | { 34 | if ($value === null) { 35 | return $value; 36 | } 37 | 38 | if ($value instanceof DateTime) { 39 | return $value->format($platform->getDateFormatString()); 40 | } 41 | 42 | throw InvalidType::new($value, static::class, ['null', DateTime::class]); 43 | } 44 | 45 | /** 46 | * @param T $value 47 | * 48 | * @return (T is null ? null : DateTime) 49 | * 50 | * @template T 51 | */ 52 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTime 53 | { 54 | if ($value === null || $value instanceof DateTime) { 55 | return $value; 56 | } 57 | 58 | $dateTime = DateTime::createFromFormat('!' . $platform->getDateFormatString(), $value); 59 | if ($dateTime !== false) { 60 | return $dateTime; 61 | } 62 | 63 | throw InvalidFormat::new( 64 | $value, 65 | static::class, 66 | $platform->getDateFormatString(), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Types/DecimalType.php: -------------------------------------------------------------------------------- 1 | getDecimalTypeDeclarationSQL($column); 23 | } 24 | 25 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?string 26 | { 27 | // Some drivers can represent decimals as float/int 28 | // See also: https://github.com/doctrine/dbal/pull/4818 29 | if (is_float($value) || is_int($value)) { 30 | return (string) $value; 31 | } 32 | 33 | return $value; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Types/EnumType.php: -------------------------------------------------------------------------------- 1 | getEnumDeclarationSQL($column); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Types/Exception/InvalidFormat.php: -------------------------------------------------------------------------------- 1 | 32 ? substr($value, 0, 20) . '...' : $value, 30 | $toType, 31 | $expectedFormat ?? '', 32 | ), 33 | 0, 34 | $previous, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Types/Exception/InvalidType.php: -------------------------------------------------------------------------------- 1 | 32 ? substr($value, 0, 20) . '...' : $value, 36 | $toType, 37 | ); 38 | } 39 | 40 | return new self($message, 0, $previous); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Types/FloatType.php: -------------------------------------------------------------------------------- 1 | getFloatDeclarationSQL($column); 17 | } 18 | 19 | /** 20 | * @param T $value 21 | * 22 | * @return (T is null ? null : float) 23 | * 24 | * @template T 25 | */ 26 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?float 27 | { 28 | return $value === null ? null : (float) $value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Types/GuidType.php: -------------------------------------------------------------------------------- 1 | getGuidTypeDeclarationSQL($column); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Types/IntegerType.php: -------------------------------------------------------------------------------- 1 | getIntegerTypeDeclarationSQL($column); 21 | } 22 | 23 | /** 24 | * @param T $value 25 | * 26 | * @return (T is null ? null : int) 27 | * 28 | * @template T 29 | */ 30 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?int 31 | { 32 | return $value === null ? null : (int) $value; 33 | } 34 | 35 | public function getBindingType(): ParameterType 36 | { 37 | return ParameterType::INTEGER; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Types/JsonType.php: -------------------------------------------------------------------------------- 1 | getJsonTypeDeclarationSQL($column); 31 | } 32 | 33 | /** 34 | * @param T $value 35 | * 36 | * @return (T is null ? null : string) 37 | * 38 | * @template T 39 | */ 40 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string 41 | { 42 | if ($value === null) { 43 | return null; 44 | } 45 | 46 | try { 47 | return json_encode($value, JSON_THROW_ON_ERROR | JSON_PRESERVE_ZERO_FRACTION); 48 | } catch (JsonException $e) { 49 | throw SerializationFailed::new($value, 'json', $e->getMessage(), $e); 50 | } 51 | } 52 | 53 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed 54 | { 55 | if ($value === null || $value === '') { 56 | return null; 57 | } 58 | 59 | if (is_resource($value)) { 60 | $value = stream_get_contents($value); 61 | } 62 | 63 | try { 64 | return json_decode($value, true, 512, JSON_THROW_ON_ERROR); 65 | } catch (JsonException $e) { 66 | throw ValueNotConvertible::new($value, 'json', $e->getMessage(), $e); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Types/PhpDateMappingType.php: -------------------------------------------------------------------------------- 1 | getClobTypeDeclarationSQL($column); 29 | } 30 | 31 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string 32 | { 33 | if (! is_array($value) || count($value) === 0) { 34 | return null; 35 | } 36 | 37 | return implode(',', $value); 38 | } 39 | 40 | /** @return list */ 41 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): array 42 | { 43 | if ($value === null) { 44 | return []; 45 | } 46 | 47 | $value = is_resource($value) ? stream_get_contents($value) : $value; 48 | 49 | return explode(',', $value); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Types/SmallFloatType.php: -------------------------------------------------------------------------------- 1 | getSmallFloatDeclarationSQL($column); 17 | } 18 | 19 | /** 20 | * @param T $value 21 | * 22 | * @return (T is null ? null : float) 23 | * 24 | * @template T 25 | */ 26 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?float 27 | { 28 | return $value === null ? null : (float) $value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Types/SmallIntType.php: -------------------------------------------------------------------------------- 1 | getSmallIntTypeDeclarationSQL($column); 21 | } 22 | 23 | /** 24 | * @param T $value 25 | * 26 | * @return (T is null ? null : int) 27 | * 28 | * @template T 29 | */ 30 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?int 31 | { 32 | return $value === null ? null : (int) $value; 33 | } 34 | 35 | public function getBindingType(): ParameterType 36 | { 37 | return ParameterType::INTEGER; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Types/StringType.php: -------------------------------------------------------------------------------- 1 | getStringTypeDeclarationSQL($column); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Types/TextType.php: -------------------------------------------------------------------------------- 1 | getClobTypeDeclarationSQL($column); 23 | } 24 | 25 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed 26 | { 27 | return is_resource($value) ? stream_get_contents($value) : $value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Types/TimeImmutableType.php: -------------------------------------------------------------------------------- 1 | getTimeTypeDeclarationSQL($column); 23 | } 24 | 25 | /** 26 | * @param T $value 27 | * 28 | * @return (T is null ? null : string) 29 | * 30 | * @template T 31 | */ 32 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string 33 | { 34 | if ($value === null) { 35 | return $value; 36 | } 37 | 38 | if ($value instanceof DateTimeImmutable) { 39 | return $value->format($platform->getTimeFormatString()); 40 | } 41 | 42 | throw InvalidType::new( 43 | $value, 44 | static::class, 45 | ['null', DateTimeImmutable::class], 46 | ); 47 | } 48 | 49 | /** 50 | * @param T $value 51 | * 52 | * @return (T is null ? null : DateTimeImmutable) 53 | * 54 | * @template T 55 | */ 56 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTimeImmutable 57 | { 58 | if ($value === null || $value instanceof DateTimeImmutable) { 59 | return $value; 60 | } 61 | 62 | $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getTimeFormatString(), $value); 63 | 64 | if ($dateTime !== false) { 65 | return $dateTime; 66 | } 67 | 68 | throw InvalidFormat::new( 69 | $value, 70 | static::class, 71 | $platform->getTimeFormatString(), 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Types/TimeType.php: -------------------------------------------------------------------------------- 1 | getTimeTypeDeclarationSQL($column); 23 | } 24 | 25 | /** 26 | * @param T $value 27 | * 28 | * @return (T is null ? null : string) 29 | * 30 | * @template T 31 | */ 32 | public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string 33 | { 34 | if ($value === null) { 35 | return $value; 36 | } 37 | 38 | if ($value instanceof DateTime) { 39 | return $value->format($platform->getTimeFormatString()); 40 | } 41 | 42 | throw InvalidType::new($value, static::class, ['null', DateTime::class]); 43 | } 44 | 45 | /** 46 | * @param T $value 47 | * 48 | * @return (T is null ? null : DateTime) 49 | * 50 | * @template T 51 | */ 52 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTime 53 | { 54 | if ($value === null || $value instanceof DateTime) { 55 | return $value; 56 | } 57 | 58 | $dateTime = DateTime::createFromFormat('!' . $platform->getTimeFormatString(), $value); 59 | if ($dateTime !== false) { 60 | return $dateTime; 61 | } 62 | 63 | throw InvalidFormat::new( 64 | $value, 65 | static::class, 66 | $platform->getTimeFormatString(), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Types/Types.php: -------------------------------------------------------------------------------- 1 | format($platform->getDateTimeFormatString()); 33 | } 34 | 35 | throw InvalidType::new( 36 | $value, 37 | static::class, 38 | ['null', DateTimeImmutable::class], 39 | ); 40 | } 41 | 42 | /** 43 | * @param T $value 44 | * 45 | * @return (T is null ? null : DateTimeImmutable) 46 | * 47 | * @template T 48 | */ 49 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTimeImmutable 50 | { 51 | if ($value === null || $value instanceof DateTimeImmutable) { 52 | return $value; 53 | } 54 | 55 | try { 56 | $dateTime = new DateTimeImmutable($value); 57 | } catch (Exception $e) { 58 | throw ValueNotConvertible::new($value, DateTimeImmutable::class, $e->getMessage(), $e); 59 | } 60 | 61 | return $dateTime; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Types/VarDateTimeType.php: -------------------------------------------------------------------------------- 1 | 0 it is necessary to use this type. 18 | */ 19 | class VarDateTimeType extends DateTimeType 20 | { 21 | /** 22 | * @param T $value 23 | * 24 | * @return (T is null ? null : DateTime) 25 | * 26 | * @template T 27 | */ 28 | public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DateTime 29 | { 30 | if ($value === null || $value instanceof DateTime) { 31 | return $value; 32 | } 33 | 34 | try { 35 | $dateTime = new DateTime($value); 36 | } catch (Exception $e) { 37 | throw ValueNotConvertible::new($value, DateTime::class, $e->getMessage(), $e); 38 | } 39 | 40 | return $dateTime; 41 | } 42 | } 43 | --------------------------------------------------------------------------------