Doctrine 自定义实体存储库 (QueryBuilder)

Doctrine custom entity repository (QueryBuilder)

我们为 Room 实体创建自定义存储库 QueryBuilder, 将 return 两个日期之间的所有可用房间。我有两个实体 Room.php 和 Reservation.php

在 RoomRepository.php 我创建 function findAvailableRooms($from, $to) Hove 我创建查询生成器谁 return 所有在选定的时间段内没有预订的房间? Tnx

Room.php

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Controller\AvailableRoom;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Bridge\Doctrine\IdGenerator\UuidV4Generator;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Uid\Uuid;
use App\Repository\RoomRepository;
use Doctrine\ORM\Mapping as ORM;
use App\Controller\AvailableRoomController;

/**
 * @ApiResource(
 *     normalizationContext={"groups"={"room:read"}},
 *     denormalizationContext={"groups"={"room:write"}},
 *     attributes={
 *         "pagination_client_items_per_page"=true
 *     },
 *     collectionOperations={
 *         "get",
 *         "post",
 *         "get_available"={
 *             "method"="GET",
 *             "path"="/rooms/available/{from}/{to}",
 *             "controller"=AvailableRoomController::class
 *         }
 *     }
 * )
 * @ORM\Entity(repositoryClass=RoomRepository::class)
 */
class Room
{
    /**
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class=UuidV4Generator::class)
     * @Groups({"room:read"})
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"room:read", "room:write", "reservation:read"})
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=255)
     * @Gedmo\Slug(fields={"name"})
     * @Groups({"room:read", "room:write"})
     */
    private $slug;

    /**
     * @ORM\Column(type="text", nullable=true)
     * @Groups({"room:read", "room:write"})
     */
    private $description;

    /**
     * @ORM\Column(type="datetime")
     * @Gedmo\Timestampable(on="create")
     * @Groups({"room:read", "room:write"})
     */
    private $createdAt;

    /**
     * @ORM\Column(type="datetime")
     * @Gedmo\Timestampable(on="update")
     * @Groups({"room:read", "room:write"})
     */
    private $updatedAt;

    /**
     * @ORM\OneToMany(targetEntity=Reservation::class, mappedBy="room")
     * @Groups({"room:read", "room:write"})
     */
    private $reservations;

    public function __construct()
    {
        $this->reservations = new ArrayCollection();
    }

    public function getId(): ?Uuid
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): self
    {
        $this->slug = $slug;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(?string $description): self
    {
        $this->description = $description;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->createdAt;
    }

    public function setCreatedAt(?\DateTimeInterface $createdAt): self
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getUpdatedAt(): ?\DateTimeInterface
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * @return Collection|Reservation[]
     */
    public function getReservations(): Collection
    {
        return $this->reservations;
    }

    public function addReservation(Reservation $reservation): self
    {
        if (!$this->reservations->contains($reservation)) {
            $this->reservations[] = $reservation;
            $reservation->setRoom($this);
        }

        return $this;
    }

    public function removeReservation(Reservation $reservation): self
    {
        if ($this->reservations->removeElement($reservation)) {
            // set the owning side to null (unless already changed)
            if ($reservation->getRoom() === $this) {
                $reservation->setRoom(null);
            }
        }

        return $this;
    }
}

Reservation.php

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use App\Repository\ReservationRepository;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Bridge\Doctrine\IdGenerator\UuidV4Generator;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Uid\Uuid;

/**
 * @ApiResource(
 *     normalizationContext={"groups"={"reservation:read"}},
 *     denormalizationContext={"groups"={"reservation:write"}},
 *     attributes={
 *         "pagination_client_items_per_page"=true
 *     }
 * )
 * @ApiFilter(DateFilter::class, properties={"dateFrom"})
 * @ORM\Entity(repositoryClass=ReservationRepository::class)
 */
class Reservation
{
    /**
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class=UuidV4Generator::class)
     * @Groups({"reservation:read"})
     */
    private $id;

    /**
     * @ORM\Column(type="date")
     * @Groups({"reservation:read", "reservation:write", "room:read"})
     */
    private $dateFrom;

    /**
     * @ORM\Column(type="date")
     * @Groups({"reservation:read", "reservation:write", "room:read"})
     */
    private $dateTo;

    /**
     * @ORM\Column(type="json", nullable=true)
     * @Groups({"reservation:read", "reservation:write", "room:read"})
     */
    private $meta = [];

    /**
     * @ORM\ManyToOne(targetEntity=Room::class, inversedBy="reservations")
     * @Groups({"reservation:read", "reservation:write"})
     */
    private $room;

    /**
     * @ORM\Column(type="datetime")
     * @Gedmo\Timestampable(on="create")
     * @Groups({"reservation:read", "reservation:write", "room:read"})
     */
    private $createdAt;

    /**
     * @ORM\Column(type="datetime")
     * @Gedmo\Timestampable(on="update")
     * @Groups({"reservation:read", "reservation:write", "room:read"})
     */
    private $updatedAt;

    public function getId(): ?Uuid
    {
        return $this->id;
    }

    public function getDateFrom(): ?\DateTimeInterface
    {
        return $this->dateFrom;
    }

    public function setDateFrom(\DateTimeInterface $dateFrom): self
    {
        $this->dateFrom = $dateFrom;

        return $this;
    }

    public function getDateTo(): ?\DateTimeInterface
    {
        return $this->dateTo;
    }

    public function setDateTo(\DateTimeInterface $dateTo): self
    {
        $this->dateTo = $dateTo;

        return $this;
    }

    public function getMeta(): ?array
    {
        return $this->meta;
    }

    public function setMeta(?array $meta): self
    {
        $this->meta = $meta;

        return $this;
    }

    public function getRoom(): ?Room
    {
        return $this->room;
    }

    public function setRoom(?Room $room): self
    {
        $this->room = $room;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->createdAt;
    }

    public function setCreatedAt(?\DateTimeInterface $createdAt): self
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getUpdatedAt(): ?\DateTimeInterface
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }
}

类似于以下放置在您的 ReservationRepository 中的方法将获取具有 Reservation 与指定日期范围重叠的 Room 的 ID:

  /**
   * @param \DateTimeInterface $start
   * @param \DateTimeInterface $end
   *
   * @return array
   */
  public function findRoomIdsReservedInDateRange(\DateTimeInterface $start, \DateTimeInterface $end)
  {
    $result = $this
      ->createQueryBuilder('r')
      ->select('r.room.id')
      ->andWhere('r.dateFrom < :end')
      ->andWhere('r.dateTo > :start')
      ->setParameter('start', $start)
      ->setParameter('end', $end)
      ->orderBy('r.room.id', 'ASC')
      ->getQuery()
      ->getScalarResult()
    ; // [['id' => 1], ['id' => 2], ['id' => 2], ['id' => 5]]

    return array_unique(array_column($result, 'id')); // [1, 2, 5]
  }

然后您可以从 RoomRepository

中调用该方法
$exclude = $reservationRepository->findRoomIdsReservedInDateRange($start, $end);

return $this
  ->createQueryBuilder('room')
  ->andWhere('room.id not in :array')
  ->setParameter('array', $exclude)
  ->getQuery()
  ->getResult()
  ;