有很多方法可以解決這個問題,全部取決於對「朋友」關係的要求。
單向
一個簡單的方法是使用一個單向多對多關聯,並把它當作如果其中一個雙向一個(保持雙方同步):
/**
* @Entity
*/
class User
{
/**
* @Id
* @Column(type="integer")
*/
private $id;
/**
* @ManyToMany(targetEntity="User")
* @JoinTable(name="friends",
* joinColumns={@JoinColumn(name="user_a_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="user_b_id", referencedColumnName="id")}
*)
* @var \Doctrine\Common\Collections\ArrayCollection
*/
private $friends;
/**
* Constructor.
*/
public function __construct()
{
$this->friends = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* @return array
*/
public function getFriends()
{
return $this->friends->toArray();
}
/**
* @param User $user
* @return void
*/
public function addFriend(User $user)
{
if (!$this->friends->contains($user)) {
$this->friends->add($user);
$user->addFriend($this);
}
}
/**
* @param User $user
* @return void
*/
public function removeFriend(User $user)
{
if ($this->friends->contains($user)) {
$this->friends->removeElement($user);
$user->removeFriend($this);
}
}
// ...
}
當你電話$userA->addFriend($userB)
,$userB
將被添加到$userA
中的好友集合中,並且$userA
將被添加到$userB
中的好友集合中。
這也會導致2個記錄添加到「朋友」表(1,2和2,1)。雖然這可以看作是重複的數據,但它會簡化您的代碼。例如,當你需要找到的所有$userA
朋友,你可以簡單地做:
SELECT u FROM User u JOIN u.friends f WHERE f.id = :userId
不需要檢查2個不同的屬性,你會與一個雙向關聯。
雙向
當使用雙向關聯的User
實體將具有2個屬性,$myFriends
和$friendsWithMe
例如。您可以按照與上述相同的方式保持它們的同步。
主要區別在於,在數據庫級別,只有一條記錄表示關係(1,2或2,1)。這使得「查找所有朋友」查詢有點複雜,因爲您必須檢查兩個屬性。
您當然可以通過確保addFriend()
將更新$myFriends
和$friendsWithMe
(並保持另一側同步),仍然可以在數據庫中使用2條記錄。這會在你的實體中增加一些複雜性,但查詢變得稍微複雜一些。
一對多/多對一
如果你需要一個系統,用戶可以添加好友,但朋友已證實他們確實是朋友,你需要的是確認存儲在join-表。然後,您不再擁有ManyToMany關聯,但類似User
< - OneToMany - >Friendship
< - ManyToOne - >User
。
你可以閱讀我的博客,帖子就這個問題:
單向=>無法確定財產'訪問類型...' – Trix
您需要映射'id'屬性。我已經將它添加到示例中(映射爲整數,但它可以是任何你喜歡的)。 –
非常有用的答案。對我來說,添加的重要部分是'$ user-> addFriend($ this);'。 – StockBreak