这就是这种情况,我有 Users 和 Profiles 。因为我需要临时的开始日期和结束日期,所以这是一个ManyToMany关系。
我的实体看起来像:
用户←一对多→ UserProfile ←一对多→ Profile
因此,我按照本文所示进行了映射: https://www.future500.nl/articles/2013/09/doctrine-2-how-to-handle-join-tables-with-extra-columns/
这是我的实体代码:
用户
/**
* UserProfile Collection
* @var Collection
*
* @ORM\OneToMany(targetEntity="App\Entity\UserProfile", mappedBy="user", cascade={"persist", "remove"}, orphanRemoval=TRUE)
*/
private $userprofiles;
//Getters and Setters
/**
* @return Collection|UserProfile[]
*/
public function getUserprofiles(): Collection
{
return $this->userprofiles;
}
public function addProfile(UserProfile $user_profile): self
{
if (!$this->userprofiles->contains($user_profile)) {
$this->userprofiles[] = $user_profile;
$user_profile->setUser($this);
}
return $this;
}
public function removeProfile(UserProfile $user_profile): self
{
if ($this->userprofiles->contains($user_profile)) {
$this->userprofiles->removeElement($user_profile);
$user_profile->setUser(null);
}
return $this;
}
用户个人资料
/**
* @var User
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="userprofiles")
* @ORM\JoinColumn(name="User_id", referencedColumnName="id", nullable=true)
*/
private $user;
/**
* @var Profile
* @ORM\ManyToOne(targetEntity="App\Entity\Profile", inversedBy="users")
* @ORM\JoinColumn(name="Profile_id", referencedColumnName="id", nullable=true)
*/
private $profile;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $beginning;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $ending;
//Getters and Setters
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getProfile(): ?Profile
{
return $this->profile;
}
public function setProfile(?Profile $profile): self
{
$this->profile = $profile;
return $this;
}
个人资料
/**
* @var Collection
*
* @ORM\OneToMany(targetEntity="App\Entity\UserProfile", mappedBy="profile", cascade={"persist","remove"}, orphanRemoval=TRUE)
*/
private $users;
//Getters and Setters
/**
* @return Collection|UserProfile[]
*/
public function getUsers(): Collection
{
return $this->users;
}
public function addUser(?UserProfile ...$user_profiles): self
{
foreach ($user_profiles as $user_profile){
if (!$this->users->contains($user_profile)) {
$this->users[] = $user_profile;
$user_profile->setProfile($this);
}
}
return $this;
}
public function removeUser(UserProfile $user_profile): self
{
if ($this->users->contains($user_profile)) {
$this->users->removeElement($user_profile);
$user_profile->setProfile(null);
}
return $this;
}
public function getUsersConnected( ) {
return array_map(function (UserProfile $userProfile){
return $userProfile->getProfile();
}, $this->users->toArray());
}
对于表单,我希望能够在创建新的 Profile 时添加 Users ,因此我创建了一个填充到 Profile 的 CollectionType 为 UserProfileType 。
个人资料类型
->add('users', CollectionType::class, array(
'entry_type' => UserProfileType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'allow_delete' => true
));
UserProfileType
$builder
->add('beginning')
->add('ending')
->add('user', EntityType::class, array(
'choice_label' => 'username',
'class' => User::class,
'property_path' => 'user',
'multiple' => false,
'expanded' => false,
'error_bubbling' => true,
'constraints' => [
new NotBlank(['message' => 'User is required.'])
]
));
使用集合的原型表单,我可以为我的新 Profile 创建尽可能多的 Users 用户。问题是,配置文件的ID 没有在联合表( UserProfile 实体)中注册,但是用户的ID 却存在;我问如果其中一个ID不存在,是否可以在Symfony中保留关系?在 OneToMany / ManyToOne 模式的情况下,form :: handleRequest()方法可以管理此问题吗?
我知道从 Symfony-demo 项目的带有标签的帖子示例的 JoinTable 批注是可能的。
我正在使用Symfony 4.1.1,谢谢您的宝贵时间!
EDIT_1
经过一些试验,我尝试在创建表单时使用 empty_data 将 Profile 的实例传递给CollectionType中的 UserProfiles 属性:
->add('users', CollectionType::class, array(
'entry_type' => UserProfileType::class,
'entry_options' => ['label' => false, 'empty_data' => new UserProfile(null, $option['data'])],
'allow_add' => true,
'allow_delete' => true
));
然后在 HiddenType 字段中检索配置文件,如下所示:
->add('profile', HiddenType::class, array(
'data' => $builder->getEmptyData()->getProfile()
));
问题在于,Doctrine抛出一个错误,指出该实体在尝试获取配置文件的ID时不受管理。在演示中,我肯定认为Doctrine使用持久性后事件订阅者来处理此问题,因为它需要新实体的ID。