Search code examples
phpsymfonydoctrine-ormmany-to-manysqlexception

doctrine 2 mapping - many to many thows exception when trying to persist owning side


I'm new to doctrine and I got stuck. Any help will be appreciated. I created two entities: Task and Group with a many to many relation with group being the owning side. I tried to persist them. Task gets persisted, but group trows an SQL exception.

Here is the code for Task.php:

<?php

namespace AppBundle\Entity;

/**
 * Task
 */
class Task
{
/**
 * @var integer
 */
private $id;

/**
 * @var string
 */
private $task;

/**
 * @var \DateTime
 */
private $dueDate;

/**
 * @var \Doctrine\Common\Collections\Collection
 */
private $groups;

/**
 * Constructor
 */
public function __construct()
{
    $this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}

/**
 * Get id
 *
 * @return integer
 */
public function getId()
{
    return $this->id;
}

/**
 * Set task
 *
 * @param string $task
 *
 * @return Task
 */
public function setTask($task)
{
    $this->task = $task;

    return $this;
}

/**
 * Get task
 *
 * @return string
 */
public function getTask()
{
    return $this->task;
}

/**
 * Set dueDate
 *
 * @param \DateTime $dueDate
 *
 * @return Task
 */
public function setDueDate($dueDate)
{
    $this->dueDate = $dueDate;

    return $this;
}

/**
 * Get dueDate
 *
 * @return \DateTime
 */
public function getDueDate()
{
    return $this->dueDate;
}

/**
 * Add group
 *
 * @param \AppBundle\Entity\Group $group
 *
 * @return Task
 */
public function addGroup(\AppBundle\Entity\Group $group)
{
    $this->groups[] = $group;

    return $this;
}

/**
 * Remove group
 *
 * @param \AppBundle\Entity\Group $group
 */
public function removeGroup(\AppBundle\Entity\Group $group)
{
    $this->groups->removeElement($group);
}

/**
 * Get groups
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getGroups()
{
    return $this->groups;
}
}

Task mapping

AppBundle\Entity\Task:
  type: entity
  table: task
  id:
   id:
     type: integer
     generator: { strategy: AUTO }
  fields:
    task:
      type: string
      length: 256
    dueDate:
      type: date
   manyToMany:
    groups:
      targetEntity: Group
       mappedBy: tasks

Group.php

    <?php

    namespace AppBundle\Entity;

    /**
     * Group
     */
    class Group
    {
        /**
         * @var integer
         */
        private $id;

        /**
         * @var string
         */
        private $name;


        /**
         * Get id
         *
         * @return integer
         */
        public function getId()
        {
            return $this->id;
        }

        /**
         * Set name
         *
         * @param string $name
         *
         * @return Group
         */
        public function setName($name)
        {
            $this->name = $name;

            return $this;
        }

        /**
         * Get name
         *
         * @return string
         */
        public function getName()
        {
            return $this->name;
        }
        /**
         * @var \Doctrine\Common\Collections\Collection
         */
        private $tasks;

        /**
         * Constructor
         */
        public function __construct()
        {
            $this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
        }

        /**
         * Add task
         *
         * @param \AppBundle\Entity\Task $task
         *
         * @return Group
         */
        public function addTask(\AppBundle\Entity\Task $task)
        {
            $this->tasks[] = $task;

            return $this;
        }

        /**
         * Add tasks
         *
         * @param array
         *
         * @return Group
         */
        public function addTasks(array $tasks)
        {
            foreach ($tasks as $task) {
                if (is_a($task, 'AppBundle\Entity\Task')) {
                    $this->tasks[] = $task;
                }
            }
            return $this;
        }

        /**
         * Remove task
         *
         * @param \AppBundle\Entity\Task $task
         */
        public function removeTask(\AppBundle\Entity\Task $task)
        {
            $this->tasks->removeElement($task);
        }

        /**
         * Get tasks
         *
         * @return \Doctrine\Common\Collections\Collection
         */
        public function getTasks()
        {
            return $this->tasks;
        }
    }

Group mapping

 AppBundle\Entity\Group:
      type: entity
      table: group
      id:
        id:
          type: integer
          generator: { strategy: AUTO }
      fields:
        name:
          type: string
      manyToMany:
        tasks:
          targetEntity: Task
          inversedBy: groups
          cascade: ['persist', 'remove']

The controller

class DoctrineController extends Controller
{
    /**
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function setupAction()
    {
        $group = new Group();
        $em = $this->getDoctrine()->getManager();

        $tasks = $em->getRepository('AppBundle:Task')->findAll();
        $group->setName('personal');
        $group->addTasks($tasks);
        $em->persist($group);
        $em->flush();

        echo 'success';

        return $this->render('AppBundle:Doctrine:setup.html.twig', array(
        ));
    }
}

The exception:

An exception occurred while executing 'INSERT INTO group (name) VALUES (?)' with params ["personal"]:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'group (name) VALUES ('personal')' at line 1 

I think it has to do with table constraints, but I don't know how to fix it. I'm pretty sure there's a flaw in my logic. If anyone can point me into the right direction with a quick-fix and an explanation/link to an article as to why this works like it does, I'll be very grateful.


Solution

  • From the Symfony documentation http://symfony.com/doc/current/book/doctrine.html#add-mapping-information

    Be careful that your class name and properties aren't mapped to a protected SQL keyword (such as group or user). For example, if your entity class name is Group, then, by default, your table name will be group, which will cause an SQL error in some engines. See Doctrine's Reserved SQL keywords documentation on how to properly escape these names. Alternatively, if you're free to choose your database schema, simply map to a different table name or column name. See Doctrine's Creating Classes for the Database and Property Mapping documentation.

    Check the Doctrine documentation for advice on how to quote these reserved words: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#quoting-reserved-words

    But after all it is adviced to not use reserved words in your class or class attribute names.