<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
use App\Commons\Entity\GenericEntity;
use App\User\Entity\Client;
/**
* @ORM\Entity(repositoryClass="App\Repository\CourseRepository")
*
* @JMS\ExclusionPolicy("all")
*/
class Course extends GenericEntity
{
/**
* @ORM\ManyToOne(targetEntity="App\User\Entity\Client")
*
* @ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
protected $client;
/**
* @ORM\Column(type="string", length=255)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $title;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $subtitle;
/**
* @ORM\Column(type="string", length=255, options={"default" : "Course"})
*
* @JMS\Expose
*
* @JMS\Groups({"public", "personal"})
*/
protected $courseNature = 'Course';
/**
* @ORM\ManyToOne(targetEntity="App\Entity\CourseSubscription")
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $subscription;
/**
* @ORM\Column(type="text", nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $description;
/**
* @ORM\Column(type="text", nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $searchwords;
/**
* @ORM\Column(type="float")
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $price;
/**
* @ORM\Column(type="string", length=20, nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $rabatt;
/**
* @ORM\Column(type="float", nullable=true)
*/
protected $taxRate = 0;
/**
* @ORM\OneToMany(targetEntity="CourseOccurrence", mappedBy="course", cascade={"all"})
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $occurrences;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Category")
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $category;
/**
* @ORM\OneToMany(targetEntity="App\Entity\CourseImage", mappedBy="course", orphanRemoval=true, cascade={"all"})
*
* @ORM\OrderBy({"orderId" = "ASC"})
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $images;
/**
* @ORM\Column(type="string", length=20, nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $number;
/**
* @ORM\Column(type="float", nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $materialCost = 0.0;
/**
* @ORM\Column(type="integer", nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $targetAgeMin;
/**
* @ORM\Column(type="integer", nullable=true)
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $targetAgeMax;
/**
* @ORM\OneToMany(targetEntity="App\Entity\CourseText", mappedBy="course", orphanRemoval=true, cascade={"all"})
*
* @ORM\OrderBy({"orderId" = "ASC"})
*
* @JMS\Expose
*
* @JMS\Groups({"detail"})
*/
protected $texts;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\CourseSeries", inversedBy="courses")
*
* @JMS\Expose
*
* @JMS\Groups({"public"})
*/
protected $series;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\CourseType")
*
* @JMS\Expose
*
* @JMS\Groups({"public", "personal"})
*/
protected $type;
/**
* @ORM\Column(type="text", nullable=true)
*/
protected $invoiceUpperComment;
/**
* @ORM\Column(type="text", nullable=true)
*/
protected $invoiceLowerComment;
/**
* @ORM\Column(type="text", nullable=true)
*/
protected $invoiceLowerCommentDebit;
/**
* @ORM\OneToMany(
* targetEntity=CourseProvider::class,
* mappedBy="course",
* cascade={"persist"},
* orphanRemoval=true
* )
*
* DO NOT EXPOSE - use getProvidersApi() instead to avoid circular references
*/
private Collection $courseProviders;
/**
* @JMS\Expose
*
* @JMS\Groups({"public","detail"})
*
* @JMS\Type("array") // dein $testFields ist ein Array von Arrays
*/
public $fields = [];
// Existing properties and methods
public function __toString(): string
{
// Passe das Feld an: name, title o.รค.
return (string) ($this->getTitle() ?? ('Titel #'.($this->getId() ?? '')));
}
/**
* Set fields for the course.
*/
public function setFields(array $fields): void
{
$this->fields = $fields;
}
/**
* Get fields for the course.
*/
public function getFields(): array
{
return $this->fields;
}
public function __construct()
{
$this->occurrences = new ArrayCollection();
$this->images = new ArrayCollection();
$this->texts = new ArrayCollection();
$this->courseProviders = new ArrayCollection();
$this->fields = []; // <-- Array lassen
}
/** @return Collection<int, CourseProvider> */
public function getCourseProviders(): Collection
{
return $this->courseProviders;
}
public function addCourseProvider(CourseProvider $cp): self
{
if (!$this->courseProviders->contains($cp)) {
$this->courseProviders->add($cp);
$cp->setCourse($this);
}
return $this;
}
public function removeCourseProvider(CourseProvider $cp): self
{
if ($this->courseProviders->removeElement($cp)) {
if ($cp->getCourse() === $this) {
$cp->setCourse(null);
}
}
return $this;
}
/** Komfort: Direkt die Provider-Liste ableiten */
/** @return Collection<int, Provider> */
public function getProviders(): Collection
{
return new ArrayCollection(
$this->courseProviders
->map(fn (CourseProvider $cp) => $cp->getProvider())
->toArray()
);
}
public function getClient(): ?Client
{
return $this->client;
}
/**
* @param Client $client
*/
public function setClient($client): self
{
$this->client = $client;
return $this;
}
public function getTitle(): ?string
{
// $title = str_replace('­', '', $this->title);
// return $title;
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getSubtitle(): ?string
{
return $this->subtitle;
}
public function setSubtitle(?string $subtitle): self
{
$this->subtitle = $subtitle;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getSearchwords(): ?string
{
return $this->searchwords;
}
public function setSearchwords(?string $searchwords): self
{
$this->searchwords = $searchwords;
return $this;
}
public function getPrice(): ?float
{
return $this->price;
}
public function setPrice(float $price): self
{
$this->price = $price;
return $this;
}
public function getTaxRate(): float
{
return null === $this->taxRate ? 0.0 : $this->taxRate;
}
public function setTaxRate(?float $taxRate): self
{
$this->taxRate = $taxRate;
return $this;
}
/**
* @JMS\Expose
*
* @JMS\Groups({"detail"})
*
* @JMS\VirtualProperty()
*
* @JMS\Type("array<App\Entity\CourseOccurrence>")
*
* @return array<App\Entity\CourseOccurrence>
*/
public function getOccurrences(bool $onlyPublished = false, bool $isBookable = false): ArrayCollection
{
$occurrences = new ArrayCollection();
foreach ($this->occurrences as $occurrence) {
$occurrences->add($occurrence);
}
return $occurrences;
}
/**
* Liefert Provider als flaches Array fรผr die API.
* Umgeht damit Gruppen-/Serializer-Probleme.
*
* @JMS\VirtualProperty()
*
* @JMS\SerializedName("providers")
*
* @JMS\Groups({"public","detail"})
*/
public function getProvidersApi(): array
{
$out = [];
foreach ($this->getProviders() as $p) {
$out[] = [
'id' => $p->getId(),
'company' => $p->getCompany(),
'street' => $p->getStreet(),
'streetNumber' => $p->getStreetNumber(),
'postalCode' => $p->getPostalcode(),
'city' => $p->getCity(),
'web' => $p->getWeb(),
'phone' => $p->getPhone(),
];
}
return $out;
}
public function getAllOccurrences(bool $onlyPublished = false, bool $isBookable = false): ArrayCollection
{
$occurrences = new ArrayCollection();
foreach ($this->occurrences as $occurrence) {
if ($onlyPublished && !$occurrence->getPublished()) {
continue;
}
if ($isBookable && !$occurrence->isBookable()) {
continue;
}
// Beispiel fรผr zusรคtzliche Berechnungen
// $freeSlots = $occurrence->getSlots() - $occurrence->getBookedSlots();
// $occurrence->setFreeSlots($freeSlots); // Beispielmethodenaufruf
$occurrences->add($occurrence);
}
return $occurrences;
}
/**
* @param ArrayCollection<CourseOccurrence> $occurrences
*/
public function setOccurrences($occurrences): self
{
$this->occurrences = $occurrences;
return $this;
}
public function addOccurrence(CourseOccurrence $occurrence): self
{
$occurrence->setCourse($this);
$this->occurrences->add($occurrence);
return $this;
}
/**
* @return Course
*/
public function removeOccurrence(CourseOccurrence $occurrence)
{
if ($this->occurrences->contains($occurrence)) {
$this->occurrences->removeElement($occurrence);
if ($occurrence->getCourse() === $this) {
$occurrence->setCourse(null);
}
}
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
public function getCourseNature(): string
{
return $this->courseNature;
}
public function setCourseNature($courseNature)
{
$this->courseNature = $courseNature;
}
/**
* @return Collection|CourseImage[]
*/
public function getImages(): Collection
{
return $this->images;
}
public function addImage(CourseImage $image): self
{
if (!$this->images->contains($image)) {
$this->images[] = $image;
$image->setCourse($this);
}
return $this;
}
public function removeImage(CourseImage $image): self
{
if ($this->images->contains($image)) {
$this->images->removeElement($image);
// set the owning side to null (unless already changed)
if ($image->getCourse() === $this) {
$image->setCourse(null);
}
}
return $this;
}
public function getNumber(): ?string
{
return $this->number;
}
public function setNumber(?string $number): self
{
$this->number = $number;
return $this;
}
public function getMaterialCost(): ?float
{
return $this->materialCost;
}
public function setMaterialCost(?float $materialCost): self
{
$this->materialCost = $materialCost;
return $this;
}
public function getTargetAgeMin(): ?int
{
return $this->targetAgeMin;
}
public function setTargetAgeMin(?int $targetAgeMin): self
{
$this->targetAgeMin = $targetAgeMin;
return $this;
}
public function getTargetAgeMax(): ?int
{
return $this->targetAgeMax;
}
public function setTargetAgeMax(?int $targetAgeMax): self
{
$this->targetAgeMax = $targetAgeMax;
return $this;
}
/**
* @return Collection|CourseText[]
*/
public function getTexts(): Collection
{
return $this->texts;
}
public function addText(CourseText $text): self
{
if (!$this->texts->contains($text)) {
$this->texts[] = $text;
$text->setCourse($this);
}
return $this;
}
public function removeText(CourseText $text): self
{
if ($this->texts->contains($text)) {
$this->texts->removeElement($text);
// set the owning side to null (unless already changed)
if ($text->getCourse() === $this) {
$text->setCourse(null);
}
}
return $this;
}
public function getSeries(): ?CourseSeries
{
return $this->series;
}
public function setSeries(?CourseSeries $series): self
{
$this->series = $series;
return $this;
}
public function getSubscription(): ?CourseSubscription
{
return $this->subscription;
}
public function setSubscription(?CourseSubscription $subscription): self
{
$this->subscription = $subscription;
return $this;
}
/**
* @JMS\Expose
*
* @JMS\Groups({"public", "personal"})
*
* @JMS\VirtualProperty()
*
* @JMS\Type("int")
*/
public function getId(): ?int
{
return parent::getId();
}
public function getType(): ?CourseType
{
return $this->type;
}
/**
* @return CourseType
*/
public function setType(?CourseType $type): self
{
$this->type = $type;
return $this;
}
public function getInvoiceUpperComment(): ?string
{
return $this->invoiceUpperComment;
}
public function setInvoiceUpperComment(?string $invoiceUpperComment): self
{
$this->invoiceUpperComment = $invoiceUpperComment;
return $this;
}
public function getInvoiceLowerComment(): ?string
{
return $this->invoiceLowerComment;
}
public function setInvoiceLowerComment(?string $invoiceLowerComment): self
{
$this->invoiceLowerComment = $invoiceLowerComment;
return $this;
}
public function getInvoiceLowerCommentDebit(): ?string
{
return $this->invoiceLowerCommentDebit;
}
public function setInvoiceLowerCommentDebit(?string $invoiceLowerCommentDebit): self
{
$this->invoiceLowerCommentDebit = $invoiceLowerCommentDebit;
return $this;
}
/**
* @JMS\Expose
*
* @JMS\Groups({"public"})
*
* @JMS\VirtualProperty()
*
* @JMS\SerializedName("type")
*
* @JMS\Type("string")
*
* @return int
*/
public function getTypeSlug()
{
return $this->getType() ? $this->getType()->getSlug() : null;
}
public function isArchive(): ?bool
{
$onlyPublished = true;
$isBookable = false;
if (count($this->getAllOccurrences($onlyPublished, $isBookable)) < 1) {
return true;
}
$now = new \DateTime();
foreach ($this->getAllOccurrences($onlyPublished, $isBookable) as $occurrence) {
$diff = $now->diff($occurrence->getEnd());
if (0 == $diff->invert || $diff->d > $_ENV['DAYS_TO_ARCHIVE']) {
return false;
}
}
return true;
}
}