Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-1799

Doctrine's Reverse Engineering 1-n (one to many) association misunderstood as 1-1 (one to one)

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: 2.1.6
    • Fix Version/s: 2.1.7, 2.2.3
    • Component/s: ORM
    • Security Level: All
    • Labels:
      None
    • Environment:
      MAC OS X 10.6.8, Symfony 2.0.12, PHP 5.3.6, mysql server 5.5.9

      Description

      I found an odd behaviour of Doctrine's reverse engineering process, just create two simple tables tied by a simple 1-n relationship, take a look at the snap of the folowing SQL code:

          SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
          SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
          SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
          
          DROP SCHEMA IF EXISTS `ACME` ;
          CREATE SCHEMA IF NOT EXISTS `ACME` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
          USE `ACME` ;
          
          -- -----------------------------------------------------
          -- Table `ACME`.`task`
          -- -----------------------------------------------------
          DROP TABLE IF EXISTS `ACME`.`task` ;
          
          CREATE  TABLE IF NOT EXISTS `ACME`.`task` (
            `id_task` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
            `description` VARCHAR(45) NULL ,
            PRIMARY KEY (`id_task`) )
          ENGINE = InnoDB;
          
          
          -- -----------------------------------------------------
          -- Table `ACME`.`tag`
          -- -----------------------------------------------------
          DROP TABLE IF EXISTS `ACME`.`tag` ;
          
          CREATE  TABLE IF NOT EXISTS `ACME`.`tag` (
            `id_tag` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
            `name` VARCHAR(50) NULL ,
            `task_id` INT UNSIGNED NOT NULL ,
            PRIMARY KEY (`id_tag`) ,
            INDEX `fk_tag_task` (`task_id` ASC) ,
            CONSTRAINT `fk_tag_task`
              FOREIGN KEY (`task_id` )
              REFERENCES `ACME`.`task` (`id_task` )
              ON DELETE NO ACTION
              ON UPDATE NO ACTION)
          ENGINE = InnoDB;
          
          
          
          SET SQL_MODE=@OLD_SQL_MODE;
          SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
          SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
      

      I have a Symfony2 netbeans project at

      > /Applications/MAMP/htdocs/Acme

      and from that location, according to

      > http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

      in a terminal I did:

          $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force
          Processing entity "Tag"
          Processing entity "Task"
          
          Exporting "yml" mapping information to "/Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine"
          
          $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:import Acme\TaskBundle yml
          Importing mapping information from "default" entity manager
            > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Tag.orm.yml
            > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Task.orm.yml
          
          $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:generate:entities Acme\TaskBundle
          Generating entities for bundle "AcmeTaskBundle"
            > backing up Tag.php to Tag.php~
            > generating Acme\TaskBundle\Entity\Tag
            > backing up Task.php to Task.php~
            > generating Acme\TaskBundle\Entity\Task
      

      The fact is that it only seems ok, because if you take a look at "Tag.orm.yml":

      Tag.orm.yml
          Acme\TaskBundle\Entity\Tag:
            type: entity
            table: tag
            fields:
              idTag:
                id: true
                type: integer
                unsigned: false
                nullable: false
                column: id_tag
                generator:
                  strategy: IDENTITY
              name:
                type: string
                length: 50
                fixed: false
                nullable: true
            oneToOne:
              task:
                targetEntity: Task
                cascade: {  }
                mappedBy: null
                inversedBy: null
                joinColumns:
                  task_id:
                    referencedColumnName: id_task
                orphanRemoval: false
            lifecycleCallbacks: {  }
      

      It created a *oneToOne* relationship and not a *oneToMany* !

      If you need any more confirmation, here are **Task.php** and **Tag.php**:

      **Task.php**

      Task.php
          <?php
          
          namespace Acme\TaskBundle\Entity;
          
          use Doctrine\ORM\Mapping as ORM;
          
          /**
           * Acme\TaskBundle\Entity\Task
           */
          class Task
          {
              /**
               * @var integer $idTask
               */
              private $idTask;
          
              /**
               * @var string $description
               */
              private $description;
          
          
              /**
               * Get idTask
               *
               * @return integer 
               */
              public function getIdTask()
              {
                  return $this->idTask;
              }
          
              /**
               * Set description
               *
               * @param string $description
               */
              public function setDescription($description)
              {
                  $this->description = $description;
              }
          
              /**
               * Get description
               *
               * @return string 
               */
              public function getDescription()
              {
                  return $this->description;
              }
          }
      
      Tag.php
      ***Tag.php***
      
          <?php
          
          namespace Acme\TaskBundle\Entity;
          
          use Doctrine\ORM\Mapping as ORM;
          
          /**
           * Acme\TaskBundle\Entity\Tag
           */
          class Tag
          {
              /**
               * @var integer $idTag
               */
              private $idTag;
          
              /**
               * @var string $name
               */
              private $name;
          
              /**
               * @var Acme\TaskBundle\Entity\Task
               */
              private $task;
          
          
              /**
               * Get idTag
               *
               * @return integer 
               */
              public function getIdTag()
              {
                  return $this->idTag;
              }
          
              /**
               * Set name
               *
               * @param string $name
               */
              public function setName($name)
              {
                  $this->name = $name;
              }
          
              /**
               * Get name
               *
               * @return string 
               */
              public function getName()
              {
                  return $this->name;
              }
          
              /**
               * Set task
               *
               * @param Acme\TaskBundle\Entity\Task $task
               */
              public function setTask(\Acme\TaskBundle\Entity\Task $task)
              {
                  $this->task = $task;
              }
          
              /**
               * Get task
               *
               * @return Acme\TaskBundle\Entity\Task 
               */
              public function getTask()
              {
                  return $this->task;
              }
          }
      

      linuxatico

        Activity

        simone adami created issue -
        Hide
        simone adami added a comment -

        This problem is encountered only in this case, 1-1 and n-m relationship are handled in the right way, has anyone else faced this problem too?

        linuxatico

        Show
        simone adami added a comment - This problem is encountered only in this case, 1-1 and n-m relationship are handled in the right way, has anyone else faced this problem too? linuxatico
        simone adami made changes -
        Field Original Value New Value
        Description I found an odd behaviour of Doctrine's reverse engineering process, just create two simple tables tied by a simple 1-n relationship, take a look at the snap of the folowing SQL code:

            SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
            SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
            SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
            
            DROP SCHEMA IF EXISTS `ACME` ;
            CREATE SCHEMA IF NOT EXISTS `ACME` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
            USE `ACME` ;
            
            -- -----------------------------------------------------
            -- Table `ACME`.`task`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`task` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`task` (
              `id_task` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `description` VARCHAR(45) NULL ,
              PRIMARY KEY (`id_task`) )
            ENGINE = InnoDB;
            
            
            -- -----------------------------------------------------
            -- Table `ACME`.`tag`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`tag` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`tag` (
              `id_tag` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `name` VARCHAR(50) NULL ,
              `task_id` INT UNSIGNED NOT NULL ,
              PRIMARY KEY (`id_tag`) ,
              INDEX `fk_tag_task` (`task_id` ASC) ,
              CONSTRAINT `fk_tag_task`
                FOREIGN KEY (`task_id` )
                REFERENCES `ACME`.`task` (`id_task` )
                ON DELETE NO ACTION
                ON UPDATE NO ACTION)
            ENGINE = InnoDB;
            
            
            
            SET SQL_MODE=@OLD_SQL_MODE;
            SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
            SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;


        I have a Symfony2 netbeans project at

        > /Applications/MAMP/htdocs/Acme

         and from that location, according to

        > http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

         in a terminal I did:

            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force
            Processing entity "Tag"
            Processing entity "Task"
            
            Exporting "yml" mapping information to "/Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine"
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:import Acme\TaskBundle yml
            Importing mapping information from "default" entity manager
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Tag.orm.yml
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Task.orm.yml
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:generate:entities Acme\TaskBundle
            Generating entities for bundle "AcmeTaskBundle"
              > backing up Tag.php to Tag.php~
              > generating Acme\TaskBundle\Entity\Tag
              > backing up Task.php to Task.php~
              > generating Acme\TaskBundle\Entity\Task

        The fact is that it only seems ok, because if you take a look at "Tag.orm.yml":

            Acme\TaskBundle\Entity\Tag:
              type: entity
              table: tag
              fields:
                idTag:
                  id: true
                  type: integer
                  unsigned: false
                  nullable: false
                  column: id_tag
                  generator:
                    strategy: IDENTITY
                name:
                  type: string
                  length: 50
                  fixed: false
                  nullable: true
              oneToOne:
                task:
                  targetEntity: Task
                  cascade: { }
                  mappedBy: null
                  inversedBy: null
                  joinColumns:
                    task_id:
                      referencedColumnName: id_task
                  orphanRemoval: false
              lifecycleCallbacks: { }

        It created a **oneToOne** relationship and not a **oneToMany** !

        If you need any more confirmation, here are ***Task.php*** and ***Tag.php***:

        ***Task.php***

            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Task
             */
            class Task
            {
                /**
                 * @var integer $idTask
                 */
                private $idTask;
            
                /**
                 * @var string $description
                 */
                private $description;
            
            
                /**
                 * Get idTask
                 *
                 * @return integer
                 */
                public function getIdTask()
                {
                    return $this->idTask;
                }
            
                /**
                 * Set description
                 *
                 * @param string $description
                 */
                public function setDescription($description)
                {
                    $this->description = $description;
                }
            
                /**
                 * Get description
                 *
                 * @return string
                 */
                public function getDescription()
                {
                    return $this->description;
                }
            }


        ***Tag.php***

            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Tag
             */
            class Tag
            {
                /**
                 * @var integer $idTag
                 */
                private $idTag;
            
                /**
                 * @var string $name
                 */
                private $name;
            
                /**
                 * @var Acme\TaskBundle\Entity\Task
                 */
                private $task;
            
            
                /**
                 * Get idTag
                 *
                 * @return integer
                 */
                public function getIdTag()
                {
                    return $this->idTag;
                }
            
                /**
                 * Set name
                 *
                 * @param string $name
                 */
                public function setName($name)
                {
                    $this->name = $name;
                }
            
                /**
                 * Get name
                 *
                 * @return string
                 */
                public function getName()
                {
                    return $this->name;
                }
            
                /**
                 * Set task
                 *
                 * @param Acme\TaskBundle\Entity\Task $task
                 */
                public function setTask(\Acme\TaskBundle\Entity\Task $task)
                {
                    $this->task = $task;
                }
            
                /**
                 * Get task
                 *
                 * @return Acme\TaskBundle\Entity\Task
                 */
                public function getTask()
                {
                    return $this->task;
                }
            }

        linuxatico
        I found an odd behaviour of Doctrine's reverse engineering process, just create two simple tables tied by a simple 1-n relationship, take a look at the snap of the folowing SQL code:
        {code:sql:title=DB.sql|borderStyle=solid}
            SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
            SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
            SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
            
            DROP SCHEMA IF EXISTS `ACME` ;
            CREATE SCHEMA IF NOT EXISTS `ACME` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
            USE `ACME` ;
            
            -- -----------------------------------------------------
            -- Table `ACME`.`task`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`task` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`task` (
              `id_task` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `description` VARCHAR(45) NULL ,
              PRIMARY KEY (`id_task`) )
            ENGINE = InnoDB;
            
            
            -- -----------------------------------------------------
            -- Table `ACME`.`tag`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`tag` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`tag` (
              `id_tag` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `name` VARCHAR(50) NULL ,
              `task_id` INT UNSIGNED NOT NULL ,
              PRIMARY KEY (`id_tag`) ,
              INDEX `fk_tag_task` (`task_id` ASC) ,
              CONSTRAINT `fk_tag_task`
                FOREIGN KEY (`task_id` )
                REFERENCES `ACME`.`task` (`id_task` )
                ON DELETE NO ACTION
                ON UPDATE NO ACTION)
            ENGINE = InnoDB;
            
            
            
            SET SQL_MODE=@OLD_SQL_MODE;
            SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
            SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
        {code}

        I have a Symfony2 netbeans project at

        > /Applications/MAMP/htdocs/Acme

         and from that location, according to

        > http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

         in a terminal I did:
        {code}
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force
            Processing entity "Tag"
            Processing entity "Task"
            
            Exporting "yml" mapping information to "/Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine"
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:import Acme\TaskBundle yml
            Importing mapping information from "default" entity manager
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Tag.orm.yml
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Task.orm.yml
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:generate:entities Acme\TaskBundle
            Generating entities for bundle "AcmeTaskBundle"
              > backing up Tag.php to Tag.php~
              > generating Acme\TaskBundle\Entity\Tag
              > backing up Task.php to Task.php~
              > generating Acme\TaskBundle\Entity\Task
        {code}
        The fact is that it only seems ok, because if you take a look at "Tag.orm.yml":
        {code:title=Tag.orm.yml|borderStyle=solid}
            Acme\TaskBundle\Entity\Tag:
              type: entity
              table: tag
              fields:
                idTag:
                  id: true
                  type: integer
                  unsigned: false
                  nullable: false
                  column: id_tag
                  generator:
                    strategy: IDENTITY
                name:
                  type: string
                  length: 50
                  fixed: false
                  nullable: true
              oneToOne:
                task:
                  targetEntity: Task
                  cascade: { }
                  mappedBy: null
                  inversedBy: null
                  joinColumns:
                    task_id:
                      referencedColumnName: id_task
                  orphanRemoval: false
              lifecycleCallbacks: { }
        {code}
        It created a **oneToOne** relationship and not a **oneToMany** !

        If you need any more confirmation, here are ***Task.php*** and ***Tag.php***:

        ***Task.php***
        {code:title=Task.php|borderStyle=solid}
            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Task
             */
            class Task
            {
                /**
                 * @var integer $idTask
                 */
                private $idTask;
            
                /**
                 * @var string $description
                 */
                private $description;
            
            
                /**
                 * Get idTask
                 *
                 * @return integer
                 */
                public function getIdTask()
                {
                    return $this->idTask;
                }
            
                /**
                 * Set description
                 *
                 * @param string $description
                 */
                public function setDescription($description)
                {
                    $this->description = $description;
                }
            
                /**
                 * Get description
                 *
                 * @return string
                 */
                public function getDescription()
                {
                    return $this->description;
                }
            }

        {code:title=Tag.php|borderStyle=solid}
        ***Tag.php***

            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Tag
             */
            class Tag
            {
                /**
                 * @var integer $idTag
                 */
                private $idTag;
            
                /**
                 * @var string $name
                 */
                private $name;
            
                /**
                 * @var Acme\TaskBundle\Entity\Task
                 */
                private $task;
            
            
                /**
                 * Get idTag
                 *
                 * @return integer
                 */
                public function getIdTag()
                {
                    return $this->idTag;
                }
            
                /**
                 * Set name
                 *
                 * @param string $name
                 */
                public function setName($name)
                {
                    $this->name = $name;
                }
            
                /**
                 * Get name
                 *
                 * @return string
                 */
                public function getName()
                {
                    return $this->name;
                }
            
                /**
                 * Set task
                 *
                 * @param Acme\TaskBundle\Entity\Task $task
                 */
                public function setTask(\Acme\TaskBundle\Entity\Task $task)
                {
                    $this->task = $task;
                }
            
                /**
                 * Get task
                 *
                 * @return Acme\TaskBundle\Entity\Task
                 */
                public function getTask()
                {
                    return $this->task;
                }
            }
        {code}
        linuxatico
        simone adami made changes -
        Description I found an odd behaviour of Doctrine's reverse engineering process, just create two simple tables tied by a simple 1-n relationship, take a look at the snap of the folowing SQL code:
        {code:sql:title=DB.sql|borderStyle=solid}
            SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
            SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
            SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
            
            DROP SCHEMA IF EXISTS `ACME` ;
            CREATE SCHEMA IF NOT EXISTS `ACME` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
            USE `ACME` ;
            
            -- -----------------------------------------------------
            -- Table `ACME`.`task`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`task` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`task` (
              `id_task` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `description` VARCHAR(45) NULL ,
              PRIMARY KEY (`id_task`) )
            ENGINE = InnoDB;
            
            
            -- -----------------------------------------------------
            -- Table `ACME`.`tag`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`tag` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`tag` (
              `id_tag` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `name` VARCHAR(50) NULL ,
              `task_id` INT UNSIGNED NOT NULL ,
              PRIMARY KEY (`id_tag`) ,
              INDEX `fk_tag_task` (`task_id` ASC) ,
              CONSTRAINT `fk_tag_task`
                FOREIGN KEY (`task_id` )
                REFERENCES `ACME`.`task` (`id_task` )
                ON DELETE NO ACTION
                ON UPDATE NO ACTION)
            ENGINE = InnoDB;
            
            
            
            SET SQL_MODE=@OLD_SQL_MODE;
            SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
            SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
        {code}

        I have a Symfony2 netbeans project at

        > /Applications/MAMP/htdocs/Acme

         and from that location, according to

        > http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

         in a terminal I did:
        {code}
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force
            Processing entity "Tag"
            Processing entity "Task"
            
            Exporting "yml" mapping information to "/Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine"
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:import Acme\TaskBundle yml
            Importing mapping information from "default" entity manager
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Tag.orm.yml
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Task.orm.yml
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:generate:entities Acme\TaskBundle
            Generating entities for bundle "AcmeTaskBundle"
              > backing up Tag.php to Tag.php~
              > generating Acme\TaskBundle\Entity\Tag
              > backing up Task.php to Task.php~
              > generating Acme\TaskBundle\Entity\Task
        {code}
        The fact is that it only seems ok, because if you take a look at "Tag.orm.yml":
        {code:title=Tag.orm.yml|borderStyle=solid}
            Acme\TaskBundle\Entity\Tag:
              type: entity
              table: tag
              fields:
                idTag:
                  id: true
                  type: integer
                  unsigned: false
                  nullable: false
                  column: id_tag
                  generator:
                    strategy: IDENTITY
                name:
                  type: string
                  length: 50
                  fixed: false
                  nullable: true
              oneToOne:
                task:
                  targetEntity: Task
                  cascade: { }
                  mappedBy: null
                  inversedBy: null
                  joinColumns:
                    task_id:
                      referencedColumnName: id_task
                  orphanRemoval: false
              lifecycleCallbacks: { }
        {code}
        It created a **oneToOne** relationship and not a **oneToMany** !

        If you need any more confirmation, here are ***Task.php*** and ***Tag.php***:

        ***Task.php***
        {code:title=Task.php|borderStyle=solid}
            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Task
             */
            class Task
            {
                /**
                 * @var integer $idTask
                 */
                private $idTask;
            
                /**
                 * @var string $description
                 */
                private $description;
            
            
                /**
                 * Get idTask
                 *
                 * @return integer
                 */
                public function getIdTask()
                {
                    return $this->idTask;
                }
            
                /**
                 * Set description
                 *
                 * @param string $description
                 */
                public function setDescription($description)
                {
                    $this->description = $description;
                }
            
                /**
                 * Get description
                 *
                 * @return string
                 */
                public function getDescription()
                {
                    return $this->description;
                }
            }

        {code:title=Tag.php|borderStyle=solid}
        ***Tag.php***

            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Tag
             */
            class Tag
            {
                /**
                 * @var integer $idTag
                 */
                private $idTag;
            
                /**
                 * @var string $name
                 */
                private $name;
            
                /**
                 * @var Acme\TaskBundle\Entity\Task
                 */
                private $task;
            
            
                /**
                 * Get idTag
                 *
                 * @return integer
                 */
                public function getIdTag()
                {
                    return $this->idTag;
                }
            
                /**
                 * Set name
                 *
                 * @param string $name
                 */
                public function setName($name)
                {
                    $this->name = $name;
                }
            
                /**
                 * Get name
                 *
                 * @return string
                 */
                public function getName()
                {
                    return $this->name;
                }
            
                /**
                 * Set task
                 *
                 * @param Acme\TaskBundle\Entity\Task $task
                 */
                public function setTask(\Acme\TaskBundle\Entity\Task $task)
                {
                    $this->task = $task;
                }
            
                /**
                 * Get task
                 *
                 * @return Acme\TaskBundle\Entity\Task
                 */
                public function getTask()
                {
                    return $this->task;
                }
            }
        {code}
        linuxatico
        I found an odd behaviour of Doctrine's reverse engineering process, just create two simple tables tied by a simple 1-n relationship, take a look at the snap of the folowing SQL code:
        {code:sql:title=DB.sql|borderStyle=solid}
            SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
            SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
            SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
            
            DROP SCHEMA IF EXISTS `ACME` ;
            CREATE SCHEMA IF NOT EXISTS `ACME` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
            USE `ACME` ;
            
            -- -----------------------------------------------------
            -- Table `ACME`.`task`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`task` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`task` (
              `id_task` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `description` VARCHAR(45) NULL ,
              PRIMARY KEY (`id_task`) )
            ENGINE = InnoDB;
            
            
            -- -----------------------------------------------------
            -- Table `ACME`.`tag`
            -- -----------------------------------------------------
            DROP TABLE IF EXISTS `ACME`.`tag` ;
            
            CREATE TABLE IF NOT EXISTS `ACME`.`tag` (
              `id_tag` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
              `name` VARCHAR(50) NULL ,
              `task_id` INT UNSIGNED NOT NULL ,
              PRIMARY KEY (`id_tag`) ,
              INDEX `fk_tag_task` (`task_id` ASC) ,
              CONSTRAINT `fk_tag_task`
                FOREIGN KEY (`task_id` )
                REFERENCES `ACME`.`task` (`id_task` )
                ON DELETE NO ACTION
                ON UPDATE NO ACTION)
            ENGINE = InnoDB;
            
            
            
            SET SQL_MODE=@OLD_SQL_MODE;
            SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
            SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
        {code}

        I have a Symfony2 netbeans project at

        > /Applications/MAMP/htdocs/Acme

         and from that location, according to

        > http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

         in a terminal I did:
        {code}
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force
            Processing entity "Tag"
            Processing entity "Task"
            
            Exporting "yml" mapping information to "/Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine"
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:import Acme\TaskBundle yml
            Importing mapping information from "default" entity manager
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Tag.orm.yml
              > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Task.orm.yml
            
            $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:generate:entities Acme\TaskBundle
            Generating entities for bundle "AcmeTaskBundle"
              > backing up Tag.php to Tag.php~
              > generating Acme\TaskBundle\Entity\Tag
              > backing up Task.php to Task.php~
              > generating Acme\TaskBundle\Entity\Task
        {code}
        The fact is that it only seems ok, because if you take a look at "Tag.orm.yml":
        {code:title=Tag.orm.yml|borderStyle=solid}
            Acme\TaskBundle\Entity\Tag:
              type: entity
              table: tag
              fields:
                idTag:
                  id: true
                  type: integer
                  unsigned: false
                  nullable: false
                  column: id_tag
                  generator:
                    strategy: IDENTITY
                name:
                  type: string
                  length: 50
                  fixed: false
                  nullable: true
              oneToOne:
                task:
                  targetEntity: Task
                  cascade: { }
                  mappedBy: null
                  inversedBy: null
                  joinColumns:
                    task_id:
                      referencedColumnName: id_task
                  orphanRemoval: false
              lifecycleCallbacks: { }
        {code}
        It created a **oneToOne** relationship and not a **oneToMany** !

        If you need any more confirmation, here are ***Task.php*** and ***Tag.php***:

        ***Task.php***
        {code:title=Task.php|borderStyle=solid}
            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Task
             */
            class Task
            {
                /**
                 * @var integer $idTask
                 */
                private $idTask;
            
                /**
                 * @var string $description
                 */
                private $description;
            
            
                /**
                 * Get idTask
                 *
                 * @return integer
                 */
                public function getIdTask()
                {
                    return $this->idTask;
                }
            
                /**
                 * Set description
                 *
                 * @param string $description
                 */
                public function setDescription($description)
                {
                    $this->description = $description;
                }
            
                /**
                 * Get description
                 *
                 * @return string
                 */
                public function getDescription()
                {
                    return $this->description;
                }
            }
        {code}

        {code:title=Tag.php|borderStyle=solid}
        ***Tag.php***

            <?php
            
            namespace Acme\TaskBundle\Entity;
            
            use Doctrine\ORM\Mapping as ORM;
            
            /**
             * Acme\TaskBundle\Entity\Tag
             */
            class Tag
            {
                /**
                 * @var integer $idTag
                 */
                private $idTag;
            
                /**
                 * @var string $name
                 */
                private $name;
            
                /**
                 * @var Acme\TaskBundle\Entity\Task
                 */
                private $task;
            
            
                /**
                 * Get idTag
                 *
                 * @return integer
                 */
                public function getIdTag()
                {
                    return $this->idTag;
                }
            
                /**
                 * Set name
                 *
                 * @param string $name
                 */
                public function setName($name)
                {
                    $this->name = $name;
                }
            
                /**
                 * Get name
                 *
                 * @return string
                 */
                public function getName()
                {
                    return $this->name;
                }
            
                /**
                 * Set task
                 *
                 * @param Acme\TaskBundle\Entity\Task $task
                 */
                public function setTask(\Acme\TaskBundle\Entity\Task $task)
                {
                    $this->task = $task;
                }
            
                /**
                 * Get task
                 *
                 * @return Acme\TaskBundle\Entity\Task
                 */
                public function getTask()
                {
                    return $this->task;
                }
            }
        {code}
        linuxatico
        Hide
        simone adami added a comment - - edited

        Hi all,
        I wanna give the Doctrine community my full support to help fixing this bug, but I need someone who can give me an answer.....
        I couldn't figure out in the source code which is the method executed when given the command

        $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force

        I will keep on looking for it, but some help will be appreciated,

        linuxatico

        Show
        simone adami added a comment - - edited Hi all, I wanna give the Doctrine community my full support to help fixing this bug, but I need someone who can give me an answer..... I couldn't figure out in the source code which is the method executed when given the command $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force I will keep on looking for it, but some help will be appreciated, linuxatico
        Hide
        simone adami added a comment -

        Found in vendor/doctrine/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php
        I'll see what I can do.

        linuxatico

        Show
        simone adami added a comment - Found in vendor/doctrine/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php I'll see what I can do. linuxatico
        Hide
        simone adami added a comment -

        Even if I keep being ignored, I want to report a very useful discovery about this annoying bug: it's 100% related to the YAML conversion, because if you execute the first command

         $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert xml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force

        Using XML instead of YML it works in the expected way. I wonder if the author of this code have written a unit test before integrating this function in the official release of Doctrine.... (ironic question)

        linuxatico

        Show
        simone adami added a comment - Even if I keep being ignored, I want to report a very useful discovery about this annoying bug: it's 100% related to the YAML conversion, because if you execute the first command $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert xml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force Using XML instead of YML it works in the expected way. I wonder if the author of this code have written a unit test before integrating this function in the official release of Doctrine.... (ironic question) linuxatico
        Hide
        Benjamin Eberlei added a comment -

        This case was indeed not unit-tested, many-to-one and one-to-one were handled the same in YAML Exporter. No need to get picky about it though, we are investing our free time here.

        Show
        Benjamin Eberlei added a comment - This case was indeed not unit-tested, many-to-one and one-to-one were handled the same in YAML Exporter. No need to get picky about it though, we are investing our free time here.
        Benjamin Eberlei made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Fix Version/s 2.1.7 [ 10198 ]
        Fix Version/s 2.2.3 [ 10196 ]
        Resolution Fixed [ 1 ]
        Benjamin Eberlei made changes -
        Workflow jira [ 13663 ] jira-feedback [ 15334 ]
        Benjamin Eberlei made changes -
        Workflow jira-feedback [ 15334 ] jira-feedback2 [ 17198 ]
        Benjamin Eberlei made changes -
        Workflow jira-feedback2 [ 17198 ] jira-feedback3 [ 19453 ]

        This list may be incomplete, as errors occurred whilst retrieving source from linked applications:

        • Request to http://www.doctrine-project.org/fisheye/ failed: Error in remote call to 'FishEye 0 (http://www.doctrine-project.org/fisheye/)' (http://www.doctrine-project.org/fisheye) [AbstractRestCommand{path='/rest-service-fe/search-v1/crossRepositoryQuery', params={query=DDC-1799, expand=changesets[0:20].revisions[0:29],reviews}, methodType=GET}] : Received status code 503 (Service Temporarily Unavailable)

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            simone adami
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: