Доктрина DQL: DQL Объединяет 4 объекта

0

Итак, у меня есть эта структура сущностей:

  • 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.

Вы можете мне помочь?

Теги:
join
dql
doctrine2

1 ответ

0

Поскольку вы сделали все ваши отношения двунаправленными, вы можете выполнить такой запрос, соединяя таблицы из 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 пользователя и получения соответствующих профилей.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню