From 5f3c1dbab8513d3529017b4df6558dcfd185b934 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Tue, 26 Mar 2024 21:40:18 +0100 Subject: [PATCH] [Documentation] Merging "Query Result Formats" with "Hydration Modes" Page: https://www.doctrine-project.org/projects/doctrine-orm/en/2.19/reference/dql-doctrine-query-language.html#query-result-formats As announced in https://github.com/doctrine/orm/pull/11372#issue-2190613801, I merged the (mostly) identical sections. * I changed the `const`s from `Query` to `AbstractQuery` * I deleted this - mainly cause I didn't find a nice place for it: > In parentheses are the constants of the ``Query`` class which you can use with the general-purpose method ``Query::execute(array $params = [], $hydrationMode = Query::HYDRATE_OBJECT)``. --- .../reference/dql-doctrine-query-language.rst | 331 ++++++++---------- 1 file changed, 138 insertions(+), 193 deletions(-) diff --git a/docs/en/reference/dql-doctrine-query-language.rst b/docs/en/reference/dql-doctrine-query-language.rst index 1cc4c22cec..ce06d02b81 100644 --- a/docs/en/reference/dql-doctrine-query-language.rst +++ b/docs/en/reference/dql-doctrine-query-language.rst @@ -1020,42 +1020,146 @@ Alternatively you can create an empty ``Query`` instance and invoke $q = $em->createQuery(); $q->setDQL('select u from MyProject\Model\User u'); -Query Result Formats -~~~~~~~~~~~~~~~~~~~~ +Query Result Formats (Hydration Modes) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The way in which the SQL result set of a DQL SELECT query is transformed -to PHP is determined by the so-called "hydration mode": - -- **``getResult()``** (``HYDRATE_OBJECT``): Retrieves a collection of objects. The - result is either a plain collection of objects (pure) or an array - where the objects are nested in the result rows (mixed). -- **``getSingleResult()``**: Retrieves a single object. If the - result contains more than one object, a ``NonUniqueResultException`` - is thrown. If the result contains no objects, a ``NoResultException`` - is thrown. The pure/mixed distinction does not apply. -- **``getOneOrNullResult()``**: Retrieve a single object. If the - result contains more than one object, a ``NonUniqueResultException`` - is thrown. If no object is found null will be returned. -- **``getArrayResult()``** (``HYDRATE_ARRAY``): Retrieves an array graph (a nested - array) for read-only purposes. - - .. note:: - - An array graph can differ from the corresponding object - graph in certain scenarios due to the difference of the identity - semantics between arrays and objects. - -- **``getScalarResult()``** (``HYDRATE_SCALAR``): Retrieves a flat/rectangular result - set of scalar values that can contain duplicate data. The - pure/mixed distinction does not apply. -- **``getSingleScalarResult()``** (``HYDRATE_SINGLE_SCALAR``: Retrieves a single scalar - value from the result returned by the dbms. If the result contains - more than a single scalar value, a ``NonUniqueResultException`` is thrown. The - pure/mixed distinction does not apply. - -In parentheses are the constants of the ``Query`` class which you can use with the -general-purpose method ``Query::execute(array $params = [], $hydrationMode = Query::HYDRATE_OBJECT)``. -In fact, the methods in the list are just convenient shortcuts for the hydration mode. +to PHP is determined by the so-called "hydration mode". + +``getResult()`` +^^^^^^^^^^^^^^^ + +Retrieves a collection of objects. The result is either a plain collection of objects (pure) or an array +where the objects are nested in the result rows (mixed): + +.. code-block:: php + + createQuery('SELECT u FROM User u'); + $users = $query->getResult(); + // same as: + $users = $query->getResult(AbstractQuery::HYDRATE_OBJECT); + +- Objects fetched in a FROM clause are returned as a Set, that means every + object is only ever included in the resulting array once. This is the case + even when using JOIN or GROUP BY in ways that return the same row for an + object multiple times. If the hydrator sees the same object multiple times, + then it makes sure it is only returned once. + +- If an object is already in memory from a previous query of any kind, then + then the previous object is used, even if the database may contain more + recent data. This even happens if the previous object is still an unloaded proxy. + +``getArrayResult()`` +^^^^^^^^^^^^^^^^^^^^ + +Retrieves an array graph (a nested array) for read-only purposes. + +.. note:: + + An array graph can differ from the corresponding object + graph in certain scenarios due to the difference of the identity + semantics between arrays and objects. + +.. code-block:: php + + getArrayResult(); + // same as: + $users = $query->getResult(AbstractQuery::HYDRATE_ARRAY); + +``getScalarResult()`` +^^^^^^^^^^^^^^^^^^^^^ + +Retrieves a flat/rectangular result set of scalar values that can contain duplicate data. The +pure/mixed distinction does not apply. + +.. code-block:: php + + getScalarResult(); + // same as: + $users = $query->getResult(AbstractQuery::HYDRATE_SCALAR); + +Fields from classes are prefixed by the DQL alias in the result. +A query of the kind `SELECT u.name ...` returns a key `u_name` in the result rows. + +``getSingleScalarResult()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieves a single scalar value from the result returned by the database. If the result contains +more than a single scalar value, a ``NonUniqueResultException`` is thrown. The pure/mixed distinction does not apply. + +.. code-block:: php + + createQuery('SELECT COUNT(u.id) FROM User u'); + $numUsers = $query->getSingleScalarResult(); + // same as: + $numUsers = $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR); + +``getSingleColumnResult()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieves an array from a one-dimensional array of scalar values: + +.. code-block:: php + + createQuery('SELECT a.id FROM User u'); + $ids = $query->getSingleColumnResult(); + // same as: + $ids = $query->getResult(AbstractQuery::HYDRATE_SCALAR_COLUMN); + +``getSingleResult()`` +^^^^^^^^^^^^^^^^^^^^^ + +Retrieves a single object. If the result contains more than one object, a ``NonUniqueResultException`` +is thrown. If the result contains no objects, a ``NoResultException`` is thrown. The pure/mixed distinction does not apply. + +``getOneOrNullResult()`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieves a single object. If the result contains more than one object, a ``NonUniqueResultException`` +is thrown. If no object is found, ``null`` will be returned. + +Custom Hydration Modes +^^^^^^^^^^^^^^^^^^^^^^ + +You can easily add your own custom hydration modes by first +creating a class which extends ``AbstractHydrator``: + +.. code-block:: php + + _stmt->fetchAllAssociative(); + } + } + +Next you just need to add the class to the ORM configuration: + +.. code-block:: php + + getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator'); + +Now the hydrator is ready to be used in your queries: + +.. code-block:: php + + createQuery('SELECT u FROM CmsUser u'); + $results = $query->getResult('CustomHydrator'); Pure and Mixed Results ~~~~~~~~~~~~~~~~~~~~~~ @@ -1159,165 +1263,6 @@ will return the rows iterating the different top-level entities. [2] => Object (User) [3] => Object (Group) - -Hydration Modes -~~~~~~~~~~~~~~~ - -Each of the Hydration Modes makes assumptions about how the result -is returned to user land. You should know about all the details to -make best use of the different result formats: - -The constants for the different hydration modes are: - - -- ``Query::HYDRATE_OBJECT`` -- ``Query::HYDRATE_ARRAY`` -- ``Query::HYDRATE_SCALAR`` -- ``Query::HYDRATE_SINGLE_SCALAR`` -- ``Query::HYDRATE_SCALAR_COLUMN`` - -Object Hydration -^^^^^^^^^^^^^^^^ - -Object hydration hydrates the result set into the object graph: - -.. code-block:: php - - createQuery('SELECT u FROM CmsUser u'); - $users = $query->getResult(Query::HYDRATE_OBJECT); - -Sometimes the behavior in the object hydrator can be confusing, which is -why we are listing as many of the assumptions here for reference: - -- Objects fetched in a FROM clause are returned as a Set, that means every - object is only ever included in the resulting array once. This is the case - even when using JOIN or GROUP BY in ways that return the same row for an - object multiple times. If the hydrator sees the same object multiple times, - then it makes sure it is only returned once. - -- If an object is already in memory from a previous query of any kind, then - then the previous object is used, even if the database may contain more - recent data. Data from the database is discarded. This even happens if the - previous object is still an unloaded proxy. - -This list might be incomplete. - -Array Hydration -^^^^^^^^^^^^^^^ - -You can run the same query with array hydration and the result set -is hydrated into an array that represents the object graph: - -.. code-block:: php - - createQuery('SELECT u FROM CmsUser u'); - $users = $query->getResult(Query::HYDRATE_ARRAY); - -You can use the ``getArrayResult()`` shortcut as well: - -.. code-block:: php - - getArrayResult(); - -Scalar Hydration -^^^^^^^^^^^^^^^^ - -If you want to return a flat rectangular result set instead of an -object graph you can use scalar hydration: - -.. code-block:: php - - createQuery('SELECT u FROM CmsUser u'); - $users = $query->getResult(Query::HYDRATE_SCALAR); - echo $users[0]['u_id']; - -The following assumptions are made about selected fields using -Scalar Hydration: - - -1. Fields from classes are prefixed by the DQL alias in the result. - A query of the kind 'SELECT u.name ..' returns a key 'u_name' in - the result rows. - -Single Scalar Hydration -^^^^^^^^^^^^^^^^^^^^^^^ - -If you have a query which returns just a single scalar value you can use -single scalar hydration: - -.. code-block:: php - - createQuery('SELECT COUNT(a.id) FROM CmsUser u LEFT JOIN u.articles a WHERE u.username = ?1 GROUP BY u.id'); - $query->setParameter(1, 'jwage'); - $numArticles = $query->getResult(Query::HYDRATE_SINGLE_SCALAR); - -You can use the ``getSingleScalarResult()`` shortcut as well: - -.. code-block:: php - - getSingleScalarResult(); - -Scalar Column Hydration -^^^^^^^^^^^^^^^^^^^^^^^ - -If you have a query which returns a one-dimensional array of scalar values -you can use scalar column hydration: - -.. code-block:: php - - createQuery('SELECT a.id FROM CmsUser u'); - $ids = $query->getResult(Query::HYDRATE_SCALAR_COLUMN); - -You can use the ``getSingleColumnResult()`` shortcut as well: - -.. code-block:: php - - getSingleColumnResult(); - -Custom Hydration Modes -^^^^^^^^^^^^^^^^^^^^^^ - -You can easily add your own custom hydration modes by first -creating a class which extends ``AbstractHydrator``: - -.. code-block:: php - - _stmt->fetchAllAssociative(); - } - } - -Next you just need to add the class to the ORM configuration: - -.. code-block:: php - - getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator'); - -Now the hydrator is ready to be used in your queries: - -.. code-block:: php - - createQuery('SELECT u FROM CmsUser u'); - $results = $query->getResult('CustomHydrator'); - Iterating Large Result Sets ~~~~~~~~~~~~~~~~~~~~~~~~~~~