Всех приветствую.
Прошу помочь с задачей дублирования записей в БД, которые создаются при добавлении связанных сущностей.
Итак есть класс Room и связанный класс RoomRenter, у одного помещения может быть много арендаторов и у одного арендатора комнаты может быть только одна комната.
Мне необходимо соблюсти условия, чтобы в таблице RoomRenter были уникальны поля RoomId и RenterId.
Запрос на изменение данных по помещению приходит в виде:
{
"title": "Room #1",
"price": 200,
"square": 200,
"status": 2,
"isBusy": true,
"buildingId": 1,
"rentersId": [2,3]
}
Стандартная проверка из документации не проходит, т.к. нет сравнения по RenterId:
if (!$this->renters->contains($renter)) {
$this->renters[] = $renter;
$renter->setRoom($this);
}
Поэтому у меня родился такой код:
#[ORM\HasLifecycleCallbacks]
#[ORM\Entity(repositoryClass: RoomRepository::class)]
#[ORM\Table(name: "room", options: ['comment' => 'Помещение.'])]
class Room
{
...
/**
* @var Collection<RoomRenter>
*/
#[ORM\JoinColumn(nullable: true)]
#[ORM\OneToMany(mappedBy: 'room', targetEntity: RoomRenter::class, cascade: ["persist", "remove"], orphanRemoval: true)]
private Collection $renters;
/**
* @param RoomRenter $roomRenter
* @return $this
*/
public function addRenter(RoomRenter $roomRenter): self
{
$renterExists = false;
foreach ($this->renters as $renter) {
if ($roomRenter->getRenter()->getId() === $renter->getRenter()->getId()) {
$renterExists = true;
}
}
if (!$renterExists) {
$this->renters[] = $roomRenter;
$roomRenter->setRoom($this);
}
return $this;
}
/**
* @param RoomRenter $renter
* @return $this
*/
public function removeRenter(RoomRenter $renter): self
{
if ($this->renters->contains($renter)) {
$this->renters->removeElement($renter);
// setThe owning side to null (unless already changed)
if ($renter->getRoom() === $this) {
$renter->setRoom(null);
}
}
return $this;
}
...
}
#[ORM\HasLifecycleCallbacks]
#[ORM\Entity(repositoryClass: RoomRenterRepository::class)]
#[ORM\Table(name: "room_renter", options: ['comment' => 'Арендаторы в помещении.'])]
#[UniqueEntity(
fields: ['room', 'renter'],
message: 'This renter is already in use on that room.',
errorPath: 'renter',
)]
class RoomRenter {
...
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(targetEntity: Room::class)]
private ?Room $room;
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(targetEntity: Renter::class)]
private Renter $renter;
...
}
class RoomService {
...
private function upsertRoom(Room $room, RoomUpdateRequest $request): Room
{
$room->setTitle($request->getTitle());
$room->setPrice($request->getPrice());
$room->setStatus($request->getStatus());
$room->setIsBusy($request->isBusy());
$room->setSquare($request->getSquare());
if ($request->getRentersId()) {
$currentRenters = [];
if (!$room->getRenters()->isEmpty()) {
foreach ($room->getRenters() as $renter) {
if (!in_array($renter->getRenter()->getId(), $request->getRentersId(), true)) {
$room->removeRenter($renter);
} else {
$currentRenters[] = $renter->getRenter()->getId();
}
}
}
foreach ($request->getRentersId() as $renterId) {
if (!in_array($renterId, $currentRenters, true)) {
$room->addRenter(
(new RoomRenter())
->setTitle('Test room renter')
->setRenter($this->renterRepository->getRenter($renterId))
);
}
}
} else {
foreach ($room->getRenters() as $renter) {
$room->removeRenter($renter);
}
}
...
}
Может кто знает поизящнее способ?