Zend/Doctrine can't perform ORM operations, table already exists - php

I inherited a project from another team and can't seem to do anything with the database. I am a total n00b with zend & doctrine, but the ORM tool seems straightforward enough; however, when trying to use it, I get the same error from orm:schema-tool:drop, orm:schema-tool:create, orm:schema-tool:update, etc.
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'mydb.alerts_residents' already exists.
My database has been created but has no tables. Other posts I've read lead me to conclude that this message is based on my Entity object definitions and annotations.
As you might suspect, alerts_residents is a join table that connects the Alert entity with the Resident entity in a many-to-many relationship. These are the only entities that reference this table, and they appear to do so correctly.
class Resident
{
/**
* #var ArrayCollection $zone
*
* #ORM\ManyToMany(targetEntity="Alert")
* #ORM\JoinTable(
* name="alerts_residents",
* joinColumns={#ORM\JoinColumn(name="resident_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="alert_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*/
protected $alerts;
class Alert
{
/**
* #var ArrayCollection $zone
*
* #ORM\ManyToMany(targetEntity="Resident")
* #ORM\JoinTable(
* name="alerts_residents",
* joinColumns={#ORM\JoinColumn(name="alert_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="resident_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*/
protected $residents;
There is no entity with #ORM\Table(name="alerts_residents"). Why am I getting this error?

You've got the many-to-many defined redundantly. M2M associations are a bit odd, because the join table has no entity of its own. As such, one side gets (more or less) arbitrarily chosen as the owning side, and that is the entity which gets the join table details. Your example has the #ORM\JoinTable annotation on both.
See http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#owning-and-inverse-side-on-a-manytomany-association

Related

ResultSetMappingBuilder and name conflict in mapper

I've got entity A with two ManyToOne relations. And both join columns with same name. When I am creating query based on entity A with ResultSetMappingBuilder and setting this entity to method addRootEntityFromClassMetada it results in InvalidArgumentException The column 'created_by' conflicts with another column in the mapper..
Here is quick sample for entity A
/**
* #var B
* #ManyToOne(targetEntity="B")
* #JoinColumn(name="created_by", referencedColumnName="id")
*/
private $a;
/**
* #var C
* #ManyToOne(targetEntity="C")
* #JoinColumn(name="created_by", referencedColumnName="id")
*/
private $b;
How can I avoid to conflict? I tried almost everything that I found on stack. But there are not many problems with this.
Doctrine 2.6.1
Thanks for you answers,
Michal

Doctrine using join table to return results not working Symfony2

I'm having difficulties using join table values to fetch results via Doctrine. I'm currently programming a CRM for a client, which implements projects with tasks and users.
My structure is as follows:
user table - contains all users.
tasks table - contains a list of tasks in a project
user_task table - the join table that dictates which users can perform which tasks.
I have created a join table in my entity like so:
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Task", inversedBy="user")
* #ORM\JoinTable(name="user_task",
* joinColumns={
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="task_id", referencedColumnName="id")
* }
* )
*/
protected $task;
And in my task entity:
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\User", mappedBy="task")
* #ORM\JoinTable(name="user_task")
*/
private $user;
My problem is, that on the front end of the CRM, the admin will change a task from the drop down which then should poll the database to grab the list of users that are able to perform that task. But because the user_stage table is not an entity in its own right, I do not know how to incorporate it in my doctrine queryBuilder.
I tried using a native query, where $taskId is passed in from the Controller:
$qb = $this->createNativeQuery('SELECT user.name FROM user JOIN user_task ON user_task.user_id = user.id WHERE user_task.task_id = '.$taskId);
$result = $qb->getResult();
But I just get the following error:
Undefined method 'createNativeQuery'. The method name must start with
either findBy or findOneBy!
I rarely use Native Queries so I am not sure what I'm doing wrong here. Is there any way of being able to perform the query I need without using NativeQuery, and just somehow accessing the join table by referencing it from both the User and Task entities?
Thank you
Michael
Don't use createNativeQuery where under $this you have Repository object.
Create method in repository class and call it there.

Symfony Association Mapping OneToOne and OneToMany to Same Entity

I have a View entity that represents the primary page record, and then I have an associated entity called ViewVersion which stores multiple versions of the entity as it's changed over time. The View entity sets the current "Published" ViewVersion in the VersionId field. This makes for a simple OneToOne association. But in some contexts I will also want to get all the versions associated with this View entity, e.g. if I want to allow the user to review older versions and revert back. So I will need another mapping which is a OneToMany. The first viewVersion will map to the active "published" version, and the second viewVersions will show all the versions.
Entity Definitions
/**
* #ORM\Entity
* #ORM\Table(name="view")
* #ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewRepository")
*/
class View extends Entity\Base {
/**
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", inversedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
* #ORM\JoinColumn(name="versionId", referencedColumnName="id")
*/
protected $viewVersion;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $versionId = NULL;
/**
* #ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="viewAll", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $viewVersions;
}
/**
* #ORM\Entity
* #ORM\Table(name="view_version")
* #ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewVersionRepository")
*/
class ViewVersion extends Entity\Base {
/**
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", mappedBy="viewVersion", cascade={"persist"})
*/
protected $view;
/**
* #ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="viewVersions")
* #ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $viewAll;
/**
* The primary view entity that this version belongs to.
* #ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
This "works" but is it recommended to have two associations with the same entity like this? Or is this a really bad idea?
The ViewVersion entity will reference a single View entity in both cases, but the mapped associations need two separate variables, e.g. View and ViewAll. I'm not exactly sure how the internals work for the association, and how the reference variable with the mapping is used.
Alternatively, I could get rid of the OneToOne association, and just set a ViewRepository function to get the current published version based on the versionId (just like the old mapped entity used to do with the getVersion()). That would work, but is it more internal overhead, because it would make two queries... or will Doctrine be smart enough to optimize this, just like it did with the getVersion().
NOTE:
These other answers are not complete.
References:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html
http://doctrine-orm.readthedocs.org/en/2.0.x/reference/association-mapping.html#one-to-many-bidirectional
Typically, I have found the best approach is to solve this in a different way.
One common pattern I have seen before is you use a single table to hold all records, and have an 'active' flag.
If your query to select the active one works like so:
SELECT * FROM table WHERE active = true ORDER BY updated_at DESC LIMIT 1;
Then enabling a new one becomes as simple as:
UPDATE table SET active = 1, updated_at = '<timestamp>' WHERE id = <new id>;
UPDATE table SET active = 0, updated_at = '<timestamp>' WHERE id = <old id>;
Your new page will be active as soon as the first query hits, and your second query will avoid any sort of weirdness as that row will already be no longer active.
If you have other models that depend on a consistent ID to reference, then another route which also maintains some sanity would be to have one table for the active entries (in whole, not in part) and then a second table with additional metadata to track versions.
The latter approach could be nicely handled via Doctrine's inheritance system (http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html) which would let you define the base View class, and then for the "ViewRevision" model, extend View and add a "Revised on" type timestamp.
Per the advice from #jmather I've decided this model is "okay", because I need a single View entity that other entities can access (e.g. Routing urls that point to a single View, i.e. "page").
I've changed the OneToOne relationship for View to be unidirectional only, because the ViewVersion already has an association back to the View via the other OneToMany (so it doesn't need two paths back).
This allows me to keep a simple method for $view->getPublished() handy and seems more logical.
/**
* #ORM\Entity
* #ORM\Table(name="view")
*/
class View extends Entity\Base {
/**
* This is a OneToOne Unidirectional association, just so that we can get the
* current published version easily, based on the publishedId.
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion")
* #ORM\JoinColumn(name="publishedId", referencedColumnName="id")
*/
protected $published;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $publishedId = NULL;
/**
* This is the regular OneToMany Bi-Directional Association, for all the versions.
* #ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $versions;
}
/**
* #ORM\Entity
* #ORM\Table(name="view_version")
*/
class ViewVersion extends Entity\Base {
/**
* #ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="versions")
* #ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $view;
/**
* The primary view entity that this version belongs to.
* #ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
However, I've discovered that as long as the $view->publishedId is set the view can't be deleted from the database because of foreign key constraints (even though it's uni-directional). So I have to break that foreign key link before removing. I think that's fine. I posted details about that here: Overlapping Entity Association causing Database Foreign Key Constraint Errors when Removing Entity

Doctrine 2, error inserting in table with foreign key

I'm very new using Doctrine, is the first project I work with it and I'm having an error while I try to insert a new user.
The thing is I've got a class User with a foreign key Country and when I try to insert a user Doctrine also try to insert the country, the country already exists so PDO launch an integrity constraint violation and Doctrine a Doctrine\DBAL\DBALException.
I know the annotation cascade={"persist"} makes the country entity to be written in the db, without it, doctrine launch another error:
A new entity was found through the relationship 'User#country' that was not configured to cascade persist operations for entity: Country#0000000078b1861f00007f935266d9fe. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Country#__toString()' to get a clue.
I've tried with all cascade options and only with persist and all the error above doesn't come up...
Is there something like cascade={"no-persist"} or something that tells doctrine the value of this attribute must be already inserted in table country???
Some code:
/**
* User
*
* #Table(name="user")
* #Entity
*/
class User {
...
/**
* #var Country
*
* #OneToOne(targetEntity="Country", cascade={"persist"})
* #JoinColumn(name="country", referencedColumnName="id")
*/
private $country
...
}
/**
* Country
*
* #Table(name="country")
* #Entity
*/
class Country {
...
/**
* #var integer
*
* #Column(name="id", type="integer")
* #Id
*/
private $id;
}
Any clue will be highly appreciated.
Thanks.
Put the cascade=persist back in.
You need to check the database to see if the country exists. Your insert with an existing country fails because the country object needs to be managed by the entity manager.
$country = $countryRepository->find($countryId);
if (!$country)
{
$country = new Country();
$entityManager->persist($country);
}
$user->setCountry($country);

What is the difference between inversedBy and mappedBy?

I am developing my application using Zend Framework 2 and Doctrine 2.
While writting annotations, I am unable to understand the difference between mappedBy and inversedBy.
When should I use mappedBy?
When should I use inversedBy?
When should I use neither?
Here is an example:
/**
*
* #ORM\OneToOne(targetEntity="\custMod\Entity\Person", mappedBy="customer")
* #ORM\JoinColumn(name="personID", referencedColumnName="id")
*/
protected $person;
/**
*
* #ORM\OneToOne(targetEntity="\Auth\Entity\User")
* #ORM\JoinColumn(name="userID", referencedColumnName="id")
*/
protected $user;
/**
*
* #ORM\ManyToOne (targetEntity="\custMod\Entity\Company", inversedBy="customer")
* #ORM\JoinColumn (name="companyID", referencedColumnName="id")
*/
protected $company;
I did a quick search and found the following, but I am still confused:
example 1
example 2
example 3
mappedBy has to be specified on the inversed side of a (bidirectional) association
inversedBy has to be specified on the owning side of a (bidirectional) association
from doctrine documentation:
ManyToOne is always the owning side of a bidirectional assocation.
OneToMany is always the inverse side of a bidirectional assocation.
The owning side of a OneToOne assocation is the entity with the table containing the foreign key.
See https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html
The answers above were not sufficient for me to understand what was going on, so after delving into it more I think I have a way of explaining it that will make sense for people who struggled like I did to understand.
inversedBy and mappedBy are used by the INTERNAL DOCTRINE engine to reduce the number of SQL queries it has to do to get the information you need. To be clear if you don't add inversedBy or mappedBy your code will still work but will not be optimized.
So for example, look at the classes below:
class Task
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="task", type="string", length=255)
*/
private $task;
/**
* #var \DateTime
*
* #ORM\Column(name="dueDate", type="datetime")
*/
private $dueDate;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
class Category
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="category")
*/
protected $tasks;
}
These classes if you were to run the command to generate the schema (for example, bin/console doctrine:schema:update --force --dump-sql) you will notice that the Category table does not have a column on it for tasks. (this is because it does not have a column annotation on it)
The important thing to understand here is that the variable tasks is only there so the internal doctrine engine can use the reference above it which says its mappedBy Category. Now... don't be confused here like I was... Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'.
Like wise, on the Tasks class the property $category mentions it is inversedBy="tasks", notice this is plural, this is NOT THE PLURAL OF THE CLASS NAME, but just because the property is called 'protected $tasks' in the Category class.
Once you understand this it becomes very easy to understand what inversedBy and mappedBy are doing and how to use them in this situation.
The side that is referencing the foreign key like 'tasks' in my example always gets the inversedBy attribute because it needs to know what class (via the targetEntity command) and what variable (inversedBy=) on that class to 'work backwards' so to speak and get the category information from. An easy way to remember this, is the class that would have the foreignkey_id is the one that needs to have inversedBy.
Where as with category, and its $tasks property (which is not on the table remember, just only part of the class for optimization purposes) is MappedBy 'tasks', this creates the relationship officially between the two entities so that doctrine can now safely use JOIN SQL statements instead of two separate SELECT statements. Without mappedBy, the doctrine engine would not know from the JOIN statement it will create what variable in the class 'Task' to put the category information.
Hope this explains it a bit better.
In bidirectional relationship has both an owning side and an inverse side
mappedBy : put into The inverse side of a bidirectional relationship To refer to the field in the owning side of entity
inversedBy : put into The owning side of a bidirectional relationship To refer to the field on the inverse side of entity
AND
mappedBy attribute used with the OneToOne, OneToMany, or ManyToMany mapping declaration.
inversedBy attribute used with the OneToOne, ManyToOne, or ManyToMany mapping declaration.
Notice :
The owning side of a bidirectional relationship the side that contains the foreign key.
there two reference about inversedBy and mappedBy into Doctrine Documentation :
First Link,Second Link
5.9.1. Owning and Inverse Side
For Many-To-Many associations you can chose which entity is the owning and which the inverse side. There is a very simple semantic rule to decide which side is more suitable to be the owning side from a developers perspective. You only have to ask yourself, which entity is responsible for the connection management and pick that as the owning side.
Take an example of two entities Article and Tag. Whenever you want to connect an Article to a Tag and vice-versa, it is mostly the Article that is responsible for this relation. Whenever you add a new article, you want to connect it with existing or new tags. Your create Article form will probably support this notion and allow to specify the tags directly. This is why you should pick the Article as owning side, as it makes the code more understandable:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

Categories