ArrayHydrator can't load OneToMany related entities collection. Differences with ObjectHydrator #5731

Open
opened 2026-01-22 15:15:51 +01:00 by admin · 2 comments
Owner

Originally created by @ultracote on GitHub (Oct 5, 2017).

For example, I have next classes:

<?php

/**
 * Some table entity
 *
 * @Map\Entity(repositoryClass="SomeTableRepository")
 * @Map\Table(name="some_table")
 */
class SomeTableEntity
{
    public function __construct()
    {
        $this->fields = new ArrayCollection();
    }

    /**
     * @var int
     * @Map\Id
     * @Map\Column(type="integer")
     * @Map\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     * @Map\Column(type="string", nullable=false, name="some_text")
     */
    private $someText;

    /* . . .
     * Other getters and setters
     * . . .
     */

    /**
     * @var FieldEntity[]|ArrayCollection
     * @Map\OneToMany(targetEntity="FieldEntity", mappedBy="someTable")
     */
    private $fields;

    public function getFields()
    {
        return $this->fields;
    }

    public function setFields($fields)
    {
        if (is_array($fields)) {
            $fields = new ArrayCollection($fields);
        }

        $this->fields = $fields;
    }

    public function addField(FieldEntity $field)
    {
        $this->fields->add($field);
    }
}

/**
 * @Map\Entity(repositoryClass="FieldRepository")
 * @Map\Table(name="field")
 */
class FieldEntity
{
    /**
     * @var int
     * @Map\Id
     * @Map\Column(type="integer")
     * @Map\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var SomeTableEntity
     * @Map\ManyToOne(targetEntity="SomeTableEntity", inversedBy="fields")
     * @Map\JoinColumn(name="some_table_id", referencedColumnName="id")
     */
    private $someTable;

    /*
     * . . .
     */

    /**
     * @return SomeTableEntity
     */
    public function getSomeTable()
    {
        return $this->someTable;
    }

    /**
     * @param SomeTableEntity $someTable
     * @return FieldEntity
     */
    public function setSomeTable(SomeTableEntity $someTable)
    {
        $this->someTable = $someTable;
        return $this;
    }
}

class SomeTableRepository
{
    /**
     * It method as example and intentionally simplified.
     */
    public function getAll()
    {
        $qb    = $this->createQueryBuilder('stbl');
        $query = $qb->getQuery();

        $objectResult = $query->getResult();
        $arrayResult  = $query->getArrayResult();
    }
}

In result $objectResult and $arrayResult have different data.

$objectResult = [
  { // SomeTable object
    id = 1,
    someText = 'blabla',
    fields = [
      Field, // object
      Field // object
    ]
  },
  . . .
];

$arrayResult = [
  [
    id = 1,
    someText = 'blabla'
    // It haven't fields!
  ],
  . . .
];

In ObjectHydrator "fields" loaded there

// PATH C: Its a root result element
. . .
// check for existing result from the iterations before
if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
  $element = $this->getEntity($data, $dqlAlias); // There

ArrayHydrator in the same logic branch take element loaded above from $this->gatherRowData():

// Check for an existing element
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
  $element = $this->_rsm->isMixed
    ? array($entityKey => $data)
    : $data;

$this->gatherRowData() returns for both (Array and Object hydrators) array without "fields", but ObjectHydrator adds "fields" below, and the ArrayHydrator does not.

Which of these works incorrectly? ObjectHydrator or ArrayHydrator?

Originally created by @ultracote on GitHub (Oct 5, 2017). For example, I have next classes: ```php <?php /** * Some table entity * * @Map\Entity(repositoryClass="SomeTableRepository") * @Map\Table(name="some_table") */ class SomeTableEntity { public function __construct() { $this->fields = new ArrayCollection(); } /** * @var int * @Map\Id * @Map\Column(type="integer") * @Map\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * @Map\Column(type="string", nullable=false, name="some_text") */ private $someText; /* . . . * Other getters and setters * . . . */ /** * @var FieldEntity[]|ArrayCollection * @Map\OneToMany(targetEntity="FieldEntity", mappedBy="someTable") */ private $fields; public function getFields() { return $this->fields; } public function setFields($fields) { if (is_array($fields)) { $fields = new ArrayCollection($fields); } $this->fields = $fields; } public function addField(FieldEntity $field) { $this->fields->add($field); } } /** * @Map\Entity(repositoryClass="FieldRepository") * @Map\Table(name="field") */ class FieldEntity { /** * @var int * @Map\Id * @Map\Column(type="integer") * @Map\GeneratedValue(strategy="AUTO") */ private $id; /** * @var SomeTableEntity * @Map\ManyToOne(targetEntity="SomeTableEntity", inversedBy="fields") * @Map\JoinColumn(name="some_table_id", referencedColumnName="id") */ private $someTable; /* * . . . */ /** * @return SomeTableEntity */ public function getSomeTable() { return $this->someTable; } /** * @param SomeTableEntity $someTable * @return FieldEntity */ public function setSomeTable(SomeTableEntity $someTable) { $this->someTable = $someTable; return $this; } } class SomeTableRepository { /** * It method as example and intentionally simplified. */ public function getAll() { $qb = $this->createQueryBuilder('stbl'); $query = $qb->getQuery(); $objectResult = $query->getResult(); $arrayResult = $query->getArrayResult(); } } ``` In result $objectResult and $arrayResult have different data. ``` $objectResult = [ { // SomeTable object id = 1, someText = 'blabla', fields = [ Field, // object Field // object ] }, . . . ]; $arrayResult = [ [ id = 1, someText = 'blabla' // It haven't fields! ], . . . ]; ``` In ObjectHydrator "fields" loaded there ```php // PATH C: Its a root result element . . . // check for existing result from the iterations before if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) { $element = $this->getEntity($data, $dqlAlias); // There ``` ArrayHydrator in the same logic branch take element loaded above from $this->gatherRowData(): ```php // Check for an existing element if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { $element = $this->_rsm->isMixed ? array($entityKey => $data) : $data; ``` $this->gatherRowData() returns for both (Array and Object hydrators) array without "fields", but ObjectHydrator adds "fields" below, and the ArrayHydrator does not. Which of these works incorrectly? ObjectHydrator or ArrayHydrator?
Author
Owner

@ultracote commented on GitHub (Nov 10, 2017):

Is it a bug?

@ultracote commented on GitHub (Nov 10, 2017): Is it a bug?
Author
Owner

@fesor commented on GitHub (Nov 14, 2017):

That's why it considered to be removed in 3.0: #3998

@fesor commented on GitHub (Nov 14, 2017): That's why it considered to be removed in 3.0: #3998
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#5731