<?php
namespace App\Entity;
use App\Entity\VenueRoom;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
use Doctrine\Common\Collections\Collection;
use Menke\UserBundle\Entity\Client;
use Menke\CommonsBundle\Entity\GenericEntity;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity(repositoryClass="App\Repository\CourseOccurrenceRepository")
* @JMS\ExclusionPolicy("all")
*/
class CourseOccurrence extends GenericEntity
{
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Venue")
* @ORM\JoinColumn(name="venueId", referencedColumnName="id")
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $venue;
/**
* @ORM\ManyToOne(targetEntity="VenueRoom")
* @ORM\JoinColumn(name="venueRoomId", referencedColumnName="id", nullable=true)
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $venueRoom;
/**
* @ORM\ManyToOne(targetEntity="Course", inversedBy="occurrences")
* @ORM\JoinColumn(name="courseId", referencedColumnName="id")
*/
protected $course;
/**
* @ORM\OneToMany(targetEntity="App\Entity\CourseOccurrenceTime", mappedBy="occurrence", orphanRemoval=true, cascade={"all"})
* @ORM\OrderBy({"start" = "ASC"})
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $times;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Person", mappedBy="courses")
*/
protected $customers;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Speaker")
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $speakers;
/**
* @ORM\Column(type="boolean")
*/
protected $published = false;
/**
* @ORM\Column(type="datetime")
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $start;
/**
* @ORM\Column(type="datetime")
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $end;
/**
* @ORM\Column(type="integer")
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $slots;
/**
* @ORM\Column(type="boolean")
* @JMS\Expose
* @JMS\Groups({"public"})
*/
protected $reservationAllowed = false;
/**
* @ORM\Column(type="integer")
*/
protected $bookedSlots = 0;
protected $pendingBookings = 0;
/**
* @ORM\OneToMany(targetEntity="App\Entity\WaitItem", mappedBy="courseOccurrence")
*/
protected $waitItems;
/**
* @ORM\OneToMany(targetEntity="App\Entity\OrderItem", mappedBy="courseOccurrence")
*/
protected $orderItems;
public function __construct()
{
$this->times = new ArrayCollection();
$this->speakers = new ArrayCollection();
$this->waitItems = new ArrayCollection();
}
/**
* @return Venue|null
*/
public function getVenue(): ?Venue
{
return $this->venue;
}
/**
* @param Venue|null $venue
* @return CourseOccurrence
*/
public function setVenue(?Venue $venue): self
{
$this->venue = $venue;
return $this;
}
/**
* @return VenueRoom|null
*/
public function getVenueRoom(): ?VenueRoom
{
return $this->venueRoom;
}
/**
* @param VenueRoom|null $venue
* @return CourseOccurrence
*/
public function setVenueRoom(?VenueRoom $venueRoom): self
{
$this->venueRoom = $venueRoom;
return $this;
}
/**
* @return Course
*/
public function getCourse(): ?Course
{
return $this->course;
}
/**
* @param Course $course
* @return CourseOccurrence
*/
public function setCourse(?Course $course)
{
$this->course = $course;
return $this;
}
/**
* @return Collection|CourseOccurrenceTime[]
*/
public function getTimes(): Collection
{
return $this->times;
}
/**
* @param mixed $times
* @return CourseOccurrence
*/
public function setTimes($times)
{
$this->times = $times;
return $this;
}
/**
* @param CourseOccurrenceTime $time
* @return CourseOccurrence
*/
public function addTime(CourseOccurrenceTime $time): self
{
if (!$this->times->contains($time)) {
$this->times[] = $time;
$time->setOccurrence($this);
}
return $this;
}
/**
* @param CourseOccurrenceTime $time
* @return CourseOccurrence
*/
public function removeTime(CourseOccurrenceTime $time): self
{
if ($this->times->contains($time)) {
$this->times->removeElement($time);
if ($time->getOccurrence() === $this) {
$time->setOccurrence(null);
}
}
return $this;
}
/**
* @return Collection|Speaker[]
*/
public function getSpeakers(): Collection
{
return $this->speakers;
}
/**
* @param Speaker $speaker
* @return CourseOccurrence
*/
public function addSpeaker(Speaker $speaker): self
{
if (!$this->speakers->contains($speaker)) {
$this->speakers[] = $speaker;
}
return $this;
}
/**
* @param Speaker $speaker
* @return CourseOccurrence
*/
public function removeSpeaker(Speaker $speaker): self
{
if ($this->speakers->contains($speaker)) {
$this->speakers->removeElement($speaker);
}
return $this;
}
/**
* @return null|string
*/
public function getTitle(): ?string
{
return $this->getCourse()->getTitle();
}
/**
* @return Category|null
*/
public function getCategory(): ?Category
{
return $this->getCourse()->getCategory();
}
/**
* @return float|null
*/
public function getPrice(): ?float
{
return $this->getCourse()->getPrice();
}
/**
* @return null|string
*/
public function getFullCaption(): ?string
{
$categoryName = $this->checkIfValueExists('categoryName');
$venue = $this->checkIfValueExists('venue');
$venueRoom = $this->checkIfValueExists('venueRoom');
if ($venue && $venueRoom) {
$place = $venue . ' ' . $venueRoom;
} else {
$place = $venue ?? $venueRoom;
}
$category = ($categoryName) ? ' Kategorie: ' . $categoryName : '';
return $this->getTitle() . ' (' . $this->getStart()->format('d.m.Y H:i') . ') '
. $place
. $category;
}
private function checkIfValueExists($value)
{
try {
switch ($value) {
case 'categoryName':
$result =
$this->getCourse()->getCategory()->getName();
break;
case 'venue':
$result =
$this->getVenue()->getName();
break;
case 'venueRoom':
$result =
$this->getVenueRoom()->getName();
break;
}
} catch (\Throwable $th) {
$result = '';
}
return $result;
}
/**
* @return bool|null
*/
public function getPublished(): ?bool
{
return $this->published;
}
/**
* @param bool $published
* @return CourseOccurrence
*/
public function setPublished(bool $published): self
{
$this->published = $published;
return $this;
}
/**
* @return bool
*/
public function isAvailable(): bool
{
// Check if occurrence is published
if (!$this->getPublished()) {
return false;
}
// Check if end date of course is past
$now = new \DateTime('now');
if ($this->getEnd()->format('U') < $now->format('U')) {
return false;
}
return true;
}
/**
* @return mixed
*/
public function getStart()
{
return $this->start;
}
/**
* @param \DateTimeInterface $start
* @return CourseOccurrence
*/
public function setStart(\DateTimeInterface $start): self
{
$this->start = $start;
return $this;
}
/**
* @return mixed
*/
public function getEnd()
{
return $this->end;
}
/**
* @param \DateTimeInterface $end
* @return CourseOccurrence
*/
public function setEnd(\DateTimeInterface $end): self
{
$this->end = $end;
return $this;
}
/**
* @return bool
*/
public function hasMultipleDays(): bool
{
return $this->getStart()->format('d.m.Y') !== $this->getEnd()->format('d.m.Y');
}
/**
* @return CourseOccurrence
*/
public function clone()
{
$entity = new CourseOccurrence();
$entity->setId(null);
$entity->setVenue($this->getVenue());
$entity->setStart($this->getStart());
$entity->setEnd($this->getEnd());
$entity->setSlots($this->getSlots());
foreach ($this->getSpeakers() as $speaker) {
$entity->addSpeaker($speaker);
}
foreach ($this->getTimes() as $time) {
$entity->addTime($time->clone());
}
return $entity;
}
/**
* Sets a new start date. Moves all other dates in relation to the new start date. This includes dates of related
* CourseOccurrenceTime entities.
*
* @param \DateTime $date
*/
public function setDate(\DateTime $date)
{
$date->add(new \DateInterval('P1D'));
$difference = $this->getStart()->diff($date);
$difference->h = 0;
$difference->i = 0;
$difference->s = 0;
$this->getStart()->add($difference);
$this->getEnd()->add($difference);
foreach ($this->getTimes() as $time) {
$time->moveDate($difference);
}
}
/**
* @return Client|null
*/
public function getClient(): ?Client
{
return $this->getCourse()->getClient();
}
/**
* @return null|string
*/
public function getNumber()
{
return $this->getCourse()->getNumber();
}
/**
* @return null|string
*/
public function getType()
{
return $this->getCourse()->getType();
}
/**
* @return Collection|CourseImage[]
*/
public function getImages(): Collection
{
return $this->getCourse()->getImages();
}
/**
* @return float|null
*/
public function getMaterialCost(): ?float
{
return $this->getCourse()->getMaterialCost();
}
/**
* @return int|null
*/
public function getTargetAgeMin(): ?int
{
return $this->getCourse()->getTargetAgeMin();
}
/**
* @return int|null
*/
public function getTargetAgeMax(): ?int
{
return $this->getCourse()->getTargetAgeMax();
}
/**
* @return bool
*/
public function hasTargetAge(): bool
{
return !empty($this->getTargetAgeMin()) || !empty($this->getTargetAgeMax());
}
/**
* @return Collection|CourseText[]
*/
public function getTexts(): Collection
{
return $this->getCourse()->getTexts();
}
/**
* @return null|string
*/
public function getDescription(): ?string
{
return $this->getCourse()->getDescription();
}
/**
* @return int|null
*/
public function getSlots(): ?int
{
return $this->slots;
}
/**
* @param int $slots
* @return CourseOccurrence
*/
public function setSlots(int $slots): self
{
$this->slots = $slots;
return $this;
}
/**
* @return bool|null
*/
public function getReservationAllowed(): ?bool
{
return $this->reservationAllowed;
}
/**
* @return bool|null
*/
public function isReservationAllowed(): ?bool
{
return $this->getReservationAllowed();
}
/**
* @param bool $reservationAllowed
* @return CourseOccurrence
*/
public function setReservationAllowed(bool $reservationAllowed): self
{
$this->reservationAllowed = $reservationAllowed;
return $this;
}
/**
* /**
* @JMS\Expose
* @JMS\Groups({"public"})
* @JMS\VirtualProperty()
* @JMS\Type("int")
* @return int|null
*/
public function getBookedSlots(): ?int
{
$bookedSlots = 0;
if ($this->getOrderItems() !== null) {
foreach ($this->getOrderItems() as $item) {
$order = $item->getOrder();
if (!$order->isCancelled() && !$item->isMaterialCost()) {
$bookedSlots += $item->getQuantity() - $item->getCancelledQuantity();
}
}
}
return $bookedSlots;
}
public function getBookedSlotsDirectly(): ?int
{
return $this->bookedSlots;
}
/**
* @param int $bookedSlots
* @return CourseOccurrence
*/
public function setBookedSlots(int $bookedSlots): self
{
$this->bookedSlots = $bookedSlots;
return $this;
}
/**
* @return int|null
*/
public function getFreeSlots(bool $directBooked = false): ?int
{
if ($directBooked === true) {
return $this->getSlots() - $this->getBookedSlotsDirectly();
} else {
return $this->getSlots() - $this->getBookedSlots();
}
}
/**
* @return null|string
*/
public function getReservationStatus(): ?string
{
$freeSlots = $this->getFreeSlots();
if ($freeSlots > 0) {
return 'Plätze frei';
} else {
if ($this->getReservationAllowed()) {
return 'ausgebucht - Reservierung möglich';
} else {
return 'ausgebucht';
}
}
}
/**
* @param int $quantity
* @return CourseOccurrence
*/
public function bookSlots(int $quantity): self
{
$this->pendingBookings += $quantity;
return $this;
}
/**
* @param int $quantity
* @return CourseOccurrence
*/
public function cancelSlots(int $quantity): self
{
$this->pendingBookings -= $quantity;
return $this;
}
/**
* Actually book pending slots
*/
public function flushBooking()
{
$bookedSlots = 0;
foreach ($this->getOrderItems() as $item) {
if (!$item->getCourseItem() && !$item->getOrder()->isCancelled() && !$item->isCancelled()) {
$bookedSlots += $item->getQuantity();
}
}
$this->bookedSlots = $bookedSlots;
}
/**
* @param int $numberOfBookings
* @return bool
*/
public function isBookable(int $numberOfBookings, bool $directBooked = false): bool
{
return $numberOfBookings <= $this->getFreeSlots($directBooked);
}
/**
* @return Collection|WaitItem[]
*/
public function getWaitItems(): Collection
{
return $this->waitItems;
}
/**
* @param WaitItem $waitItem
* @return CourseOccurrence
*/
public function addWaitItem(WaitItem $waitItem): self
{
if (!$this->waitItems->contains($waitItem)) {
$this->waitItems[] = $waitItem;
$waitItem->setCourseOccurrence($this);
}
return $this;
}
/**
* @param WaitItem $waitItem
* @return CourseOccurrence
*/
public function removeWaitItem(WaitItem $waitItem): self
{
if ($this->waitItems->contains($waitItem)) {
$this->waitItems->removeElement($waitItem);
// set the owning side to null (unless already changed)
if ($waitItem->getCourseOccurrence() === $this) {
$waitItem->setCourseOccurrence(null);
}
}
return $this;
}
/**
* @return int
*/
public function getWaitItemCount(): int
{
return count($this->waitItems);
}
/**
* @return bool
*/
public function hasWaitList(): bool
{
return $this->isReservationAllowed() && $this->getWaitItemCount() > 0;
}
/**
* @param CourseOccurrence $target
* @return CourseOccurrence
*/
public function moveWaitListTo(CourseOccurrence $target): self
{
foreach ($this->getWaitItems() as $waitItem) {
$this->removeWaitItem($waitItem);
$target->addWaitItem($waitItem);
}
return $this;
}
/**
* @return array
*/
public function getSpeakerNames()
{
$speakerNames = [];
foreach ($this->getSpeakers() as $speaker) {
$speakerNames[] = $speaker->getFullname();
}
return $speakerNames;
}
/**
* @return string
*/
public function getCaption()
{
return $this->getTitle() . ' (' . $this->getStart()->format('d.m.Y') . ')';
}
public function getKursstart()
{
return $this->getStart()->format('d.m.Y');
}
public function getKursende()
{
return $this->getEnd()->format('d.m.Y');
}
public function getTaxRate()
{
return $this->getCourse()->getTaxRate();
}
public function getKursstartendeuhrzeit()
{
return $this->getStart()->format('H:i') . ' bis ' . $this->getEnd()->format('H:i') . ' Uhr';
}
/**
* @JMS\Expose
* @JMS\Groups({"public"})
* @JMS\VirtualProperty()
* @JMS\Type("int")
* @return int
*/
public function getId(): ?int
{
return parent::getId();
}
/**
* @return OrderItem[]
*/
public function getOrderItems()
{
return $this->orderItems;
}
/**
*
*/
public function setOrderItems($orderItems)
{
$this->orderItems = $orderItems;
}
}