Skip to content

Instantly share code, notes, and snippets.

@faizanakram99
Created January 20, 2024 00:15
Show Gist options
  • Save faizanakram99/9826afd3ae8835fa291e25f78856305d to your computer and use it in GitHub Desktop.
Save faizanakram99/9826afd3ae8835fa291e25f78856305d to your computer and use it in GitHub Desktop.
DBAL results to object hydrator
<?php
declare(strict_types=1);
namespace HakunaMatata;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\DBAL\Types\Type;
interface QueryHydrator
{
/**
* Prepares and executes an SQL query and return the first row of the result as a hydrated object of class $hydrationClass.
*
* @template T of object
*
* @param string|QueryBuilder $query SQL query
* @param class-string<T> $hydrationClass
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return T|null Null is returned if now rows are found
*
* @throws Exception
*/
public function fetchOne(string|QueryBuilder $query, string $hydrationClass, array $params = [], array $types = []): ?object;
/**
* Prepares and executes an SQL query and returns all the rows of the result as an array of hydrated objects of class $hydrationClass.
*
* @template T of object
*
* @param string|QueryBuilder $query SQL query
* @param class-string<T> $hydrationClass The class to use for the result
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return array<array-key, T>
*
* @throws Exception
*/
public function fetchAll(string|QueryBuilder $query, string $hydrationClass, array $params = [], array $types = []): array;
}
<?php
declare(strict_types=1);
namespace HakunaMatata;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
final class SqlQueryHydrator implements QueryHydrator
{
public function __construct(
private Connection $doctrineConnection,
private DenormalizerInterface $objectHydrator,
) {
}
public function fetchOne(
string|QueryBuilder $query,
string $hydrationClass,
array $params = [],
array $types = [],
): ?object {
['sql' => $sql, 'params' => $params] = $this->prepareSql($query, $params);
$result = $this->doctrineConnection->fetchAssociative($sql, $params, $types);
if (false === $result) {
return null;
}
return $this->objectHydrator->denormalize(
$result,
$hydrationClass,
null,
[
AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true,
],
);
}
public function fetchAll(
string|QueryBuilder $query,
string $hydrationClass,
array $params = [],
array $types = [],
): array {
['sql' => $sql, 'params' => $params] = $this->prepareSql($query, $params);
$result = $this->doctrineConnection->fetchAllAssociative($sql, $params, $types);
return $this->objectHydrator->denormalize(
$result,
"{$hydrationClass}[]",
null,
[
AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true,
],
);
}
/**
* @param string|QueryBuilder $query
* @param array<int, mixed>|array<string, mixed> $params
*
* @return array{sql: string, params: array<int, mixed>|array<string, mixed>}
*/
private function prepareSql($query, array $params): array
{
if ($query instanceof QueryBuilder) {
$params = \array_merge($params, $query->getParameters());
$sql = $query->getSQL();
} else {
$sql = $query;
}
return [
'sql' => $sql,
'params' => $params,
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment