diff --git a/docs/en/reference/data-retrieval-and-manipulation.rst b/docs/en/reference/data-retrieval-and-manipulation.rst index 0efba4c466c..6b1878084a1 100644 --- a/docs/en/reference/data-retrieval-and-manipulation.rst +++ b/docs/en/reference/data-retrieval-and-manipulation.rst @@ -398,6 +398,26 @@ Execute the query and fetch the first two columns into an associative array as k .. note:: All additional columns will be ignored and are only allowed to be selected by DBAL for its internal purposes. +fetchAllAssociativeIndexed() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Execute the query and fetch the data as an associative array where the key represents the first column and the value is +an associative array of the rest of the columns and their values: + +.. code-block:: php + + fetchAllAssociativeIndexed('SELECT id, username, password FROM user'); + + /* + array( + 1 => array( + 'username' => 'jwage', + 'password' => 'changeme', + ) + ) + */ + fetchNumeric() ~~~~~~~~~~~~~~ @@ -459,6 +479,19 @@ Execute the query and iterate over the first two columns as keys and values resp .. note:: All additional columns will be ignored and are only allowed to be selected by DBAL for its internal purposes. +fetchAllAssociativeIndexed() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Execute the query and iterate over the result with the key representing the first column and the value being +an associative array of the rest of the columns and their values: + +.. code-block:: php + + iterateAssociativeIndexed('SELECT id, username, password FROM user') as $id => $data) { + // ... + } + delete() ~~~~~~~~~ diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 1d9477431f9..2d5d4402bb8 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -25,6 +25,7 @@ use Traversable; use function array_key_exists; +use function array_shift; use function assert; use function func_get_args; use function implode; @@ -990,9 +991,9 @@ public function fetchAllAssociative(string $query, array $params = [], array $ty * Prepares and executes an SQL query and returns the result as an associative array with the keys * mapped to the first column and the values mapped to the second column. * - * @param string $query The SQL query. - * @param array|array $params The query parameters. - * @param array|array $types The query parameter types. + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types * * @return array * @@ -1013,6 +1014,32 @@ public function fetchAllKeyValue(string $query, array $params = [], array $types return $data; } + /** + * Prepares and executes an SQL query and returns the result as an associative array with the keys mapped + * to the first column and the values being an associative array representing the rest of the columns + * and their values. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociativeIndexed(string $query, array $params = [], array $types = []): array + { + $stmt = $this->executeQuery($query, $params, $types); + + $data = []; + + foreach ($stmt->fetchAll(FetchMode::ASSOCIATIVE) as $row) { + $data[array_shift($row)] = $row; + } + + return $data; + } + /** * Prepares and executes an SQL query and returns the result as an array of the first column values. * @@ -1100,9 +1127,9 @@ public function iterateAssociative(string $query, array $params = [], array $typ * Prepares and executes an SQL query and returns the result as an iterator with the keys * mapped to the first column and the values mapped to the second column. * - * @param string $query The SQL query. - * @param array|array $params The query parameters. - * @param array|array $types The query parameter types. + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types * * @return Traversable * @@ -1119,6 +1146,28 @@ public function iterateKeyValue(string $query, array $params = [], array $types } } + /** + * Prepares and executes an SQL query and returns the result as an iterator with the keys mapped + * to the first column and the values being an associative array representing the rest of the columns + * and their values. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []): Traversable + { + $stmt = $this->executeQuery($query, $params, $types); + + while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield array_shift($row) => $row; + } + } + /** * Prepares and executes an SQL query and returns the result as an iterator over the first column values. * diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index ff27cd13aca..ad5d29b9a5d 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -13,6 +13,7 @@ use Throwable; use Traversable; +use function array_shift; use function is_array; use function is_string; @@ -398,6 +399,25 @@ public function fetchAllKeyValue(): array return $data; } + /** + * Returns an associative array with the keys mapped to the first column and the values being + * an associative array representing the rest of the columns and their values. + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociativeIndexed(): array + { + $data = []; + + foreach ($this->fetchAll(FetchMode::ASSOCIATIVE) as $row) { + $data[array_shift($row)] = $row; + } + + return $data; + } + /** * {@inheritdoc} * @@ -483,6 +503,21 @@ public function iterateKeyValue(): Traversable } } + /** + * Returns an iterator over the result set with the keys mapped to the first column and the values being + * an associative array representing the rest of the columns and their values. + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociativeIndexed(): Traversable + { + while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield array_shift($row) => $row; + } + } + /** * {@inheritDoc} * diff --git a/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php b/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php index 49854b3e121..e5f4d2472dd 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php @@ -126,6 +126,27 @@ public function testFetchAllKeyValueOneColumn(): void $this->connection->fetchAllKeyValue($sql); } + public function testFetchAllAssociativeIndexed(): void + { + self::assertEquals([ + 'foo' => ['b' => 1], + 'bar' => ['b' => 2], + 'baz' => ['b' => 3], + ], $this->connection->fetchAllAssociativeIndexed($this->query)); + } + + public function testStatementFetchAllAssociativeIndexed(): void + { + $stmt = $this->connection->prepare($this->query); + $stmt->execute(); + + self::assertEquals([ + 'foo' => ['b' => 1], + 'bar' => ['b' => 2], + 'baz' => ['b' => 3], + ], $stmt->fetchAllAssociativeIndexed()); + } + public function testFetchFirstColumn(): void { self::assertEquals([ @@ -171,7 +192,7 @@ public function testIterateKeyValue(): void ], iterator_to_array($this->connection->iterateKeyValue($this->query))); } - public function testStatementKeyValue(): void + public function testStatementIterateKeyValue(): void { $stmt = $this->connection->prepare($this->query); $stmt->execute(); @@ -192,6 +213,27 @@ public function testIterateKeyValueOneColumn(): void iterator_to_array($this->connection->iterateKeyValue($sql)); } + public function testIterateAssociativeIndexed(): void + { + self::assertEquals([ + 'foo' => ['b' => 1], + 'bar' => ['b' => 2], + 'baz' => ['b' => 3], + ], iterator_to_array($this->connection->iterateAssociativeIndexed($this->query))); + } + + public function testStatementIterateAssociativeIndexed(): void + { + $stmt = $this->connection->prepare($this->query); + $stmt->execute(); + + self::assertEquals([ + 'foo' => ['b' => 1], + 'bar' => ['b' => 2], + 'baz' => ['b' => 3], + ], iterator_to_array($stmt->iterateAssociativeIndexed())); + } + public function testIterateColumn(): void { self::assertEquals([