You are browsing a version that is no longer maintained. |
Bi-Directional References
By default when you map a bi-directional reference, the reference is maintained on both sides of the relationship and there is not a single "owning side". Both sides are considered owning and changes are tracked and persisted separately. Here is an example:
When I persist some instances of the above classes the references would exist on both sides! The
BlogPost
collection would have a DBRef stored on the $user
property and the User
collection would have a DBRef stored in the $posts
property.
Owning and Inverse Sides
A user may have lots of posts and we don't need to store a reference to each post on the user, we can get the users post by running a query like the following:
1 db.BlogPost.find({ 'user.$id' : user.id })
In order to map this you can use the inversedBy
and mappedBy
options. Here is the same
example above where we implement this:
One to Many
1 <?php
/** @Document */
class BlogPost
{
// ...
/** @ReferenceOne(targetDocument=User::class, inversedBy="posts") */
private $user;
}
/** @Document */
class User
{
// ...
/** @ReferenceMany(targetDocument=BlogPost::class, mappedBy="user") */
private $posts;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
So now when we persist a User
and multiple BlogPost
instances for that User
:
And we retrieve the User
later to access the posts for that user:
The above will execute a query like the following to lazily load the collection of posts to iterate over:
1 db.BlogPost.find( { 'user.$id' : user.id } )
Remember that the inverse side, the side which specified |
Other Examples
Here are several examples which implement the inversedBy
and mappedBy
options:
One to One
Here is an example where we have a one to one relationship between Cart
and Customer
:
1 <?php
/** @Document */
class Cart
{
// ...
/**
* @ReferenceOne(targetDocument=Customer::class, inversedBy="cart")
*/
public $customer;
}
/** @Document */
class Customer
{
// ...
/**
* @ReferenceOne(targetDocument=Cart::class, mappedBy="customer")
*/
public $cart;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
The owning side is on Cart.customer
and the Customer.cart
referenced is loaded with a query
like this:
1 db.Cart.find( { 'customer.$id' : customer.id } )
If you want to nullify the relationship between a Cart
instance and Customer
instance
you must null it out on the Cart.customer
side:
When specifying inverse one-to-one relationships the referenced document is
loaded directly when the owning document is hydrated instead of using a
proxy. In the example above, loading a |
Self-Referencing Many to Many
1 <?php
namespace Documents;
/** @Document */
class User
{
// ...
/**
* @ReferenceMany(targetDocument=User::class, mappedBy="myFriends")
*/
public $friendsWithMe;
/**
* @ReferenceMany(targetDocument=User::class, inversedBy="friendsWithMe")
*/
public $myFriends;
public function __construct($name)
{
$this->name = $name;
$this->friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection();
$this->myFriends = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addFriend(User $user): void
{
$user->friendsWithMe[] = $this;
$this->myFriends[] = $user;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32