How to join column and target entity manually in manytoone relation? - doctrine-orm

I have two fields : account_type_id and account_id.
How can i manually map doctrine TargetEntity to join Company Entity if accountTypeId = 1 OR join User Entity if account_type_id = 2 ?
<?php
/** #Entity */
class Accounts
{
// 1= Company, 2 = User
private $accountType;
/**
* #ManyToOne(targetEntity="Companies")
*/
private $company;
/**
* #ManyToOne(targetEntity="Users")
*/
private $user;
//...
}

Unfortunately, joining different columns on the fly cannot be done automatically, but you can have both fields set as nullable and only set the correct one when persisting the Account entity.
This would be the annotation:
/**
* #ORM\ManyToOne(targetEntity="Users", inversedBy="users")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true)
*/
private $user;
Keep in mind that nullable=true is the default anyway, I'm just being specific here.
If you want to go defensively about this, you can have an additional check in getter
/**
* #return User
* #throws \Exception
*/
public function getUser()
{
if ($this->accountType !== 2) {
throw new \Exception("Entity is not of type 'user'");
}
return $this->user;
}

Related

How to set parent id on a child entity when submitting symfony3 form

How can I set the task_id on the TaskLine entity?
Similar Questions:
Doctrine: How to insert foreign key value
Best practice for inserting objects with foreign keys in symfony2
Doctrine 2 entity association does not set value for foreign key
I get this error:
Neither the property "task_id" nor one of the methods "getTaskId()", "taskId()", "isTaskId()", "hasTaskId()", "__get()" exist and have public access in class "AppBundle\Entity\TaskLine"
NOTE: Normally I work with PropelORM.
I'm trying to save a new TaskLine entity which is related to Task entity. I'm posting JSON payload which look something like this.
{
"id": null,
"task_id": 1,
"note" : "new note"
}
In the controller I json_decode the request payload and submit that to $form->submit($note_data), $form is an instance of:
class TaskNoteType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add( 'task_id', NumberType::class )
->add( 'note', TextType::class )
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\TaskLine'
));
}
}
Here is my Task entity
class Task
{
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=150, nullable=true)
*/
private $description;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
}
TaskLine entity
class TaskLine
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \AppBundle\Entity\Task
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Task")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="task_id", referencedColumnName="id")
* })
*/
private $task;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set task
*
* #param \AppBundle\Entity\Task $task
*
* #return TaskLine
*/
public function setTask(\AppBundle\Entity\Task $task = null)
{
$this->task = $task;
return $this;
}
/**
* Get task
*
* #return \AppBundle\Entity\Task
*/
public function getTask()
{
return $this->task;
}
}
I found my answer in here:
Best Practice for inserting objects with foreign keys in Symfony2
Answered by: Tuan nguyen
In ORM you have to set Foreign key by an object which your entity
associated with. You could use EntityManager#getReference to get a
reference to category entity without loading it from DB. Like this
$category = $entityManager->getReference('YourProject\Entity\Category', $categoryId);
$product = new Product();
$product->setCategory($category);
Similar questions:
Doctrine: How to insert foreign key value
Following function you should have already in your Slider entity (or
similar).
public function addImage(Image $image) {
$image->setSlider($this); // This is the line you're probably looking for
$this->images[] = $image;
return $this; }
What it does is if you persist the entity it writes the ID of the Slider (sid) into your Image.
Doctrine 2 entity
association does not set value for foreign key
I found something in the Doctrine 2 documentation:
Changes made only to the inverse side of an association are ignored.
Make sure to update both sides of a bidirectional association (or at
least the owning side, from Doctrine’s point of view) As in my case
the owning side is the User I must update it. Doctrine 1 was able to
manage it automatically... too bad.

doctrine2 foreign key gets not created

I have two simple entities connected to each other with a OneToMany association.
/**
* #ORM\Entity(repositoryClass="Shopware\CustomModels\JoeKaffeeAbo\Client")
* #ORM\Table(name="joe_kaffee_abo_client")
*/
class Client extends ModelEntity
{
public function __construct() {
$this->abos = new ArrayCollection();
}
/**
* #ORM\OneToMany(targetEntity="Shopware\CustomModels\JoeKaffeeAbo\Abo", mappedBy="client", cascade= "all")
* #var \Doctrine\Common\Collections\ArrayCollection
*/
protected $abos;
public function addAbo($abo)
{
//$this->abos[] = $abo;
$this->abos->add($abo);
}
The second one is Abo:
/**
* #ORM\Entity(repositoryClass="Shopware\CustomModels\JoeKaffeeAbo\Abo")
* #ORM\Table(name="joe_kaffee_abo_abos")
*/
class Abo extends ModelEntity
{
/**
* #ORM\ManyToOne(targetEntity="Shopware\CustomModels\JoeKaffeeAbo\Client",inversedBy="abos")
* #ORM\JoinColumn(name="clientId", referencedColumnName="id")
*/
protected $client;
}
Somehow the join column gets not filled - it seems that doctrine ignores the association I set up. And if I call $client->addAbo($abo) there gets not relation created...and I cant receive the added abos via a getter function which returns the abo array collection.

Doctrine and ZF2- Working with Associations (inserting)

Entity User
class User {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
...
/**
* #ORM\ManyToMany(targetEntity="Controleitor\Model\Entity\Account", mappedBy="user")
*/
protected $userAccount;
public function __construct() {
$this->userAccount = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getUserAccount() {
return $this->userAccount;
}
...
}
Entity Account
class Account{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
*
* #ORM\ManyToMany(targetEntity="JasUser\Model\Entity\User", inversedBy="userAccount")
* #ORM\JoinTable(name="user_has_account",
* joinColumns={#ORM\JoinColumn(name="idAccount", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="idUser", referencedColumnName="id")}
* )
*/
private $user;
public function __construct(array $options = null) {
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
}
...
}
Test:
$user = $this->entityManager->getRepository('User')->findOneById($id);
$user->getUserAccount()->add($account);
$this->entityManager->persist($account);
$this->entityManager->flush();
$id = $entity->getId();
It gets the user, the userAccount and also inserts the new record account in the db, but it doesn't adds the record in the user_has_account table for the manytomany association between user and account with the add method as I was expecting..
Looks like you've got owning/inverse sides of your relation backwards.
The owning side has to use the inversedBy attribute of the OneToOne, ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute contains the name of the association-field on the inverse-side.
Changes made only to the inverse side of an association are ignored. Make sure to update both sides of a bidirectional association (or at least the owning side, from Doctrine’s point of view)
This can be somewhat annoying.
The preferred solution is to only touch the Collections internally. So instead of having your calling code do $user->getUserAccount()->add($account), implement it like this:
<?php
class Account {
// ...
public function addUser($user){
$this->users->add($user);
}
}
class User {
// ...
public function addAccount($account){
// relation must be added from the owning side
$account->addUser($this);
}
}

Doctrine2: Many-to-Many from Object X to Object X

i try to set up a "following" feature for users, so users can follow users.
I tried doing this by adding a Many-to-many Relation:
#ORM\ManyToMany(targetEntity="User",inversedBy="User",fetch="LAZY",cascade={"persist"})
#ORM\JoinTable=(name="user_followers",
joinColumns={
#ORM\JoinColumn(name="user_id", referencedColumnName="id")
},
inverseJoinColumns={#JoinColumn(name="follower_id",referencedColumnName="id")}
)
Now doctrine creates a table user_user with just one field user_id.
I really have no idea how to declare this.
Any thoughts?
I found the Solution myself.
You can actually use a self refferencing Many-to-Many Solution. From the Doctrine Website:
<?php
/** #Entity */
class User
{
// ...
/**
* #ManyToMany(targetEntity="User", mappedBy="myFriends")
*/
private $friendsWithMe;
/**
* #ManyToMany(targetEntity="User", inversedBy="friendsWithMe")
* #JoinTable(name="friends",
* joinColumns={#JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="friend_user_id", referencedColumnName="id")}
* )
*/
private $myFriends;
public function __construct() {
$this->friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection();
$this->myFriends = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/association-mapping.html#many-to-many-self-referencing

Doctrine 2 - Insert new item in database

I'm trying to make something very simple.. but I do wrong, and I don't know what is the problem. Just I'm trying to insert new item to database with Doctrine 2:
$favouriteBook = new UserFavouriteBook;
$favouriteBook->user_id = 5;
$favouriteBook->book_id = 8;
$favouriteBook->created_at = new DateTime("now");
$this->_em->persist($favouriteBook);
$this->_em->flush();
As you can see.. is very simple, but that, give me next error:
Error: Message: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'user_id' cannot be null
Obviosly, if I make a "dump" before "persist" and "flush" of $favouriteBook, all looks be correct..
This is my "favouriteBook" entity:
/** #Column(type="integer")
* #Id
*/
private $user_id;
/** #Column(type="integer")
* #Id
*/
private $book_id;
/**
* #ManyToOne(targetEntity="Book", inversedBy="usersFavourite")
* #JoinColumn(name="book_id", referencedColumnName="id")
*/
private $book;
/**
* #ManyToOne(targetEntity="User", inversedBy="favouriteBooks")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/** #Column(type="datetime") */
private $created_at;
public function __get($property) {
return $this->$property;
}
public function __set($property, $value) {
$this->$property = $value;
}
Anyone can image what is the problem? .. I don't know what else try.. Thanks
I think what beberlei is saying is that within your favouriteBook entity, you don't need to define the user_id and book_id as class properties, b/c the book and user properties you have set already recognize these as the relevant join columns. Also, your attempt to persist the favouriteBook entity failed because you need to set the book and user entity associations within the favouriteBook entity, not the foreign keys. So it would be:
$favouriteBook = new UserFavouriteBook;
$favouriteBook->book = $book;
$favouriteBook->user = $user;
$favouriteBook->created_at = new DateTime("now");
$this->_em->persist($favouriteBook);
$this->_em->flush();
You are mapping foreign keys and the associations. You have to modify the association not the foreign key field. Its bad-practice to map them both, you should remove $book_id and $user_id completly.