Итак, у меня есть эта структура сущностей:
User
который имеет Email
(несколько одновременно);Email
, принадлежащая Domain
(если [email protected], то у меня есть Domain
"example.com" в базе данных)Domain
МОЖЕТ иметь связанный с ним Profile
. Теперь, учитывая User
я бы хотел получить все Profiles
(ы), к которым он может получить доступ (ЕСЛИ ЛЮБОЙ! Возможно, у Domain
нет Profile
).
Структура объектов:
// User entity
use FOS\UserBundle\Model\User as BaseUser;
/**
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Email", mappedBy="forUser")
*/
protected $emails;
...
}
// Email entity
/**
* @ORM\Entity(repositoryClass="\AppBundle\Repository\EmailRepository")
* @ORM\Table(name="emails")
*/
class Email
{
/**
* @var EmailValue
*
* @ORM\Id
* @ORM\Column(name="email", type="email", nullable=false, unique=true)
*/
protected $email;
/**
* @var Domain
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Domain", inversedBy="emails")
* @ORM\JoinColumn(name="domain", referencedColumnName="second_level")
*/
protected $domain;
/**
* @var \MyNamespace\Bundle\UserBundle\Entity\User
*
* @ORM\ManyToOne(targetEntity="MyNamespace\Bundle\UserBundle\Entity\User", inversedBy="emails")
* @ORM\JoinColumn(name="for_user", referencedColumnName="id")
*/
protected $forUser;
...
}
// Domain entity
/**
* @ORM\Entity(repositoryClass="\AppBundle\Repository\DomainRepository")
* @ORM\Table(name="domains")
*/
class Domain
{
/**
* @var string
*
* @ORM\Id
* @ORM\Column(type="string", nullable=false, unique=true)
*/
private $secondLevel;
/**
* @var UrlValue
*
* @ORM\Column(name="url", type="uri", nullable=false, unique=true)
*/
private $url;
...
/**
* Each Domain can be linked to only one Profile.
*
* @var Profile|null
*
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Profile", inversedBy="domain")
*/
private $profile;
/**
* Each Domain can have more than one Email.
*
* @var Collection
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Email", mappedBy="domain")
*/
private $emails;
...
}
// Profile entity
/**
* @ORM\Table(name="profiles")
* @ORM\Entity(repositoryClass="\AppBundle\Repository\ProfileRepository")
* @ORM\HasLifecycleCallbacks
*/
class Profile
{
/**
* @var int
*
* @ORM\Column(name="id", type="string", unique=true)
* @ORM\Id
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="AppBundle\Doctrine\IdGenerator")
*/
private $id;
/**
* Each Store can have only one Domain.
*
* @var Domain
*
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Domain", mappedBy="profile")
*/
private $domain;
...
}
Теперь, учитывая User
я бы хотел получить все Profiles
(ы), к которым он может получить доступ (ЕСЛИ ЛЮБОЙ! Возможно, у Domain
нет Profile
).
Я решаю, может ли User
получить доступ к Profile
если у него есть Email
с Domain
.
Итак, если у User
есть Email
[email protected], он может получить доступ к Profile
Domain
example.com.
Я знаю, что нужно соединить четыре таблицы, но я понятия не имею, как я могу сделать такие JOIN
.
Вы можете мне помочь?
Поскольку вы сделали все ваши отношения двунаправленными, вы можете выполнить такой запрос, соединяя таблицы из Profile
. Вы можете использовать построитель запросов и добавить в свой ProfileRepository
следующий метод для выполнения поиска на основе экземпляра User
:
public function getUserProfiles(User $user)
{
return $this->createQueryBuilder('profile')
->addSelect('domain') // select the corresponding domain at the same time
->join('profile.domain', 'domain')
->join('domain.emails', 'emails')
->where('emails.forUser = :user')
->setParameter('user', $user)
->getQuery()
->getResult();
}
Если у вас просто есть доступ к идентификатору пользователя, вы можете использовать where('IDENTITY(emails.forUser) = :userId')
вместо предложения where
, указанного выше.
Примечание. Если у пользователя несколько электронных писем, связанных с одним и тем же доменом/профилем, базовый SQL-запрос будет возвращать одну и ту же запись профиля несколько раз, но Doctrine getResult
их к одной записи в результирующем наборе, если вы используете getResult
или getArrayResult
. Вы получите дубликаты, если вы используете getScalarResult
как описано в документации.
Вы также можете сделать это по-другому и присоединиться к emails
, domain
и profile
от User
чтобы иметь возможность получать все данные из вашего экземпляра User
. Важной частью было бы использовать leftJoin
для соединения profile
чтобы домены без профилей все равно были выбраны. В этом случае вам нужно добавить метод в свой класс User
для обхода emails
пользователя и получения соответствующих профилей.