Reputation: 317
I've created a concept of a Person model having many e-mails. I also have a Company model that can share the same e-mails with People (Person model).
In short: People OneToMany PeopleEmail ManyToOne Email (classic manytomany unidirectional with a join table)
people { id, firstname, lastname, created }
people_emails { person_id, email_id, main, created }
emails { id, email, created }
as well as:
companies { id, name, employee_count, created }
companies_emails { company_id, email_id, main, created }
emails { id, email, created }
The problem is, that I'd like to store a boolean value called "main" in the join table as follows:
person_id | email_id | main | created
8 | 5 | true | 2014-10-21 16:54:21
...so that I can do this:
Mark Wilson (Person) has 5 emails.
3 of them are his company e-mails (shared): [email protected], [email protected], [email protected]
2 of them are his own.
1 he answers only in his leisure time
1 is his MAIN email: i.e. [email protected]
Instead of fetching all those 5 emails, I'd like to easily get the primary email just as if it was a regular Person model column:
firstname: Mark (string)
lastname: Wilson (string)
emails: (array)
primary_email: (email object)
I cannot store the "main" property anywhere else, as I want to point, that the relation between Mark and his Email is "main", not the email itself.
Now, I do have this value stored, but the problem is, how to make an entity property like:
class Person {
(...)
/**
* @ORM\ManyToMany(targetEntity="Email")
* @ORM\JoinTable(name="people_emails",
* joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="email_id", referencedColumnName="id", unique=true)}
* )
*/
private $primary_email;
/**
* @ORM\ManyToMany(targetEntity="Email")
* @ORM\JoinTable(name="people_emails",
* joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="email_id", referencedColumnName="id", unique=true)} // A condition?
* )
*/
private $emails;
public function getPrimaryEmail() {
return $this->primary_email; // Single row limit?
}
public function getEmails() {
return $this->emails;
}
(...)
}
The thing is, I would really love to have it as an entity property, just for use in any case possible without the need to write custom repostory functions for the whole Person model.
Or maybe that is a completely wrong way. I'd like to use that property in Twig like:
{{person.primary_email.email}}
To sum up: I'd like to store a ManyToMany single row relationship depending on joinTable column.
How to do that?
Upvotes: 1
Views: 2150
Reputation: 1423
There are many ways to do this and there are also many critical things to say about your design choices. Either way here is an example of one way you could achieve this using two join tables (you need two if you want to use foreign keys).
<?php
interface AddressLink
{
public function getEmail();
public function isMain();
}
trait EmailAddressOwner
{
protected abstract function getAddressLinks();
public function getPrimaryEmailAddress()
{
return $this->getAddressLinks()->filter(function (AddressLink $addressLink) {
return $addressLink->isMain();
})->first();
}
public function getEmailAddresses()
{
return $this->getAddressLinks()->map(function (AddressLink $addressLink) {
return $addressLink->getEmail();
});
}
}
class PersonEmailAddress implements AddressLink
{
private $person; // ManyToOne
private $email; // ManyToOne
private $main; // bool
}
class CompanyEmailAddress implements AddressLink
{
private $company; // ManyToOne
private $email; // ManyToOne
private $main; // bool
}
class Email
{
private $id;
private $address;
}
class Person
{
/**
* @ORM\OneToMany(targetEntity="PersonEmailAddress")
*/
private $emailAddressLinks;
use EmailAddressOwner;
public function getAddressLinks()
{
return $this->emailAddressLinks;
}
}
class Company
{
/**
* @ORM\OneToMany(targetEntity="CompanyEmailAddress")
*/
private $emailAddressLinks;
use EmailAddressOwner;
public function getAddressLinks()
{
return $this->emailAddressLinks;
}
}
Another way would be to include one ManyToMany
relation to your Email
entity and one ManyToOne
relation for the primary e-mail address.
To answer you question in the comments if in twig you do
{{ person.primaryEmail.email }}
It wil actually call the getPrimaryEmail()
method on your Person object. Which you can implement like I've outlined above. That way you don't need to have this extra property.
Upvotes: 1