I am rookie in Symfony Doctrine and need some help with Join entities.
Normally Column are joins by primary key ID
/**
* User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="MainBundle\Repository\UserRepository")
* UniqueEntity("email", message="Account with email already exists.")
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #var \MainBundle\Entity\PersonDetails
*
* #ORM\ManyToOne(targetEntity="MainBundle\Entity\Person")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="person_details_id", referencedColumnName="id", nullable=true)
* })
*/
private $personDetails = null;
This is ok.
But problem is that I want to Join two columns in Relation OneToOne by id field in User Entity
/**
* User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="MainBundle\Repository\UserRepository")
* UniqueEntity("email", message="Account with email already exists.")
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #var \MainBundle\Entity\PersonDetails
*
* #ORM\ManyToOne(targetEntity="MainBundle\Entity\Person")
* #ORM\JoinColumn(name="id", referencedColumnName="user_id", nullable=true)
* })
*/
private $personDetails = null;
When I try to join columns on this way I get error
Missing value for primary key id on MainBundle\Entity\PersonDetails
Is it possible to index other field than id or what I trying to do is impossible?
Thanks guys.
You have mixed up the column-name and the field-name that shall be referenced in your #JoinColumn declaration.
#JoinColumn(name="id", referencedColumnName="user_id")
This way Doctrine looks for a field/property named user_id on your User entity. I guess you want the column in the join-table to be named user_id and the entries being id's of the User entity.
UserDetail
/**
* #ORM\Entity
*/
class UserDetail
{
/**
* #ORM\ManyToOne(
* targetEntity="User",
* inversedBy="details"
* )
* #ORM\JoinColumn(
* name="user_id",
* referencedColumnName="id"
* )
*/
protected $user;
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/** #ORM\Column() */
protected $key;
/** #ORM\Column() */
protected $value;
public function __construct($key, $value)
{
$this->key = $key;
$this->value = $value;
}
User
class User
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\OneToMany(
* targetEntity="UserDetail",
* mappedBy="user",
* cascade={
* "persist",
* "remove",
* "merge"
* },
* orphanRemoval=true
* )
*/
protected $details;
public function __construct()
{
$this->details = new ArrayCollection();
}
public function addDetail(UserDetail $detail)
{
$detail->setUser($this);
$this->details->add($detail);
return $this;
}
Now if you add a detail to your User like this and persist/flush afterwards:
$user->addDetail(new UserDetail('Height', '173cm'));
This will result in a join-colum in the user_detail table that looks like this:
| key | value | user_id |
|---------------|-----------|---------|
| Height | 173cm | 1 |
Citing Doctrine documentation:
It is not possible to use join columns pointing to non-primary keys.
Doctrine will think these are the primary keys and create lazy-loading
proxies with the data, which can lead to unexpected results. Doctrine
can for performance reasons not validate the correctness of this
settings at runtime but only through the Validate Schema command.
I had the same problem, I solved it by performing the mapping only to fields that are primary key. If I needed to get the related entities by other fields, I implemented methods in the Entity repository.
Related
I have a many to many table for User and House, called user_house. Instead of just two columns: user_id and house_id, i want to add 3 more: eg action, created_at, updated_at. How can I do this?
I cannot find any relevant docs on this.
The following just creates a separate table with two columns in it.
class User extends EntityBase
{
...
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\House")
*/
protected $action;
Basically, what I want to achieve is:
in the user_house table the combination of user_id, house_id, action should be unique.
when a user clicks a "view" on a house, user_house table gets updated with some user_id, some house_id, view, now(), now()
when a user clicks a "like" on a house, user_house table gets updated with some user_id, some house_id, like, now(), now()
when a user clicks a "request a call" on a house, user_house table gets updated with some user_id, some house_id, contact, now(), now()
Could someone point me in the right direction? Thanks!
You need to break your ManyToMany relation to OneToMany and ManyToOne by introducing a junction entity called as UserHasHouses, This way you could add multiple columns to your junction table user_house
User Entity
/**
* User
* #ORM\Table(name="user")
* #ORM\Entity
*/
class User
{
/**
* #ORM\OneToMany(targetEntity="NameSpace\YourBundle\Entity\UserHasHouses", mappedBy="users",cascade={"persist","remove"} )
*/
protected $hasHouses;
}
House Entity
/**
* Group
* #ORM\Table(name="house")
* #ORM\Entity
*/
class House
{
/**
* #ORM\OneToMany(targetEntity="NameSpace\YourBundle\Entity\UserHasHouses", mappedBy="houses",cascade={"persist","remove"} )
*/
protected $hasUsers;
}
UserHasHouses Entity
/**
* UserHasHouses
* #ORM\Table(name="user_house")
* #ORM\Entity
*/
class UserHasHouses
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="NameSpace\YourBundle\Entity\House", cascade={"persist"}, fetch="LAZY")
* #ORM\JoinColumn(name="house_id", referencedColumnName="id")
*/
protected $houses;
/**
* #ORM\ManyToOne(targetEntity="NameSpace\YourBundle\Entity\User", cascade={"persist","remove"}, fetch="LAZY" )
* #ORM\JoinColumn(name="user_id", referencedColumnName="id",nullable=true)
*/
protected $users;
/**
* #var \DateTime
* #ORM\Column(name="created_at", type="datetime")
*/
protected $createdAt;
/**
* #var \DateTime
* #ORM\Column(name="updated_at", type="datetime")
*/
protected $updatedAt;
//... add other properties
public function __construct()
{
$this->createdAt= new \DateTime('now');
}
}
have additional column in ManyToMany join table in Doctrine (Symfony2)
I'm trying to setup a many to many between fos Userbundle and my own group bundle so that I can group users. this is working fine. I can set a new group and can add as many users to this group as I like to. But when I want to check if a user is in a group, I get a Index join Column error. I think I didn't understand the usage of manytomany the correct way so it would be nice if you can help me getting the point.
My entities look like:
User:
class User extends BaseUser
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $usergroups;
//....//
And my Group Entity looks like:
/**
* #ORM\ManyToMany(targetEntity="PrUserBundle\Entity\User", inversedBy="id")
* #ORM\JoinColumn(name="id", referencedColumnName="id")
* #var user
*/
private $user;
//....
/**
* Add user
*
* #param \PrUserBundle\Entity\User $user
* #return Lieferanten
*/
public function addUser(\PrUserBundle\Entity\User $user)
{
$this->user[] = $user;
return $this;
}
/**
* Remove user
*
* #param \PrUserBundle\Entity\User $user
*/
public function removeUser(\PrUserBundle\Entity\User $user)
{
$this->user->removeElement($user);
}
/**
* Get user
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getUser()
{
return $this->user;
}
When I try to catch all users in a group, I get an error:
$group=$em->getRepository('PrGroupBundle:Group')->findAll();
var_dump($lfr[0]->getUser()->getId());
I guess I missunderstood how to handle the bidirectional manytomany. Or can I use a manytoone also?
I have an entity called User that has the following:
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(type="string",length=100)
**/
protected $id_user;
/** #ORM\Column(type="string")
*/
protected $surname;
/**
* #ORM\Column(type="string",length=50)
*/
protected $name;
/**
* #var ArrayCollection $friends
* #ORM\ManyToMany(targetEntity="UniDocs\UserBundle\Entity\User")
* #ORM\JoinTable(name="friends",
* joinColumns={#ORM\JoinColumn(name="friend1", referencedColumnName="id_user")},
* inverseJoinColumns={#ORM\JoinColumn(name="friend2", referencedColumnName="id_user")}
* )
*/
protected $friends;
.
.
.
/**
* Get friends
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getFriends()
{
return $this->friends;
}
.
.
.
}
I need to make a query that gives me the friends of an user which name contain letter 'a' and surname letter 'b' (for example. Those letter are specified on a filter in a web form).
I know I can access all the friends of the registered user using getFriends() method, but... how to filter those friends?
You cannot do that using getters, you need to write a repository method and use that method in order to fetch exactly what you are looking for.
class FriendRepository extends EntityRepository
{
public function findByUserAlphabetical(User $user)
{
// do query with alphabetical stuff
return $query = ...
}
}
Then in your logic:
$friends = $friendRepository->findByUserAlphabetical($user);
$user->setFriends($friends);
Also, you will want to prevent fetching the friends in the original User query, so you can set your annotation fetch to LAZY:
/**
* #var ArrayCollection $friends
* #ORM\ManyToMany(targetEntity="UniDocs\UserBundle\Entity\User", fetch="LAZY")
* #ORM\JoinTable(name="friends",
* joinColumns={#ORM\JoinColumn(name="friend1", referencedColumnName="id_user")},
* inverseJoinColumns={#ORM\JoinColumn(name="friend2", referencedColumnName="id_user")}
* )
*/
protected $friends;
I have followed One-to-Many relation not working and created a one to many relationship
i have a users table where i have following fields
- id(primary key)
- name
- pwd
i have attachments table where user can upload more than one file i.e one user_id contains multiple files
- id
- user_id(foreignkey)
- path
my user entity contains the following code
namespace Repair\StoreBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* users
* #ORM\Entity(repositoryClass="Repair\StoreBundle\Entity\usersRepository")
*/
class users
{
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
--some code --
/**
* #ORM\OneToMany(targetEntity="attachments", mappedBy="user_id")
*/
private $attachments;
public function __construct()
{
$this->attachments= new ArrayCollection();
}
/**
* Add attachments
*
* #param \Repair\StoreBundle\Entity\attachments $attachments
* #return users
*/
public function addAttachment(\Repair\StoreBundle\Entity\attachments $attachments)
{
$this->attachments[] = $attachments;
return $this;
}
/**
* Remove attachments
*
* #param \Repair\StoreBundle\Entity\attachments $attachments
*/
public function removeAttachment(\Repair\StoreBundle\Entity\attachments $attachments)
{
$this->attachments->removeElement($attachments);
}
/**
* Get attachments
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAttachments()
{
return $this->attachments;
}
this is my attachments entity
namespace Repair\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* attachments
*/
class attachments
{
-- some code for id--
private $id;
/**
* #var integer
* #ORM\Column(name="user_id", type="integer", nullable=false)
* #ORM\ManyToOne(targetEntity="users", inversedBy="users")
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
*/
protected $userId;
public function getId()
{
return $this->id;
}
/**
* Set userId
* #param integer $userId
* #return attachments
*/
public function setUserId($userId)
{
$this->userId = $userId;
return $this;
}
/**
* Get userId
*
* #return integer
*/
public function getuserId()
{
return $this->userId;
}
--Some code for paths --
}
It is not displaying any errors
but how to know whether the foriegn key is set or not i went to phpmyadmin and checked the indexes it only shows the primary keys.please say whether i did correct or not and how to check whether foreign key is set or not
problem is in your annotations. In your attachment entity you should have annotation like this.
* #ORM\ManyToOne(targetEntity="users", inversedBy="annotations")
you don't have to have join column annotation. But if you want to have it there, it should look like this.
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
Also it shouldn't be called user_id but user, because doctrine takes it as whole entity.
So, i have the following structure of entities:
/**
* #ORM\Entity
*/
class Group
{
/**
* Many-To-Many, Unidirectional
*
* #var ArrayCollection $permissions
*
* #ORM\ManyToMany(targetEntity="Permission")
* #ORM\JoinTable(name="group_has_permission",
* joinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="permission_id", referencedColumnName="id")}
* )
*/
protected $permissions;
public function __construct()
{
$this->permissions = new ArrayCollection();
}
}
/**
* #ORM\Entity
*/
class Permission {}
It's just an example, but i'm confused. I need another entity probably called "group_has_permission" with two fields: group_id and permission_id, right? Or am i wrong?
You don't need to create a new entity.
Doctrine will create for you a group table, a permission table & a join table in order to link a group to multiple permissions. This is transparent for you.