Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefined index and invalid number of prepared parameters #7707

Open
NotionCommotion opened this issue May 13, 2019 · 2 comments
Open

Undefined index and invalid number of prepared parameters #7707

NotionCommotion opened this issue May 13, 2019 · 2 comments

Comments

@NotionCommotion
Copy link

NotionCommotion commented May 13, 2019

Bug Report

Q A
BC Break yes
Version 1.6.1

Summary

The owning side of bi-directional one-to-one association cannot be a class type inherited class. ERD per this link. When doing so, the inherited class is not added to UnitOfWork::entityIdentifiers array, but only the inherited class's parent. This later results in UnitOfWork::getEntityIdentifier() inability to get the identifier and Doctrine providing the wrong number of parameters for the prepared statement.

Current behavior

As seen below, the first two queries execute, but the last one (client_subClassType1) fails as Doctrine doesn't include the parent's PK to be used as this table's PK.

[michael@devserver testing]$ php create.php
"START TRANSACTION"
INSERT INTO mainClass (name) VALUES (?)
array(1) {
  [1]=>
  string(13) "MainClassName"
}
array(1) {
  [1]=>
  string(6) "string"
}
INSERT INTO subClass (someCommonProperty, id, discriminator) VALUES (?, ?, ?)
array(3) {
  [1]=>
  string(18) "SomeCommonProperty"
  [2]=>
  int(7)
  [3]=>
  string(13) "subClassType1"
}
array(3) {
  [1]=>
  string(6) "string"
  [2]=>
  string(7) "integer"
  [3]=>
  string(6) "string"
}

Notice: Undefined index: 000000000744ff62000000006b73da3c in /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 2995
INSERT INTO subclassType1 (id, someIndividualProperty) VALUES (?, ?)
array(1) {
  [1]=>
  string(22) "SomeIndividualProperty"
}
array(1) {
  [1]=>
  string(6) "string"
}
"ROLLBACK"

Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117
Stack trace:
#0 /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php(117): PDOStatement->execute(NULL)
#1 /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php(153): Doctrine\DBAL\Driver\PDOStatement->execute(NULL)
#2 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php(213): Doctrine\DBAL\Statement->execute()
#3 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(1073): Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister->executeInserts()
#4 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(386): Doctrine\ORM\UnitOfWork->executeInserts(Object(Doctrine\ORM\Mapping\ClassMetadata))
#5 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(359): Do in /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php on line 106
[michael@devserver testing]$

How to reproduce

Execute the following script with entities defined below.

<?php
ini_set('display_errors', 1);

require_once "bootstrap.php";

$mainClass = new MainClass();
$mainClass->setName('MainClassName');
$subClass=new SubClassType1();
$subClass->setSomeCommonProperty('SomeCommonProperty');
$subClass->setSomeIndividualProperty('SomeIndividualProperty');
$subClass->setMainClass($mainClass);

$entityManager->getConnection()
  ->getConfiguration()
  ->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());

$entityManager->persist($mainClass);
$entityManager->flush();

Entities:

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * MainClass
 *
 * @Table(name="mainClass")
 * @Entity
 */
class MainClass
{
    /**
     * @var int
     *
     * @Column(name="id", type="integer")
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

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

    /**
     * @var \SubClass
     *
     * @OneToOne(targetEntity="SubClass", mappedBy="mainClass", cascade={"persist","remove"}, orphanRemoval=true)
     */
    protected $subClass;

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }
    public function setName($name)
    {
        $this->name = $name;
    }

    public function setSubClass(\SubClass $subClass)
    {
        $this->subClass = $subClass;

        return $this;
    }

    public function getSubClass()
    {
        return $this->subClass;
    }
}

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * SubClass
 *
 * @Table(name="subClass")
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discriminator", type="string", length=32)
 * @DiscriminatorMap({"subClassType1" = "SubClassType1", "subClassType2" = "SubClassType2"})
 * @Entity
 */
abstract class SubClass
{
    /**
     * @var \MainClass
     *
     * @Id
     * @GeneratedValue(strategy="NONE")
     * @OneToOne(targetEntity="MainClass", inversedBy="subClass")
     * @JoinColumns({
     *   @JoinColumn(name="id", referencedColumnName="id", onDelete="CASCADE")
     * })
     */
    protected $mainClass;

    /** @Column(type="string") */
    protected $someCommonProperty;


    public function setMainClass(\MainClass $mainClass)
    {
        $mainClass->setSubClass($this);
        $this->mainClass = $mainClass;

        return $this;
    }

    public function getMainClass()
    {
        return $this->mainClass;
    }

    public function getSomeCommonProperty()
    {
        return $this->someCommonProperty;
    }
    public function setSomeCommonProperty($someCommonProperty)
    {
        $this->someCommonProperty = $someCommonProperty;
    }
}

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * SubClassType1
 *
 * @Table(name="subclassType1")
 * @Entity
 */
class SubClassType1 extends SubClass
{

    /** @Column(type="string") */
    protected $someIndividualProperty;

    public function getSomeIndividualProperty()
    {
        return $this->someIndividualProperty;
    }
    public function setSomeIndividualProperty($someIndividualProperty)
    {
        $this->someIndividualProperty = $someIndividualProperty;
    }
}

Expected behavior

Inherited class should be added UnitOfWork::entityIdentifiers array, the correct number of prepared statements parameters should be provided, and an error shouldn't occur.

@SenseException
Copy link
Member

Thank you for reporting this issue. Can you please create a PR containing a failing test for this? I assume this should be able with UnitOfWork::getEntityIdentifier().

@NotionCommotion
Copy link
Author

Hi SenseException. Not really sure about PR, but just uploaded the scripts to https://github.com/NotionCommotion/doctrine_github_issue_7707. In the root directory, just type "php create.php", and you will see the error. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants