AbstractQuery::toIterable is not a full replacement for AbstractQuery::iterate #6881

Closed
opened 2026-01-22 15:40:39 +01:00 by admin · 7 comments
Owner

Originally created by @stof on GitHub (Dec 3, 2021).

Bug Report

Q A
BC Break yes (kind of)
Version 2.10.2

Summary

The new AbstractQuery::toIterable method does not support hydrating mixed results, while the deprecated AbstractQuery::iterate was supporting it. This means that it is not always possible to migrate from the deprecated API to its replacement API (and so that some cases would not be possible in ORM 3.0).

It would be great to support it.

Originally created by @stof on GitHub (Dec 3, 2021). ### Bug Report <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |------------ | ------ | BC Break | yes (kind of) | Version | 2.10.2 #### Summary The new `AbstractQuery::toIterable` method does not support hydrating mixed results, while the deprecated `AbstractQuery::iterate` was supporting it. This means that it is not always possible to migrate from the deprecated API to its replacement API (and so that some cases would not be possible in ORM 3.0). It would be great to support it.
admin closed this issue 2026-01-22 15:40:39 +01:00
Author
Owner

@derrabus commented on GitHub (Dec 3, 2021):

Can you provide an example of a piece of code that cannot be migrated to the new API?

@derrabus commented on GitHub (Dec 3, 2021): Can you provide an example of a piece of code that cannot be migrated to the new API?
Author
Owner

@stof commented on GitHub (Dec 3, 2021):

@derrabus any query selecting both an entity result and additional scalar results in its ResultSetMapping (be it in DQL or through createNativeQuery()

@stof commented on GitHub (Dec 3, 2021): @derrabus any query selecting both an entity result and additional scalar results in its ResultSetMapping (be it in DQL or through `createNativeQuery()`
Author
Owner

@stof commented on GitHub (Dec 3, 2021):

This is the code that is explicitly treating it as unsupported: 7b24275346/lib/Doctrine/ORM/AbstractQuery.php (L1091-L1093)

However, removing this condition is not enough, as \Doctrine\ORM\Internal\Hydration\AbstractHydrator::toIterable does not support it AFAICT.

@stof commented on GitHub (Dec 3, 2021): This is the code that is explicitly treating it as unsupported: https://github.com/doctrine/orm/blob/7b242753466508e1dd10f67c1baee95785f845c1/lib/Doctrine/ORM/AbstractQuery.php#L1091-L1093 However, removing this condition is not enough, as `\Doctrine\ORM\Internal\Hydration\AbstractHydrator::toIterable` does not support it AFAICT.
Author
Owner

@beberlei commented on GitHub (Dec 18, 2021):

Yes this is a known problem, we need to adress this in the generator, but I haven't found a way yet that does not lead to bugs in edge cases.

@beberlei commented on GitHub (Dec 18, 2021): Yes this is a known problem, we need to adress this in the generator, but I haven't found a way yet that does not lead to bugs in edge cases.
Author
Owner

@stof commented on GitHub (Dec 20, 2021):

For reference, here is the code I'm using since years in my project (but I don't guarantee that it covers all edge cases):

<?php

namespace Incenteev\WebBundle\Doctrine\Util;

use Doctrine\ORM\AbstractQuery;

class IterationCleaner
{
    /**
     * @phpstan-param AbstractQuery::HYDRATE_* $hydrationMode
     */
    public static function iterateCleanly(AbstractQuery $query, int $hydrationMode): \Traversable
    {
        // Doctrine's Query::iterate API is quite weird: it returns an array of data.
        // And in some cases, it might even split the data into multiple items of the returned array (see https://github.com/doctrine/orm/issues/2821)
        // TODO remove this logic once AbstractQuery::toIterable supports mixed hydration. See https://github.com/doctrine/orm/issues/9219
        foreach ($query->iterate(null, $hydrationMode) as $row) {
            if (count($row) > 1 && is_array($row[0])) {
                yield array_merge(...$row);
            } else {
                yield $row[0];
            }
        }
    }
}
@stof commented on GitHub (Dec 20, 2021): For reference, here is the code I'm using since years in my project (but I don't guarantee that it covers all edge cases): ```php <?php namespace Incenteev\WebBundle\Doctrine\Util; use Doctrine\ORM\AbstractQuery; class IterationCleaner { /** * @phpstan-param AbstractQuery::HYDRATE_* $hydrationMode */ public static function iterateCleanly(AbstractQuery $query, int $hydrationMode): \Traversable { // Doctrine's Query::iterate API is quite weird: it returns an array of data. // And in some cases, it might even split the data into multiple items of the returned array (see https://github.com/doctrine/orm/issues/2821) // TODO remove this logic once AbstractQuery::toIterable supports mixed hydration. See https://github.com/doctrine/orm/issues/9219 foreach ($query->iterate(null, $hydrationMode) as $row) { if (count($row) > 1 && is_array($row[0])) { yield array_merge(...$row); } else { yield $row[0]; } } } } ```
Author
Owner

@kbond commented on GitHub (Feb 24, 2022):

Related to https://github.com/doctrine/orm/issues/8520. Possible solution: https://github.com/doctrine/orm/pull/8555?

As a workaround, I use the paginator to chunk the results and iterate from each chunk.

@kbond commented on GitHub (Feb 24, 2022): Related to https://github.com/doctrine/orm/issues/8520. Possible solution: https://github.com/doctrine/orm/pull/8555? As a workaround, I use the paginator to _chunk_ the results and iterate from each _chunk_.
Author
Owner

@stof commented on GitHub (Dec 15, 2025):

This has been fixed in https://github.com/doctrine/orm/pull/12187

@stof commented on GitHub (Dec 15, 2025): This has been fixed in https://github.com/doctrine/orm/pull/12187
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6881