Undefined index: isIdentifier in Hydrator #6928

Open
opened 2026-01-22 15:41:31 +01:00 by admin · 8 comments
Owner

Originally created by @fink3l on GitHub (Feb 7, 2022).

Summary

After merge https://github.com/doctrine/orm/pull/7905 (doctrine/orm > 2.6.4) i'm having problems with LimitSubqueryWalker and AbstractHydrator. When i add hint LimitSubqueryWalker to Query and try to hydrate my Query i will get Notice Undefined index: isIdentifier in lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php:459

How to reproduce

For reproduce i wrote test:

<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\Tests\OrmFunctionalTestCase;

final class IsIdentifierUndefinedTest extends OrmFunctionalTestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        $this->setUpEntitySchema(
            [
                SomeEntity::class,
            ]
        );
    }

    public function testLimitSubqueryWalkerIsIdentifierUndefined(): void
    {
        $this->_em->persist(new SomeEntity());
        $this->_em->flush();

        $dql   = 'SELECT e FROM Doctrine\Tests\ORM\Functional\Ticket\SomeEntity e';
        $query = $this->_em->createQuery($dql);
        $query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_TREE_WALKERS, [\Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker::class]);

        $query->getResult(AbstractQuery::HYDRATE_ARRAY);
    }
}

/** @Entity */
final class SomeEntity
{
    /**
     * @var int
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    public $id;
}
Originally created by @fink3l on GitHub (Feb 7, 2022). #### Summary After merge https://github.com/doctrine/orm/pull/7905 (doctrine/orm > 2.6.4) i'm having problems with LimitSubqueryWalker and AbstractHydrator. When i add hint `LimitSubqueryWalker` to Query and try to hydrate my Query i will get Notice `Undefined index: isIdentifier` in **lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php:459** #### How to reproduce For reproduce i wrote test: ``` <?php declare(strict_types=1); namespace Doctrine\Tests\ORM\Functional\Ticket; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\GeneratedValue; use Doctrine\ORM\Mapping\Id; use Doctrine\Tests\OrmFunctionalTestCase; final class IsIdentifierUndefinedTest extends OrmFunctionalTestCase { protected function setUp(): void { parent::setUp(); $this->setUpEntitySchema( [ SomeEntity::class, ] ); } public function testLimitSubqueryWalkerIsIdentifierUndefined(): void { $this->_em->persist(new SomeEntity()); $this->_em->flush(); $dql = 'SELECT e FROM Doctrine\Tests\ORM\Functional\Ticket\SomeEntity e'; $query = $this->_em->createQuery($dql); $query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_TREE_WALKERS, [\Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker::class]); $query->getResult(AbstractQuery::HYDRATE_ARRAY); } } /** @Entity */ final class SomeEntity { /** * @var int * @Id * @Column(type="integer") * @GeneratedValue */ public $id; } ```
Author
Owner

@realkasparov commented on GitHub (Feb 14, 2022):

The same situation!

@realkasparov commented on GitHub (Feb 14, 2022): The same situation!
Author
Owner

@greg0ire commented on GitHub (Feb 14, 2022):

You seem to still be using an outdated version because now the line with the issue is 460 (not 459). But when I try your test on 2.11.x, I get the issue, which means recent versions are still affected.

@greg0ire commented on GitHub (Feb 14, 2022): You seem to still be using an outdated version because now the line with the issue is 460 (not 459). But when I try your test on 2.11.x, I get the issue, which means recent versions are still affected.
Author
Owner

@greg0ire commented on GitHub (Feb 14, 2022):

@lcobucci @ostrolucky maybe you will have some idea of what to do?

@greg0ire commented on GitHub (Feb 14, 2022): @lcobucci @ostrolucky maybe you will have some idea of what to do?
Author
Owner

@lcobucci commented on GitHub (Feb 14, 2022):

I'm on mobile now and won't be able to do this but essentially we need to debug what's generated by 8f847cb5aa/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php (L521) to understand why that index is missing.

@lcobucci commented on GitHub (Feb 14, 2022): I'm on mobile now and won't be able to do this but essentially we need to debug what's generated by https://github.com/doctrine/orm/blob/8f847cb5aaf401110dce778dde9f4f014a750bde/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php#L521 to understand why that index is missing.
Author
Owner

@greg0ire commented on GitHub (Feb 14, 2022):

From what I see when executing the failing test case, it ends up here:

bfed8cb6ed/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php (L570-L575)

I'm not sure what to add there, but when I add 'isIdentifier' => true or 'isIdentifier' => false (I don't have any idea what I'm doing), I get another error message Exception: [PHPUnit\Framework\Error\Warning] Undefined array key "" emanating from 8f847cb5aa/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php (L159) (which is consistent with 'dqlAlias' => '' in the listing above.

@greg0ire commented on GitHub (Feb 14, 2022): From what I see when executing the failing test case, it ends up here: https://github.com/doctrine/orm/blob/bfed8cb6ed448f4ab1ea3fff06e4d6c44439e4ef/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php#L570-L575 I'm not sure what to add there, but when I add `'isIdentifier' => true` or `'isIdentifier' => false` (I don't have any idea what I'm doing), I get another error message `Exception: [PHPUnit\Framework\Error\Warning] Undefined array key ""` emanating from https://github.com/doctrine/orm/blob/8f847cb5aaf401110dce778dde9f4f014a750bde/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php#L159 (which is consistent with `'dqlAlias' => ''` in the listing above.
Author
Owner

@lcobucci commented on GitHub (Feb 15, 2022):

I have some time today for checking it 👍

@lcobucci commented on GitHub (Feb 15, 2022): I have some time today for checking it 👍
Author
Owner

@lcobucci commented on GitHub (Feb 15, 2022):

@fink3l @realkasparov does the snippet represent a real-life use case or is this only there to reproduce the issue? In other words, why are you having to use that SQL walker?

@lcobucci commented on GitHub (Feb 15, 2022): @fink3l @realkasparov does the snippet represent a real-life use case or is this only there to reproduce the issue? In other words, why are you having to use that SQL walker?
Author
Owner

@lcobucci commented on GitHub (Feb 15, 2022):

Just to give more information here, this SQL walker was designed for the pagination tool (ergo my previous question). Using it outside of its designed use case will create unintended results - SQL AST is manipulated to generate a SELECT DISTINCT table.id AS _dctrn_id FROM table.

The unintended result highlighted here is that ArrayHydrator (and ObjectHydrator) doesn't work when that SQL walker is added to the query. That's because, since the linked issue, we're doing a workaround to avoid BC-breaks and always force DBAL type conversion for pagination queries.

Using scalar hydrators work just fine:

<?php
declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\Tests\OrmFunctionalTestCase;

final class GH9483Test extends OrmFunctionalTestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        $this->setUpEntitySchema(
            [
                GH9483SomeEntity::class,
            ]
        );
    }

    public function testLimitSubqueryWalkerIsIdentifierUndefined(): void
    {
        $this->_em->persist(new GH9483SomeEntity());
        $this->_em->flush();

        $dql   = 'SELECT e FROM Doctrine\Tests\ORM\Functional\Ticket\GH9483SomeEntity e';
        $query = $this->_em->createQuery($dql);
        $query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_TREE_WALKERS, [\Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker::class]);

        self::assertSame([['__dctrn_id' => 1]], $query->getResult(AbstractQuery::HYDRATE_SCALAR));
        self::assertSame(1, $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR));
    }
}

/** @Entity */
final class GH9483SomeEntity
{
    /**
     * @var int
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    public $id;
}

The ideal solution would be always performing the DBAL type conversion but that's a BC-break. Then, the workaround that was previously introduced could be removed.

With that said, we must ask: why do you need to rely on a pagination SQL walker for a query that doesn't use the paginator component? Or, wouldn't it be easier for you to make your code explicit and use a DQL like SELECT DISTINCT e.id FROM Doctrine\Tests\ORM\Functional\Ticket\GH9483SomeEntity e?

@lcobucci commented on GitHub (Feb 15, 2022): Just to give more information here, this SQL walker was designed for the pagination tool (ergo my previous question). Using it outside of its designed use case will create unintended results - SQL AST is manipulated to generate a `SELECT DISTINCT table.id AS _dctrn_id FROM table`. The unintended result highlighted here is that `ArrayHydrator` (and `ObjectHydrator`) doesn't work when that SQL walker is added to the query. That's because, since the linked issue, we're doing a workaround to avoid BC-breaks and always force DBAL type conversion for pagination queries. Using scalar hydrators work just fine: ```php <?php declare(strict_types=1); namespace Doctrine\Tests\ORM\Functional\Ticket; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\GeneratedValue; use Doctrine\ORM\Mapping\Id; use Doctrine\Tests\OrmFunctionalTestCase; final class GH9483Test extends OrmFunctionalTestCase { protected function setUp(): void { parent::setUp(); $this->setUpEntitySchema( [ GH9483SomeEntity::class, ] ); } public function testLimitSubqueryWalkerIsIdentifierUndefined(): void { $this->_em->persist(new GH9483SomeEntity()); $this->_em->flush(); $dql = 'SELECT e FROM Doctrine\Tests\ORM\Functional\Ticket\GH9483SomeEntity e'; $query = $this->_em->createQuery($dql); $query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_TREE_WALKERS, [\Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker::class]); self::assertSame([['__dctrn_id' => 1]], $query->getResult(AbstractQuery::HYDRATE_SCALAR)); self::assertSame(1, $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR)); } } /** @Entity */ final class GH9483SomeEntity { /** * @var int * @Id * @Column(type="integer") * @GeneratedValue */ public $id; } ``` The ideal solution would be **always performing** the DBAL type conversion but that's a BC-break. Then, the workaround that was previously introduced could be removed. With that said, we must ask: why do you need to rely on a pagination SQL walker for a query that doesn't use the paginator component? Or, wouldn't it be easier for you to make your code explicit and use a DQL like `SELECT DISTINCT e.id FROM Doctrine\Tests\ORM\Functional\Ticket\GH9483SomeEntity e`?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6928