Doctrine 查询生成器使用 join 嵌套 orX 和 andX 条件

Gau*_*ier 7 doctrine join repository query-builder conditional-statements

我有两个实体UserCalendarEvent。我的用户附属于一家工厂,calendarEvent 可用于了解用户是否被“借用”到他所属工厂的另一家工厂......

我的两个实体是这样的:

用户:

class User extends BaseUser
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="firstname", type="string", length=255, nullable=true)
     */
    private $firstname;

    /**
     * @var string
     * @ORM\Column(name="lastname", type="string", length=255, nullable=true)
     */
    private $lastname;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\CalendarEvent", mappedBy="user")
     */
    private $events;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Factory", inversedBy="users")
     * @ORM\JoinColumn(name="factory_id", referencedColumnName="id")
     */
    private $factory;

}
Run Code Online (Sandbox Code Playgroud)

日历事件:

class CalendarEvent
{

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id; 

    /**
     * @var \DateTime
     * @ORM\Column(type="datetime", name="event_start")
     */
    private $startDate;

    /**
     * @var \DateTime
     * @ORM\Column(type="datetime", name="event_end")
     */
    private $endDate;

    /**
     * @var bool
     * @ORM\Column(name="isLoan", type="boolean")
     */
    private $isLoan = TRUE;

    /**
     * @ORM\ManyToOne(targetEntity="Factory")
     * @ORM\JoinColumn(name="factory_id", referencedColumnName="id", nullable = true)
     */
    private $factory;

    /**
     * @ORM\ManyToOne(targetEntity="UserBundle\Entity\User", inversedBy="events")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;
}
Run Code Online (Sandbox Code Playgroud)

我想做的是创建一个存储库函数,当UserRepository我在条目参数中使用工厂触发请求时,它会为我提供实际上是工厂的人...

为了实现这一目标,我尝试指定一个条件。这个条件应该是这样的:

select * from user where (
    (user.factory == $idfactory AND not loaned_to_other_factory) OR 
    (user.factory != $idfactory AND loaned_to_my_factory)
)
Run Code Online (Sandbox Code Playgroud)

要知道用户是否已借用到我的工厂,必须验证以下条件:

Does a record exist in CalendarEvent where startDate < NOW and endDate > NOW and loaned == true and factory == $factory
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用我的存储库来使用用户和/或条件,但我已经被该查询困扰了很长时间,我什至不习惯使用存储库,因为 findBy 方法在大多数情况下都可以正常工作......

Expression of type 'Doctrine\ORM\QueryBuilder' not allowed in this context.我尝试了这个,但这个变量有一个错误$notLoanedToOther

public function findByFactory($idFactory)
{
    $qb = $this->_em->createQueryBuilder();
    $qb->select('u')
    ->from($this->_entityName, 'u')
    ->leftJoin('u.events', 'e');

    $sub = $this->createQueryBuilder("e");
    $sub->select("e");
    $sub->from("CalendarEvent","e");
    $sub->where('e.user = u.id');
    $sub->andWhere('e.startDate < :now');
    $sub->andWhere('e.endDate > :now');

    $notLoanedToOther = $qb->where($qb->expr()->not($qb->expr()->exists($sub->getDQL())));

    $sub = $this->createQueryBuilder("e");
    $sub->select("e");
    $sub->from("CalendarEvent","e");
    $sub->where('e.user = u.id');
    $sub->where('e.factory = :idf');
    $sub->andWhere('e.startDate < :now');
    $sub->andWhere('e.endDate > :now');

    $loanedToMyFactory = $qb->where($qb->expr()->exists($sub->getDQL()));

    $condition1 = $qb->expr()->andX(
        $qb->expr()->eq('u.factory', ':idf'),
        $notLoanedToOther
    );

    $condition2 = $qb->expr()->andX(
        $qb->expr()->neq('u.factory', ':idf'),
        $loanedToMyFactory
    );

    $qb ->where($qb->expr()->orX($condition1, $condition2));

    $qb ->setParameter('idf', $idFactory);

    return $qb->getQuery()->getResult();
}
Run Code Online (Sandbox Code Playgroud)

我真的希望我说得有道理,有人可以给我一些建议来实现这一目标。提前致谢

M K*_*aid 6

我想你可以将你的存在查询翻译为不在

$notLoanedToOther = $this->createQueryBuilder("e")
                         ->select("e.user")
                         ->from("CalendarEvent","e")
                         ->andWhere('e.startDate < :now')
                         ->andWhere('e.endDate > :now')
                         ->getDQL();

$loanedToMyFactory = $this->createQueryBuilder("e")
                          ->select("e.user")
                          ->from("CalendarEvent","e")
                          ->where('e.factory = :idf')
                          ->andWhere('e.startDate < :now')
                          ->andWhere('e.endDate > :now')
                          ->getDQL();

$qb = $this->_em->createQueryBuilder();
 $qb->select('u')
    ->from($this->_entityName, 'u')
    ->where(
        $qb->expr()->not(
            $qb->expr()->in(
            'u.id',
            $notLoanedToOther
            )
        )
    )
    ->andWhere(
        $qb->expr()->in(
        'u.id',
        $loanedToMyFactory
        )   
    )
    ->where(
        $qb->expr()->orX(
                $qb->expr()->andX(
                    $qb->expr()->eq('u.factory', ':idf'),
                    $qb->expr()->not(
                        $qb->expr()->in(
                        'u.id',
                        $notLoanedToOther
                        )
                    )
                ), 
                $qb->expr()->andX(
                    $qb->expr()->neq('u.factory', ':idf'),
                    $qb->expr()->in(
                    'u.id',
                    $loanedToMyFactory
                    )
                )
            )
        )
    ->setParameter('idf', $idFactory)
    ->setParameter('now', $someDate)
    ;
Run Code Online (Sandbox Code Playgroud)

在 Doctrine 2 中执行 WHERE .. IN 子查询