Error Creating Many to Many Relationship Using Doctrine 2 - doctrine-orm

I'm trying to generate the schema for my database using Doctrine 2's ZF2 module but with the following definition:
/**
* #ORM\ManyToMany(targetEntity="Tag")
* #ORM\JoinTable(name="Manytomany_Issuetag",
* #ORM\joinColumns={#ORM\JoinColumn(name="IssueId", referencedColumnName="id")},
* #ORM\inverseJoinColumns={#ORM\JoinColumn(name="TagId", referencedColumnName="id")}
* )
*/
protected $tags;
When I run vendor/bin/doctrine-module orm:schema-tool:update --dump-sql I receive the following error:
Annotation #ORM\joinColumns is not allowed to be declared on property Application\Entity\Issue::$tags. You may only use this annotation on these code elements: PROPERTY
Edit: As requested here is the working annotation
/**
* #ORM\ManyToMany(targetEntity="Tag")
* #ORM\JoinTable(name="Manytomany_Issuetag",
* joinColumns={#ORM\JoinColumn(name="IssueId", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="TagId", referencedColumnName="id")}
* )
*/
protected $tags;

I think you need to drop a couple of the #ORM\ declarations, it should look like this (obviously without my comments)
/**
* #ORM\ManyToMany(targetEntity="Tag")
* #ORM\JoinTable(name="Manytomany_Issuetag",
* joinColumns={#ORM\JoinColumn(name="IssueId", referencedColumnName="id")},
* ^ drop the #ORM\
* inverseJoinColumns={#ORM\JoinColumn(name="TagId", referencedColumnName="id")}
* ^ drop the #ORM\
* )
*/
protected $tags;

Related

Association errors with Doctrine after upgrade

I'm working on upgrading a product from Symfony 2.7 to 4.2 (currently at 3.4) and am getting stuck with some existing associations.
The field AppBundle\Entity\User#currentBillingAgreement is on the owning side of a bi-directional relationship, but the specified mappedBy association on the target-entity AppBundle\Entity\BillingAgreement# does not contain the required 'inversedBy' attribute.
If association AppBundle\Entity\User#currentBillingAgreement is one-to-one, then the inversed side AppBundle\Entity\BillingAgreement#user has to be one-to-one as well.
The User entity has these associations:
/**
* #var BillingAgreement
* #ORM\OneToOne(
* targetEntity="AppBundle\Entity\BillingAgreement",
* inversedBy="user",
* cascade={"persist"}
* )
* #ORM\JoinColumn(
* name="currentBillingAgreementID",
* referencedColumnName="billingAgreementID"
* )
*/
protected $currentBillingAgreement;
/**
* #var ArrayCollection
* #ORM\OneToMany(
* targetEntity="AppBundle\Entity\BillingAgreement",
* mappedBy="user",
* cascade={"persist"}
* )
* #Serializer\Exclude()
*/
protected $billingAgreements;
and BillingAgreement has this:
/**
* #var User
* #ORM\ManyToOne(
* targetEntity="AppBundle\Entity\User",
* inversedBy="billingAgreements"
* )
* #ORM\JoinColumn(
* name="userID",
* referencedColumnName="userID",
* nullable=false
* )
*/
protected $user;
When I add a OneToOne mapping to BillingAgreement::$user (#ORM\OneToOne(targetEntity="AppBundle\Entity\User", inversedBy="currentBillingAgreement")), I get a new error:
The field AppBundle\Entity\BillingAgreement#user is on the owning side of a bi-directional relationship, but the specified mappedBy association on the target-entity AppBundle\Entity\User# does not contain the required 'inversedBy' attribute.
and the original 2 errors remain.
You can make the OneToOne association unidirectional by removing inversedBy="user", from the annotation.
or
Use a different field for each association on BillingAgreement entity:
/**
* #var User
* #ORM\ManyToOne(
* targetEntity="AppBundle\Entity\User",
* inversedBy="billingAgreements"
* )
* #ORM\JoinColumn(
* name="userID",
* referencedColumnName="userID",
* nullable=false
* )
*/
protected $user;
/**
* #var User
* #ORM\OneToOne(targetEntity="AppBundle\Entity\User", inversedBy="currentBillingAgreement")
*/
protected $singleUser;
and in User entity:
/**
* #var BillingAgreement
* #ORM\OneToOne(
* targetEntity="AppBundle\Entity\BillingAgreement",
* inversedBy="singleUser",
* cascade={"persist"}
* )
* #ORM\JoinColumn(
* name="currentBillingAgreementID",
* referencedColumnName="billingAgreementID"
* )
*/
protected $currentBillingAgreement;
/**
* #var ArrayCollection
* #ORM\OneToMany(
* targetEntity="AppBundle\Entity\BillingAgreement",
* mappedBy="user",
* cascade={"persist"}
* )
* #Serializer\Exclude()
*/
protected $billingAgreements;
References
Doctrine 2.6 Association Mapping

How to remove a relationship cleanly in Docrine 2?

There are entities Endpoint, EndpointServerConfig, and Server:
/**
* Server
*
* #ORM\Table(
* name="server",
* indexes={
* #ORM\Index(name="fk_server_server_type_idx", columns={"server_type_id"}),
* #ORM\Index(name="fk_server_cluster_idx", columns={"cluster_id"})
* }
* )
* #ORM\Entity
*/
class Server
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=32, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*
* #Groups({"export"})
*/
protected $name;
/**
* #var EndpointServerConfig[]
*/
protected $endpointServerConfigs;
}
/**
* EndpointServerConfig
*
* #ORM\Table(name="endpoint_server_config", indexes={
* #ORM\Index(name="fk_endpoint_server_config_server_idx", columns={"server_name"})}
* )
* #ORM\Entity
*/
class EndpointServerConfig
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var Server
*
* #ORM\ManyToOne(targetEntity="Server")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="server_name", referencedColumnName="name")
* })
*
* #Groups({"export"})
*/
protected $server;
/**
* #var Endpoint
*
* #ORM\OneToOne(targetEntity="Endpoint", mappedBy="endpointServerConfig")
*/
protected $endpoint;
}
/**
* Endpoint
*
* #ORM\Table(
* name="endpoint",
* indexes={
* ...
* #ORM\Index(name="fk_endpoint_endpoint_server_config_idx", columns={"endpoint_server_config_id"}),
* ...
* }
* )
* #ORM\Entity
* ...
*/
class Endpoint
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
}
Now I want to update an entity (e.g. Foo), that contains an Endpoint. Among other changes I want to remove the reference to the Server from the Endpoint's EndpointServerConfig. That means for the database: The endpoint_server_config.server needs to be set to NULL.
I load the Foo to a Zend\Form, disable the server and submit the changes. On the server side I unset the EndpointServerConfig#server over Foo:
/** #var Foo $myFoo */
if(! $myFoo->getEndpoint()->getEndpointServerConfig()->getServer() || ! $myFoo->getEndpoint()->getEndpointServerConfig()->getServer()->getName()) {
$myFoo->getEndpoint()->getEndpointServerConfig()->setServer(null);
}
$this->entityManager->persist($myFoo);
$this->entityManager->flush($myFoo);
It leads to an error:
An exception occurred while executing 'UPDATE server SET name = ? WHERE name = ?' with params ["", "someservername"]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`mydb`.`endpoint_server_config`, CONSTRAINT `fk_endpoint_server_config_server` FOREIGN KEY (`server_name`) REFERENCES `server` (`name`) ON DELETE NO ACTION ON UPDATE NO ACTION)
That means, Doctrine tries to UPDATE the Server, instead of just to remove the reference to it from the EndpointServerConfig. But why?
Only when I manually set endpoint_server_config.server_name to NULL (directly in the database), I can save the changes via form and Doctrine.
How to get it working?
EDIT
Just noticed, that I get the same problem on every update of the EndpointServerConfig. So not only on setServer(null), bu also when I try to set a new Server. In this case the attempts leads to the error:
An exception occurred while executing 'UPDATE server SET name = ? WHERE name = ?' with params ["newservername", "someservername"]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`mydb`.`endpoint_server_config`, CONSTRAINT `fk_endpoint_server_config_server` FOREIGN KEY (`server_name`) REFERENCES `server` (`name`) ON DELETE NO ACTION ON UPDATE NO ACTION)
Add following:-
cascade={"persist", "remove"}
on your relation.
#ORM\ManyToOne(targetEntity="Server", cascade={"persist", "remove"})

Doctrine Many-To-Many delete target entity instead of only jointable record

I have Photo Entity which has Man-To-Many relation with Tag Entity.
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Tag", cascade={"persist", "remove"})
* #ORM\JoinTable(name="photos_tags",
* joinColumns={#ORM\JoinColumn(name="photo_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id", onDelete="CASCADE")}
* )
**/
protected $tags;
Let say that I have a PhotoA which has TagA and TagB. But also I have and PhotoB which also has TagA. When I delete PhotoB, the TagA is also deleted. This is what i DONT want. I define cascade operations as I thought that this should delete only JoinColumn values... but its appears that the TagEntity is also delete as cascade operation.
Where I am wrong?
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Tag")
* #ORM\JoinTable(name="photos_tags",
* joinColumns={#ORM\JoinColumn(name="photo_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
**/
protected $tags;
This annotation solves the problem. I didnt realize that doctrine manage by itself these realtions and remove records in joined table without any need of describe. Obviously if want to delete and Tag Entity, then should annotated cascade operations.

Doctrine 2 ManyToOne with Join Table

I'm looking for a suggestion on how to map a OneToMany/ManyToOne relationship that uses a join table. The mapping I have is not taking, and I get an error that article_id is not set in the media table. 
class Media
{
// ...
/**
* #ManyToOne(targetEntity="Document", inversedBy="media")
* #JoinTable(name="articles_x_media", referencedColumnName="id")
* joinColumns={#JoinColumn(name="media_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="bid_id", referencedColumnName="id")})
* )
*/
protected $document;
}
class Document
{
// ...
/**
* #OneToMany(targetEntity="Media", mappedBy="document"))
* #JoinTable(name="articles_x_media", referencedColumnName="id")
* joinColumns={#JoinColumn(name="article_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="media_id", referencedColumnName="id")}
* )
*/
protected $media;
}
There's a specific paragraph in the documentation about OneToMany mapping with join table.
Anyway, what you probably want is an uni-directional ManyToMany association.
Also, #OneToMany does not come with a #JoinTable, and the same for #ManyToOne either.

OneToMany invalid Mapping

i am trying to create a oneToMany relationship. Since Doctrine only offers ManyToOne Unidirectional im using that. Somehow the validation of the mapping fails and I am not able to spot my mistake:
Validation Error:
[Mapping] FAIL - The entity-class 'Strego\TippBundle\Entity\BetRound'
mapping is invalid:
* The association Strego\TippBundle\Entity\BetRound#userStatus refers to the owning side field
Strego\TippBundle\Entity\UserBetRoundStatus#betRound which does not
exist.
My First Entity (BetRound):
<?php
namespace Strego\TippBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection as Collection;
use Strego\AppBundle\Entity\Base as BaseEntity;
/**
* Strego\TippBundle\Entity\BetRound
*
* #ORM\Table()
* #ORM\Entity
*/
class BetRound extends BaseEntity {
//......
/**
*
* #var Collection
* #ORM\OneToMany(targetEntity="UserBetRoundStatus", mappedBy="betRound", cascade={"all"})
*/
protected $userStatus;
}
My related Entity(UserBetRoundStatus)
<?php
namespace Strego\TippBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Strego\AppBundle\Entity\Base as BaseEntity;
/**
* Strego\TippBundle\Entity\Game
*
* #ORM\Table
* #ORM\Entity
* #UniqueEntity(fields={"user", "betRound"}, message="Unique Entity Validator Fails for UserStatus", groups="unique")
*
*/
class UserBetRoundStatus extends BaseEntity {
// .....
/*
* #var BetRound
* #ORM\ManyToOne(targetEntity="BetRound", inversedBy="userStatus")
* #ORM\JoinColumn(name="betround_id", referencedColumnName="id", nullable=false)
* #Assert\NotNull()
*/
protected $betRound;
}
I have found the issue:
/** <--------- you need two *
* #var BetRound
* #ORM\ManyToOne(targetEntity="BetRound", inversedBy="userStatus")
* #ORM\JoinColumn(name="betround_id", referencedColumnName="id", nullable=false)
* #Assert\NotNull()
*/
protected $betRound;