More than one ManyToMany realtions - Doctrine, Symfony - php

I have two tables "RFQ" and "RFQItem".
First ManyToMany relation I need to make a choose which RFQItems add to RFQ in RFQ form.
Second ManyToMany relation I need to make a new RFQItems when creating new RFQ.
I have configured all, but schema update throws me an error:
The table with name 'rfqgroup.rfq_rfqitem' already exists.
Entity:
/**
* #ORM\ManyToMany(targetEntity="RFQItem")
* #ORM\JoinColumn(referencedColumnName="id", nullable=true)
*/
protected $rfqitem;
/**
* #ORM\ManyToMany(targetEntity="RFQItem", cascade={"persist"})
* #ORM\JoinColumn(referencedColumnName="rfq_id", nullable=true)
*/
protected $rfq_item_title;
It is even possible to make these relations?

You must use the #JoinTable attribute to ensure that the Many-to-Many tables have unique names.
/**
* #ORM\ManyToMany(targetEntity="RFQItem")
* #ORM\JoinTable(name="rfq_rfqitem",
* joinColumns={#ORM\JoinColumn(name="rfq_item_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="rfqgroup_id", referencedColumnName="id")}
* )
*/
public $rfqitem;
/**
* #ORM\ManyToMany(targetEntity="RFQItem")
* #ORM\JoinTable(name="rfq_rfqitem_title",
* joinColumns={#ORM\JoinColumn(name="rfq_item_title_id", referencedColumnName="rfq_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="rfqgroup_id", referencedColumnName="id")}
* )
*/
public $rfq_item_title;
You may need to correct the JoinColumn attributes for name and referencedColumnName depending on the variable names you've picked in each entity.

Related

Resolving [Doctrine\ORM\ORMException] ManyToOne Column name `id` referenced for relation from Comment towards User does not exist

Class Comment
/**
* #var \Caerus\AppBundle\Entity\Users
*
* #ORM\ManyToOne(targetEntity="User" , inversedBy="comment")
*
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
*
*/
protected $user;
Class User
/**
* #var mixed
*
* #ORM\OneToMany(targetEntity="Comment", mappedBy="user")
*/
protected $comment;
Basically quite simple. I need the comments class to have a user_id field which is a direct copy of the original user_id field from the users class.
The error is as following:
[Doctrine\ORM\ORMException] ManyToOne Column name id referenced for relation from Comment towards User does not exist
Why exactly is it still saying doesn't exist and how do I solve that ?
Referenced Column name should be the "id" property of the User class.
/**
* #var \Caerus\AppBundle\Entity\Users
*
* #ORM\ManyToOne(targetEntity="User" , inversedBy="comment")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
*/
protected $user;
P.S.
I would also name the OneToMany property "comments" as it holds many Comment objects.
"#var \Caerus\AppBundle\Entity\Users" should be ...\User as your class is called User
Running php bin/console doctrine:schema:validate will give you more insight into which entity classes and columns are involved in the error condition.
Also you can use this code:
/**
* #var \Caerus\AppBundle\Entity\Users
*
* #ORM\ManyToOne(targetEntity="User" , inversedBy="comment")
*
* #ORM\JoinColumn(nullable=true , referencedColumnName="variable_id_of_comment")
*/
protected $user;

adding created timestamp to join table in doctrine2

I have the following property in my User entity to track followers and following. Basically a user can follow other user as well. I have a join column called app_user_follow_user, however I also wanted to add a timestamp of whenever someone follows another user, when did it happen. How can I specify a created timestamp via this ORM?
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="following")
*/
protected $followers;
/**
* #ORM\ManyToMany(targetEntity="User", inversedBy="followers")
* #ORM\JoinTable(name="app_user_follow_user",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="follow_user_id", referencedColumnName="id")}
* )
*/
protected $following;
Doctrine ManyToMany relationships are used when your join table has two columns. If you need to add another column you have to convert the relationship to OneToMany on both sides and ManyToOne on the joined entity.
This is entirely untested but it will hopefully give you the gist.
User Entity
/**
* #ORM\OneToMany(targetEntity="AppUserFollowUser", mappedBy="appUser")
*/
protected $followers;
/**
* #ORM\OneToMany(targetEntity="AppUserFollowUser", mappedBy="followUser")
*/
protected $following;
AppUserFollowUser Entity
/**
* #ORM\Table(name = "app_user_follow_user")
*/
class AppUserFollowUser
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="followers")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $appUser;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="following")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="follow_user_id", referencedColumnName="id")
* })
*/
private $followUser;
/**
* #ORM\Column(name="created_date", type="datetime", nullable=false)
*/
private $createdDate;
}
I think that you will have to create a link entity manually (entiy1 onetomany linkEntity manytoone entity2.
Because, the usual link entity are automated and should be as simple and (data less) as possible, so doctrine can take all the controle over it,
imagine you need to get the timestamp, how can you do it on an (none hard coded) entity, you will need a getter, and the annotations are not supposed to contains code.

Doctrine multiple composite foreign key

I am trying to construct an object with two composite foreign keys pointing out to the same object, but they seem to have the same data, like doing the join only on one column, product_id.
class PostpaidProduct extends Product {
/**
* #ManyToOne(targetEntity="Bundle", fetch="EAGER", cascade={"persist"})
* #JoinColumn(name="bundle_voice_id", referencedColumnName="id")
*/
private $bundleVoice;
/**
* #ManyToOne(targetEntity="Bundle", fetch="EAGER", cascade={"persist"})
* #JoinColumn(name="bundle_data_id", referencedColumnName="id")
*/
private $bundleData;
/**
* #OneToMany(targetEntity="BundlePromo", mappedBy="product", fetch="EAGER", cascade={"persist"})
* #JoinColumns({
* #JoinColumn(name="id", referencedColumnName="product_id"),
* #JoinColumn(name="bundle_voice_id", referencedColumnName="bundle_id")
* })
*/
private $bundleVoicePromos;
/**
* #OneToMany(targetEntity="BundlePromo", mappedBy="product", fetch="EAGER", cascade={"persist"})
* #JoinColumns({
* #JoinColumn(name="id", referencedColumnName="product_id"),
* #JoinColumn(name="bundle_data_id", referencedColumnName="bundle_id")
* })
*/
private $bundleDataPromos;
}
What would be wrong with my mapping?
Is it possible to have composite foreign keys but without being primary keys?
I have talked to one of the developers of Doctrine and he said that the #JoinColumns field in #OneToMany relationships is ignored. The alternative would be having just one foreign key and to use matching criterias in an entity method, filtering for the entries needed based on the other key. Another solution would be having repository methods specific for getting these values.
Also, in OneToMany relationships eager fetching does not work, so it does separate queries for all children. So if you have a product with multiple prices, when fetching a product it will do separate queries for fetching the prices.

Getting the users of an FOSUserBundle Group (Symfony2)

I have been struggling with this question for the past couple of hours and haven't been able to find anything.
I have configured the FOSUserBundle and have the groups activated correctly and working. However, the user-group relation is defined as follows in the User class :
/**
* #ORM\ManyToMany(targetEntity="Netlabs\UserBundle\Entity\Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
and in the Group class, I do not even have a $user list defined. I tried loads of "normal" things like creating a $users variable in my Group class and defining it's relation to the User object, but it is not playing nice with the FOSUserBundle (every time, it creates a NEW table to create the relation, when there is already one in place). For example:
/**
* #ORM\ManyToMany(targetEntity="Netlabs\UserBundle\Entity\Group", inversedBy="groups", cascade={"all"})
*
*/
protected $users;
Any suggestions ?
Again, my main goal is : I want to be able to do Group->getUsers()
In your Group class, your targetEntity must be User and not Group. Furthermore, try to add an inversedBy rule for the $groups attributs and modifie inversedBy in mappedBy for $users.
/**
* #ORM\ManyToMany(targetEntity="Netlabs\UserBundle\Entity\Group", inversedBy="users")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
And
/**
* #ORM\ManyToMany(targetEntity="Netlabs\UserBundle\Entity\User", mappedBy="groups")
*
*/
protected $users;

Doctrine #UniqueEntity with ManyToOne fields?

I'm trying to create a UniqueEntity with 2 fields (both are ManyToOne fields).
The code is as follow:
/*
* #ORM\Table()
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(fields={"user", "connect"})
*/
class UserConnect
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var boolean $isLeader
*
* #ORM\Column(name="isLeader", type="boolean")
*/
private $isLeader;
/**
* #var date $joinedDate
*
* #ORM\Column(name="joinedDate", type="date")
*/
private $joinedDate;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="userConnects")
*
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Connect", inversedBy="userConnects")
*
*/
private $connect;
The goal is to ensure that I've got only one Entity that link a USER with a CONNECT.
Should I write something else in my #UniqueEntity declaration?
I understand you want to get an error only when both user and connect fields for one record are duplicated in other record in the database.
The #UniqueEntity annotation is rightly declared for your purpose (multiple column index) but only will be triggered in the form validation and doesn't affects the DDBB schema.
If you want to add the same check at database level you should use the #UniqueConstraint annotation in the Table() declaration and give a name to the new index. Something like:
/*
* #ORM\Table(uniqueConstraints={#ORM\UniqueConstraint(name="IDX_USER_CONNECT", columns={"user_id", "connect_id"})})
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(fields={"user", "connect"})
*/
class UserConnect
{
In the other hand, if you declare #ORM\Column(unique=true) in each attribute you will get a very different behavior, it won't be a multiple column index but you will have two independent unique columns, if you enter twice the same user_id you will get an error independently of the connect_id value, and the same will happens if you enter twice the same connect_id value.
This works:
/**
* State
*
* #ORM\Table(
* name="general.states",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="states_country_name_code_key", columns={"idcountry", "name","code"}),
* })
* #ORM\Entity(repositoryClass="Fluency\Bundle\GeneralBundle\Entity\Repository\StateRepository")
*/
class State
{.......
Taken from an entity on my system. This way affects Database schema. See where i put #\ORM\UniqueConstraint annotation. Sorry #estopero... next time i must read first the other answers.
you should add the unique declaration in your attributes annotations too.
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="userConnects")
* #ORM\Column(unique=true)
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Connect", inversedBy="userConnects")
* #ORM\Column(unique=true)
*/
private $connect;
See this symfony doc and this StackOverflow answer.

Categories