Skip to content

DDC-1080: AbstractHydrator ->_gatherRowData using wrong metadata info #1671

Closed
doctrinebot opened this Issue Mar 25, 2011 · 9 comments

2 participants

@doctrinebot

Jira issue originally created by user tbo:

The following worked in a previous version but after upgrading to the latest to fix the security issue, I got an issue.

I will first start with the setup:

CREATE TABLE `bar` (
  `barID` int(11) NOT NULL AUTO_INCREMENT,
  `barTitle` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`barID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE `foo` (
  `fooID` int(11) NOT NULL AUTO_INCREMENT,
  `fooTitle` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`fooID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE `fooBar` (
  `fooID` int(11) NOT NULL,
  `barID` int(11) NOT NULL,
  `orderNr` int(11) DEFAULT NULL,
  PRIMARY KEY (`fooID`,`barID`),
  KEY `b` (`barID`),
  KEY `f` (`fooID`),
  CONSTRAINT `f` FOREIGN KEY (`fooID`) REFERENCES `foo` (`fooID`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `b` FOREIGN KEY (`barID`) REFERENCES `bar` (`barID`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `bar` (barID,barTitle) VALUES (1,'bar title 1');
INSERT INTO `bar` (barID,barTitle) VALUES (2,'bar title 2');
INSERT INTO `bar` (barID,barTitle) VALUES (3,'bar title 3');
INSERT INTO `bar` (barID,barTitle) VALUES (4,'bar title 4');

INSERT INTO `foo` (fooID,fooTitle) VALUES (1,'foo title 1');
INSERT INTO `foo` (fooID,fooTitle) VALUES (2,'foo title 2');

INSERT INTO `fooBar` (fooID,barID,orderNr) VALUES (1,1,0);
INSERT INTO `fooBar` (fooID,barID,orderNr) VALUES (1,2,1);
INSERT INTO `fooBar` (fooID,barID,orderNr) VALUES (1,3,3);
<?php
/****
 * @Entity
 * @Table(name="foo")
 */

class Application*Model*Foo
{

    /****
     * @Id 
     * @Column(name="fooID", type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    protected $_fooID;

    /****
     * @Column(name="fooTitle", type="string")
     */
    protected $_fooTitle;

    /****
     * @OneToMany(targetEntity="Application*Model_FooBar", mappedBy="*foo",
     * cascade={"persist"})
     * @OrderBy({"_orderNr"="ASC"})
     */
    protected $_fooBars;

    public function **construct ()
    {
        $this->_fooBars = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /****
     * @return the $fooID
     */
    public function getFooID ()
    {
        return $this->_fooID;
    }

    /****
     * @return the $fooTitle
     */
    public function getFooTitle ()
    {
        return $this->_fooTitle;
    }

    /****
     * @return the $fooBars
     */
    public function getFooBars ()
    {
        return $this->_fooBars;
    }

    /****
     * @param field_type $fooID
     */
    public function setFooID ($fooID)
    {
        $this->_fooID = $fooID;
    }

    /****
     * @param field_type $fooTitle
     */
    public function setFooTitle ($fooTitle)
    {
        $this->_fooTitle = $fooTitle;
    }

    /****
     * @param field_type $fooBars
     */
    public function setFooBars ($fooBars)
    {
        $this->_fooBars = $fooBars;
    }


}
<?php
/****
 * @Entity
 * @Table(name="bar")
 */

class Application*Model*Bar
{

    /****
     * @Id 
     * @Column(name="barID", type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    protected $_barID;

    /****
     * @Column(name="barTitle", type="string")
     */
    protected $_barTitle;

    /****
     * @OneToMany(targetEntity="Application*Model_FooBar", mappedBy="*bar",
     * cascade={"persist"})
     * @OrderBy({"_orderNr"="ASC"})
     */
    protected $_fooBars;

    public function **construct ()
    {
        $this->_fooBars = new \Doctrine\Common\Collections\ArrayCollection();
    }
    /****
     * @return the $barID
     */
    public function getBarID ()
    {
        return $this->_barID;
    }

    /****
     * @return the $barTitle
     */
    public function getBarTitle ()
    {
        return $this->_barTitle;
    }

    /****
     * @return the $fooBars
     */
    public function getFooBars ()
    {
        return $this->_fooBars;
    }

    /****
     * @param field_type $barID
     */
    public function setBarID ($barID)
    {
        $this->_barID = $barID;
    }

    /****
     * @param field_type $barTitle
     */
    public function setBarTitle ($barTitle)
    {
        $this->_barTitle = $barTitle;
    }

    /****
     * @param field_type $fooBars
     */
    public function setFooBars ($fooBars)
    {
        $this->_fooBars = $fooBars;
    }


}
<?php
/****
 * @Table(name="fooBar")
 * @Entity
 */
class Application*Model*FooBar
{

    /****
     * @ManyToOne(targetEntity="Application*Model*Foo")
     * @JoinColumn(name="fooID", referencedColumnName="fooID")
     * @Id
     */
    protected $_foo = null;

    /****
     * @ManyToOne(targetEntity="Application*Model*Bar")
     * @JoinColumn(name="barID", referencedColumnName="barID")
     * @Id
     */
    protected $_bar = null;

    /****
     * @var integer orderNr
     * @Column(name="orderNr", type="integer", nullable=false)
     */
    protected $_orderNr = null;

    /****
     * Retrieve the foo property
     *
     * @return Application*Model*Foo
     */
    public function getFoo()
    {
        return $this->_foo;
    }

    /****
     * Set the foo property
     *
     * @param Application*Model*Foo $foo
     * @return Application*Model*FooBar
     */
    public function setFoo($foo)
    {
        $this->_foo = $foo;
        return $this;
    }

    /****
     * Retrieve the bar property
     *
     * @return Application*Model*Bar
     */
    public function getBar()
    {
        return $this->_bar;
    }

    /****
     * Set the bar property
     *
     * @param Application*Model*Bar $bar
     * @return Application*Model*FooBar
     */
    public function setBar($bar)
    {
        $this->_bar = $bar;
        return $this;
    }

    /****
     * Retrieve the orderNr property
     *
     * @return integer|null
     */
    public function getOrderNr()
    {
        return $this->_orderNr;
    }

    /****
     * Set the orderNr property
     *
     * @param integer|null $orderNr
     * @return Application*Model*FooBar
     */
    public function setOrderNr($orderNr)
    {
        $this->_orderNr = $orderNr;
        return $this;
    }


}

When I execute the following code

$foo = $this->*em->find('Application_Model*Foo', 1);
$fooBars = $foo->getFooBars();
var_dump(count($fooBars));

I expect "3" as output. But I get "1".

There seems to be an issue with the metadata or the used fieldname in the _gatherRowData in the AbstractHydrator.

The following is a dump of $classMetadata = $this->em->getClassMetadata($this->rsm->aliasMap[$cache[$key]['dqlAlias']]);

Doctrine\ORM\Mapping\ClassMetadata Object
(
    [reflFields] => Array
        (
            [_orderNr] => ReflectionProperty Object
                (
                    [name] => _orderNr
                    [class] => Application*Model*FooBar
                )

            [_foo] => ReflectionProperty Object
                (
                    [name] => _foo
                    [class] => Application*Model*FooBar
                )

            [_bar] => ReflectionProperty Object
                (
                    [name] => _bar
                    [class] => Application*Model*FooBar
                )

        )

    [_prototype:Doctrine\ORM\Mapping\ClassMetadata:private] => 
    [name] => Application*Model*FooBar
    [namespace] => 
    [rootEntityName] => Application*Model*FooBar
    [customRepositoryClassName] => 
    [isMappedSuperclass] => 
    [parentClasses] => Array
        (
        )

    [subClasses] => Array
        (
        )

    [namedQueries] => Array
        (
        )

    [identifier] => Array
        (
            [0] => _foo
            [1] => _bar
        )

    [inheritanceType] => 1
    [generatorType] => 5
    [fieldMappings] => Array
        (
            [_orderNr] => Array
                (
                    [fieldName] => _orderNr
                    [type] => integer
                    [length] => 
                    [precision] => 0
                    [scale] => 0
                    [nullable] => 
                    [unique] => 
                    [columnName] => orderNr
                )

        )

    [fieldNames] => Array
        (
            [orderNr] => _orderNr
        )

    [columnNames] => Array
        (
            [_orderNr] => orderNr
        )

    [discriminatorValue] => 
    [discriminatorMap] => Array
        (
        )

    [discriminatorColumn] => 
    [table] => Array
        (
            [name] => fooBar
        )

    [lifecycleCallbacks] => Array
        (
        )

    [associationMappings] => Array
        (
            [_foo] => Array
                (
                    [fieldName] => _foo
                    [id] => 1
                    [joinColumns] => Array
                        (
                            [0] => Array
                                (
                                    [name] => fooID
                                    [referencedColumnName] => fooID
                                    [unique] => 
                                    [nullable] => 1
                                    [onDelete] => 
                                    [onUpdate] => 
                                    [columnDefinition] => 
                                )

                        )

                    [cascade] => Array
                        (
                        )

                    [inversedBy] => 
                    [targetEntity] => Application*Model*Foo
                    [fetch] => 2
                    [type] => 2
                    [mappedBy] => 
                    [isOwningSide] => 1
                    [sourceEntity] => Application*Model*FooBar
                    [isCascadeRemove] => 
                    [isCascadePersist] => 
                    [isCascadeRefresh] => 
                    [isCascadeMerge] => 
                    [isCascadeDetach] => 
                    [sourceToTargetKeyColumns] => Array
                        (
                            [fooID] => fooID
                        )

                    [joinColumnFieldNames] => Array
                        (
                            [fooID] => fooID
                        )

                    [targetToSourceKeyColumns] => Array
                        (
                            [fooID] => fooID
                        )

                    [orphanRemoval] => 
                )

            [_bar] => Array
                (
                    [fieldName] => _bar
                    [id] => 1
                    [joinColumns] => Array
                        (
                            [0] => Array
                                (
                                    [name] => barID
                                    [referencedColumnName] => barID
                                    [unique] => 
                                    [nullable] => 1
                                    [onDelete] => 
                                    [onUpdate] => 
                                    [columnDefinition] => 
                                )

                        )

                    [cascade] => Array
                        (
                        )

                    [inversedBy] => 
                    [targetEntity] => Application*Model*Bar
                    [fetch] => 2
                    [type] => 2
                    [mappedBy] => 
                    [isOwningSide] => 1
                    [sourceEntity] => Application*Model*FooBar
                    [isCascadeRemove] => 
                    [isCascadePersist] => 
                    [isCascadeRefresh] => 
                    [isCascadeMerge] => 
                    [isCascadeDetach] => 
                    [sourceToTargetKeyColumns] => Array
                        (
                            [barID] => barID
                        )

                    [joinColumnFieldNames] => Array
                        (
                            [barID] => barID
                        )

                    [targetToSourceKeyColumns] => Array
                        (
                            [barID] => barID
                        )

                    [orphanRemoval] => 
                )

        )

    [isIdentifierComposite] => 1
    [containsForeignIdentifier] => 1
    [idGenerator] => Doctrine\ORM\Id\AssignedGenerator Object
        (
        )

    [sequenceGeneratorDefinition] => 
    [tableGeneratorDefinition] => 
    [changeTrackingPolicy] => 1
    [isVersioned] => 
    [versionField] => 
    [reflClass] => ReflectionClass Object
        (
            [name] => Application*Model*FooBar
        )

)

$fieldName = $this->_rsm->metaMappings[$key]; is "fooID" or "barID"

After assigning $cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName); you get false back.

So you check for fooID / barID in the array

[identifier] => Array
        (
            [0] => _foo
            [1] => _bar
        )

what of course is false because they aren't in the array.

When I set the flag $cache[$key]['isIdentifier'] to true for the 2 fields, I get an output of 3 as expected.

So the fieldname is wrong or the identifier list is wrong.

@doctrinebot

Comment created by @beberlei:

"In a previous version"? What exact version please? I can't pin down the commits with such a broad statement.

Edit: Ah you are working with master and fkpk support. Can you still find out the version? There were some general fixes in the hydrator and one larger refactoring since I merged the fkpk branch.

@doctrinebot

Comment created by tbo:

This is the last log on a server where it is still working:
ORM:

commit 180078d0f6fa97bf5f3398e8c5d2f56030236c33
Author: Guilherme Blanco <guilhermeblanco@gmail.com>
Date:   Mon Mar 14 01:04:50 2011 -0300

    Added namedQueries as optional during serialization of ClassMetadata.

Common:

commit ba63ae0f0b6b62a2a8617f01386698730ff2b713
Author: Jonathan H. Wage <jonwage@gmail.com>
Date:   Wed Feb 16 10:17:48 2011 -0600

    Revert "Adding Driver interface for mapping drivers."

DBAL:

commit ae084d9c6975356f8f0f10d8802abe91df45b739
Author: Benjamin Eberlei <kontakt@beberlei.de>
Date:   Sun Jan 30 10:58:14 2011 -0500

    Release {$version}
@doctrinebot

Comment created by @beberlei:

Ah i know what the problem might be.

@doctrinebot

Comment created by tbo:

Great! Looking forward for a fix. It would solve a lot of issues I'm having now.

@doctrinebot

Comment created by @beberlei:

The bug appears because you rename the id column from the default value. If you rename the property to $fooId instead of $_fooId it works.

I have to check how i can fix this issue, but its complicated.

@doctrinebot

Comment created by @beberlei:

There are two potential fixes for this bug, both have their drawbacks, we have to discuss them in the team. For now rename the field to the name of the column to get it working.

@doctrinebot

Comment created by @beberlei:

Not a blocker, there is a workaround

@doctrinebot

Comment created by @beberlei:

Fixed

@doctrinebot

Issue was closed with resolution "Fixed"

@beberlei beberlei was assigned by doctrinebot Dec 6, 2015
@doctrinebot doctrinebot added this to the 2.1 milestone Dec 6, 2015
@doctrinebot doctrinebot closed this Dec 6, 2015
@doctrinebot doctrinebot added the Bug label Dec 7, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.