Last active
November 11, 2022 01:35
-
-
Save m1ndgr3p/6ab638319b53beebe76c92099a515d93 to your computer and use it in GitHub Desktop.
custom connection to guess uuid_binary_ordered_time
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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