Skip to content

Instantly share code, notes, and snippets.

@m1ndgr3p
Last active November 11, 2022 01:35
Show Gist options
  • Save m1ndgr3p/6ab638319b53beebe76c92099a515d93 to your computer and use it in GitHub Desktop.
Save m1ndgr3p/6ab638319b53beebe76c92099a515d93 to your computer and use it in GitHub Desktop.
custom connection to guess uuid_binary_ordered_time
<?php
declare(strict_types=1);
namespace Acme\Resources\Doctrine\Connection;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ExpandArrayParameters;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Result;
use Doctrine\DBAL\Types\Type;
use Doctrine\Deprecations\Deprecation;
use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType;
use Ramsey\Uuid\UuidInterface;
final class CustomConnection extends \Doctrine\DBAL\Connection
{
public function executeQuery(
string $sql,
array $params = [],
$types = [],
?QueryCacheProfile $qcp = null
): Result
{
if ($qcp !== null) {
return $this->executeCacheQuery($sql, $params, $types, $qcp);
}
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($logger !== null) {
$logger->startQuery($sql, $params, $types);
}
try {
if (count($params) > 0) {
if ($this->needsArrayParameterConversion($params, $types)) {
[$sql, $params, $types] = $this->expandArrayParameters($sql, $params, $types);
}
$stmt = $connection->prepare($sql);
$this->bindParameters($stmt, $params, $types);
$result = $stmt->execute();
} else {
$result = $connection->query($sql);
}
return new Result($result, $this);
} catch (Exception $e) {
throw $this->convertExceptionDuringQuery($e, $sql, $params, $types);
} finally {
if ($logger !== null) {
$logger->stopQuery();
}
}
}
private function expandArrayParameters(string $sql, array $params, array $types): array
{
$this->parser ??= $this->getDatabasePlatform()->createSQLParser();
$visitor = new ExpandArrayParameters($params, $types);
$this->parser->parse($sql, $visitor);
return [
$visitor->getSQL(),
$visitor->getParameters(),
$visitor->getTypes(),
];
}
private function needsArrayParameterConversion(array $params, array $types): bool
{
if (is_string(key($params))) {
return true;
}
foreach ($types as $type) {
if (
$type === self::PARAM_INT_ARRAY
|| $type === self::PARAM_STR_ARRAY
|| $type === self::PARAM_ASCII_STR_ARRAY
) {
return true;
}
}
return false;
}
private function bindParameters(Statement $stmt, array $params, array $types): void
{
// Check whether parameters are positional or named. Mixing is not allowed.
if (is_int(key($params))) {
$bindIndex = 1;
foreach ($params as $key => $value) {
if (isset($types[$key])) {
$type = $types[$key];
[$value, $bindingType] = $this->getBindingInfo($value, $type);
} else {
if (array_key_exists($key, $types)) {
Deprecation::trigger(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/5550',
'Using NULL as prepared statement parameter type is deprecated.'
. 'Omit or use Parameter::STRING instead',
);
}
$bindingType = ParameterType::STRING;
}
$stmt->bindValue($bindIndex, $value, $bindingType);
++$bindIndex;
}
} else {
// Named parameters
foreach ($params as $name => $value) {
if (isset($types[$name])) {
$type = $types[$name];
[$value, $bindingType] = $this->getBindingInfo($value, $type);
} else {
if (array_key_exists($name, $types)) {
Deprecation::trigger(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/5550',
'Using NULL as prepared statement parameter type is deprecated.'
. 'Omit or use Parameter::STRING instead',
);
}
$bindingType = ParameterType::STRING;
}
$stmt->bindValue($name, $value, $bindingType);
}
}
}
private function getBindingInfo($value, $type): array
{
if (is_string($type)) {
$type = Type::getType($type);
} elseif (is_string($value) && $type !== UuidBinaryOrderedTimeType::NAME && \preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-[1][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $value) === 1) {
$type = Type::getType(UuidBinaryOrderedTimeType::NAME);
} elseif ($value instanceof UuidInterface) {
$type = Type::getType(UuidBinaryOrderedTimeType::NAME);
}
if ($type instanceof Type) {
$value = $type->convertToDatabaseValue($value, $this->getDatabasePlatform());
$bindingType = $type->getBindingType();
} else {
$bindingType = $type ?? ParameterType::STRING;
}
return [$value, $bindingType];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment