diff --git a/src/Mouf/Database/QueryWriter/CountNbResult.php b/src/Mouf/Database/QueryWriter/CountNbResult.php index 0de2238..e31cde6 100644 --- a/src/Mouf/Database/QueryWriter/CountNbResult.php +++ b/src/Mouf/Database/QueryWriter/CountNbResult.php @@ -50,6 +50,10 @@ public function val() { $sql = 'SELECT count(*) as cnt FROM ('.$this->queryResult->toSql().') tmp'; - return $this->connection->fetchColumn($sql); + return $this->connection->fetchOne( + $sql, + $this->queryResult->getParametersForBind(), + $this->queryResult->getParameterTypesForBind(), + ); } } diff --git a/src/Mouf/Database/QueryWriter/QueryResult.php b/src/Mouf/Database/QueryWriter/QueryResult.php index d0287b3..592ddbe 100644 --- a/src/Mouf/Database/QueryWriter/QueryResult.php +++ b/src/Mouf/Database/QueryWriter/QueryResult.php @@ -2,6 +2,8 @@ namespace Mouf\Database\QueryWriter; +use Doctrine\DBAL\Types\Type; +use SQLParser\SqlRenderInterface; use function method_exists; use Mouf\Database\QueryWriter\Utils\DbHelper; use Mouf\Utils\Value\ValueUtils; @@ -48,25 +50,49 @@ class QueryResult implements ArrayValueInterface, PaginableInterface, SortableIn private $offset; /** @var int|null */ private $limit; + private int $conditionsMode; + private bool $extrapolateParameters; + /** + * @var Type[]|int[]|string[] + */ + private array $parameterTypes = []; /** * @param Select $select * @param Connection $connection + * @param int $conditionsMode + * @param bool $extrapolateParameters */ - public function __construct(Select $select, Connection $connection) - { + public function __construct( + Select $select, + Connection $connection, + int $conditionsMode = SqlRenderInterface::CONDITION_APPLY, + bool $extrapolateParameters = true + ) { $this->select = $select; $this->connection = $connection; + $this->conditionsMode = $conditionsMode; + $this->extrapolateParameters = $extrapolateParameters; } /** * The list of parameters to apply to the SQL request. * * @param array|array|ArrayValueInterface $parameters + * @param Type[]|string[]|int[] $types Parameter types */ - public function setParameters($parameters): void + public function setParameters($parameters, array $types = []): void { $this->parameters = $parameters; + $this->parameterTypes = $types; + } + + /** + * @return array|array|ArrayValueInterface + */ + public function getParameters(): array + { + return $this->parameters; } /** @@ -76,8 +102,8 @@ public function setParameters($parameters): void */ public function val() { - $parameters = ValueUtils::val($this->parameters); - $pdoStatement = $this->connection->query($this->select->toSql($parameters, $this->connection->getDatabasePlatform()).DbHelper::getFromLimitString($this->offset, $this->limit)); + $sql = $this->toSql().DbHelper::getFromLimitString($this->offset, $this->limit); + $pdoStatement = $this->connection->executeQuery($sql, $this->getParametersForBind(), $this->getParameterTypesForBind()); return new ResultSet($pdoStatement); } @@ -91,7 +117,23 @@ public function toSql() { $parameters = ValueUtils::val($this->parameters); - return $this->select->toSql($parameters, $this->connection->getDatabasePlatform()); + return $this->select->toSql( + $parameters, + $this->connection->getDatabasePlatform(), + 0, + $this->conditionsMode, + $this->extrapolateParameters + ); + } + + public function getParametersForBind(): array + { + return $this->extrapolateParameters ? [] : $this->parameters; + } + + public function getParameterTypesForBind(): array + { + return $this->extrapolateParameters ? [] : array_intersect_key($this->parameterTypes, $this->parameters); } /** diff --git a/src/Mouf/Database/QueryWriter/ResultSet.php b/src/Mouf/Database/QueryWriter/ResultSet.php index 5cffdec..d22f514 100644 --- a/src/Mouf/Database/QueryWriter/ResultSet.php +++ b/src/Mouf/Database/QueryWriter/ResultSet.php @@ -3,7 +3,7 @@ namespace Mouf\Database\QueryWriter; use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\Driver\Statement; +use Doctrine\DBAL\Result; /** * Wraps the results of a PDOStatement. @@ -12,7 +12,7 @@ */ class ResultSet implements \Iterator { - /** @var Statement */ + /** @var Result */ private $statement; /** @var int */ private $key = 0; @@ -23,12 +23,12 @@ class ResultSet implements \Iterator /** @var int */ private $rewindCalls = 0; - public function __construct(Statement $statement) + public function __construct(Result $statement) { $this->statement = $statement; } - public function rewind() + public function rewind(): void { ++$this->rewindCalls; if ($this->rewindCalls == 2) { @@ -39,7 +39,7 @@ public function rewind() /** * @return array|false */ - public function current() + public function current(): mixed { if (!$this->fetched) { $this->fetch(); @@ -51,12 +51,12 @@ public function current() /** * @return int */ - public function key() + public function key(): mixed { return $this->key; } - public function next() + public function next(): void { ++$this->key; $this->fetched = false; @@ -65,11 +65,11 @@ public function next() private function fetch(): void { - $this->result = $this->statement->fetch(FetchMode::ASSOCIATIVE); + $this->result = $this->statement->fetchAssociative(); $this->fetched = true; } - public function valid() + public function valid(): bool { if (!$this->fetched) { $this->fetch(); diff --git a/src/SQLParser/Node/NodeFactory.php b/src/SQLParser/Node/NodeFactory.php index 54df8f9..c7c4aff 100644 --- a/src/SQLParser/Node/NodeFactory.php +++ b/src/SQLParser/Node/NodeFactory.php @@ -150,38 +150,7 @@ public static function toObject(array $desc) $expr->setTable($desc['table']); } - - - $expr->setTable(str_replace('`', '', $desc['table'])); - switch ($desc['join_type']) { - case 'CROSS': - $joinType = 'CROSS JOIN'; - break; - case 'JOIN': - $joinType = 'JOIN'; - break; - case 'LEFT': - $joinType = 'LEFT JOIN'; - break; - case 'RIGHT': - $joinType = 'RIGHT JOIN'; - break; - case 'INNER': - $joinType = 'INNER JOIN'; - break; - case 'OUTER': - $joinType = 'OUTER JOIN'; - break; - case 'NATURAL': - $joinType = 'NATURAL JOIN'; - break; - case ',': - $joinType = ','; - break; - default: - throw new \Exception("Unexpected join type: '".$desc['join_type']."'"); - } - $expr->setJoinType($joinType); + $expr->setJoinType(self::mapJoinType($desc['join_type'])); if (isset($desc['alias']['name'])) { $expr->setAlias($desc['alias']['name']); @@ -222,7 +191,7 @@ public static function toObject(array $desc) $expr->setSubQuery(self::buildFromSubtree($desc['sub_tree'])); if (isset($desc['join_type'])) { - $expr->setJoinType($desc['join_type']); + $expr->setJoinType(self::mapJoinType($desc['join_type'])); } if (isset($desc['alias']['name'])) { @@ -908,4 +877,30 @@ public static function toSql($nodes, AbstractPlatform $platform, array $paramete return $sql; } + + private static function mapJoinType(string $originalJoinType): string + { + switch ($originalJoinType) { + case 'CROSS': + return 'CROSS JOIN'; + case 'JOIN': + return 'JOIN'; + case 'LEFT': + return 'LEFT JOIN'; + case 'RIGHT': + return 'RIGHT JOIN'; + case 'INNER': + return 'INNER JOIN'; + case 'OUTER': + return 'OUTER JOIN'; + case 'NATURAL': + return 'NATURAL JOIN'; + case 'STRAIGHT_JOIN': + return 'STRAIGHT_JOIN'; + case ',': + return ','; + default: + throw new \Exception("Unexpected join type: '".$originalJoinType."'"); + } + } } diff --git a/tests/Mouf/Database/MagicQueryTest.php b/tests/Mouf/Database/MagicQueryTest.php index 3c5e789..caa39c2 100644 --- a/tests/Mouf/Database/MagicQueryTest.php +++ b/tests/Mouf/Database/MagicQueryTest.php @@ -17,8 +17,8 @@ public function testStandardSelect() $sql = "SELECT GROUP_CONCAT(id SEPARATOR ', ') AS ids FROM users"; $this->assertEquals("SELECT GROUP_CONCAT(id SEPARATOR ', ') AS ids FROM users", self::simplifySql($magicQuery->build($sql))); - $sql = 'SELECT id FROM users WHERE name LIKE :name LIMIT :offset, :limit'; - $this->assertEquals("SELECT id FROM users WHERE name LIKE 'foo'", self::simplifySql($magicQuery->build($sql, ['name' => 'foo']))); + $sql = 'SELECT id FROM mysql.users WHERE name LIKE :name LIMIT :offset, :limit'; + $this->assertEquals("SELECT id FROM mysql.users WHERE name LIKE 'foo'", self::simplifySql($magicQuery->build($sql, ['name' => 'foo']))); $sql = 'SELECT id FROM users WHERE name LIKE :name LIMIT 2, :limit'; $this->assertEquals("SELECT id FROM users WHERE name LIKE 'foo' LIMIT 2, 10", self::simplifySql($magicQuery->build($sql, ['name' => 'foo', 'limit' => 10])));