23
votes

After I successfuly created TaskBundle with One-to-Many relation between category and tasks, now I'm trying to create a new TaskBundle with Many-to-Many relation. I get also problem with checking checkbox in this relation, but now it is not a primary problem (maybe after solving this). I deleted all tables, which is TaskBundle using and trying to create a new, but here is problem (description at the bottom).

My Task object:

<?php

namespace Acme\TaskBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="tasks") 
 */
class Task
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;              

    /**
     * @ORM\Column(type="string", length=200)    
     * @Assert\NotBlank(
     *      message = "Task is empty"      
     * )    
     * @Assert\Length(
     *      min = "3",
     *      minMessage = "Task is too short"         
     * )     
     */     
    protected $task;

    /**
     * @ORM\Column(type="datetime")    
     * @Assert\NotBlank()
     * @Assert\Type("\DateTime")
     */
    protected $dueDate;

    /**
     * @Assert\True(message = "You have to agree.")    
     */         
    protected $accepted;

    /**
     * @ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
     * @ORM\JoinTable(name="categories")                         
     */
    protected $category;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->category = 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 category
     *
     * @param \Acme\TaskBundle\Entity\Category $category
     * @return Task
     */
    public function addCategory(\Acme\TaskBundle\Entity\Category $category)
    {
        $this->category[] = $category;

        return $this;
    }

    /**
     * Remove category
     *
     * @param \Acme\TaskBundle\Entity\Category $category
     */
    public function removeCategory(\Acme\TaskBundle\Entity\Category $category)
    {
        $this->category->removeElement($category);
    }

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

and Category object

<?php

namespace Acme\TaskBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="categories") 
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")             
     */
    protected $id; 

    /**
     * @ORM\Column(type="string", length=200, unique=true)   
     * @Assert\NotNull(message="Categories cannot be empty", groups = {"adding"})                   
     */         
    protected $name;  

    /**
     * @ORM\ManyToMany(targetEntity="Task", mappedBy="category")
     */
    private $tasks;            


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

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

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

        return $this;
    }

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

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

        return $this;
    }

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

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

So, after i put doctrine:schema:update --force i'll get error: Table 'symfony.categories' already exists. I've tried to delete all caches, but same problem. Any idea?

There's only problem, if it is as m2m relation.

PS: I was looking for this problem at the Google, but no one answers at this problem. There were only questions, but not correct answers, where the problem is and how to solve it.

8
Maybe try doing a doctrine:schema:update --dump-sql and then running the SQL directly on the database and see if it could possibly be malformed SQL and it's just not throwing an exception? Long shot, but atleast that narrows it down a bit.Ken Hannel
@Ken Hannel: same message: [Doctrine\DBAL\Schema\SchemaException] The table with name 'symfony.categories' already exists. doctrine:schema:update [--complete] [--dump-sql] [--force] [--em[="..."]]Lkopo
unfortunately, the error occurs before the sql is completely created so dump-sql doesn't really help.Scott

8 Answers

19
votes

Looks like you already have table named "categories" in that database. Remove this line @ORM\JoinTable(name="categories") and try without it.

P.S. "Categories" is really a strange name for join table. You should probably follow some conventions and let doctrine name it. Common names for join tables are category_task or category2task as they are more self-explanatory. Nothing that important, just trying to suggest what I consider good practice.

7
votes

The thing is that doctrine doesn't understand how your existing table should be used. But you can give him some help.

You have two options :

  • You don't care about the existing table : simple, you can remove the @ORM\JoinTable(name="categories") annotation, and doctrine will create an other table etc.

  • You want to keep your existing table, which sounds pretty logical : you have to be more explicit in your annotation by adding @ORM\JoinColumn annotation.

Here is an example:

class 

<?php
...
/**
 * @ORM\Entity
 * @ORM\Table(name="tasks") 
 */
class Task
{
    ...
    /**
     * @ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
     * @ORM\JoinTable(name="categories",
     *       joinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")},
     *       inverseJoinColumns={@ORM\JoinColumn(name="task_id", referencedColumnName="id")})                         
     */
    protected $category;
    ...
}

and Category object

<?php
...    
/**
 * @ORM\Entity
 * @ORM\Table(name="categories") 
 */
class Category
{
    ...
    /**
     * @ORM\ManyToMany(targetEntity="Task", mappedBy="category")
     * @ORM\JoinTable(name="categories",
     *       joinColumns={@ORM\JoinColumn(name="task_id", referencedColumnName="id")},
     *       inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")})
     */
    private $tasks;            
...

Doing so, you will be able to keep your table without any doctrine error.

3
votes

My fix for this, as far as I can tell, was a case-sensitivity issue with table names. Doctrine let me create a Users and a users table but afterwards would die on migrations:diff or migrations:migrate .

I used the -vvv option to get more detail on this error message; it seems that the error happens when Doctrine is loading up its own internal representation of the current database's schema. So if your current database has table names that Doctrine doesn't understand (like two tables that are identical, case-insensitive) then it will blow up in this fashion.

Seems like most of the answers above assume that the error is in your code, but in my case it was in the database.

1
votes

in Symfony4.1 you can force the migration using the migration version

doctrine:migrations:execute <migration version>

ex

for migration version123456.php use

doctrine:migrations:execute 123456
1
votes

I got this error with 2 ManyToMany targeting the same entity (User in the exemple below).

To create the table name doctrine use the entity and target entity name.

So in my case it was trying to create two time the table thread_user

To debug this it's easy. Just use the '@ORM\JoinTable' annotation and specify the table name.

Here is a working exemple.

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\User")
 * @ORM\JoinTable(name="thread_participant")
 */
private $participants;

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\User")
 * @ORM\JoinTable(name="thread_recipient")
 */
private $recipients;
0
votes

there is another using the table name ,you can search it in your project . Maby be demo,I think it... sorry for my chinese english !

0
votes

Try to drop everything inside of your proxy directory.

0
votes

I fix same issue after check other entities on each bundles, be aware of this.