<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
use ApiPlatform\Core\Serializer\Filter\GroupFilter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use App\Repository\ProgramRepository;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass=ProgramRepository::class)
* @ApiResource(
* normalizationContext={
* "groups"={"program:read"}
* },
* denormalizationContext={
* "groups"={"program:write"}
* },
* collectionOperations={
* "get"={"security"="is_granted('ROLE_USER')"},
* "post"={"security"="is_granted('ROLE_ADMIN')"},
* "post_update"={
* "security"="is_granted('ROLE_ADMIN')",
* "path"="/programs/{id}",
* "description"="Update a Program with method POST (using content-type: 'multipart')",
* "method"="POST",
* "controller"="App\Controller\Api\ProgramController::update"
* },
* "post_clone"={
* "security"="is_granted('ROLE_ADMIN')",
* "path"="/programs/{id}/clone",
* "description"="Clone a program",
* "method"="POST",
* "deserialize"=false,
* "controller"="App\Controller\Api\ProgramController::clone"
* },
* "vitality_balance_recommended_programs_by_client"={
* "description"="Get vitality balance recommended programs by client.",
* "path"="/clients/{id}/vitality-balance/recommended-programs",
* "method"="GET",
* "controller"="App\Controller\Api\VitalityBalanceController::getVitalityBalanceRecommandedProgramsByClient",
* "security"="is_granted('ROLE_CLIENT')"
* }
* },
* itemOperations={
* "get"={"security"="is_granted('ROLE_USER')"},
* "delete"={"security"="is_granted('ROLE_ADMIN')"},
* "patch"={"security"="is_granted('ROLE_ADMIN')"},
* "activate_program"={
* "method"="GET",
* "controller"="App\Controller\Api\ProgramController::activate",
* "path"="/programs/{id}/activate",
* "security"="is_granted('ROLE_ADMIN')",
* "openapi_context"={"summary"="Activates a program"},
* },
* "deactivate_program"={
* "method"="GET",
* "controller"="App\Controller\Api\ProgramController::deactivate",
* "path"="/programs/{id}/deactivate",
* "security"="is_granted('ROLE_ADMIN')",
* "openapi_context"={"summary"="Deactivates a program"},
* }
* }
* )
* @ORM\HasLifecycleCallbacks()
* @ApiFilter(OrderFilter::class, properties={"id", "name", "rank", "active", "daysCount", "status"})
* @ApiFilter(SearchFilter::class, properties={"name": "partial", "status", "active", "objectives.id": "exact", "reEducation"})
* @ApiFilter(GroupFilter::class,
* arguments={
* "parameterName": "groups",
* "overrideDefaultGroups": true
* }
* )
* @ApiFilter(PropertyFilter::class,
* arguments={
* "parameterName"="fields",
* "overrideDefaultProperties"=true
* }
* )
*/
class Program
{
const STATUS_NEW = 'new';
const STATUS_ACTIVE = 'active';
const STATUS_DISABLED = 'disabled';
const STATUSES = [
self::STATUS_NEW,
self::STATUS_ACTIVE,
self::STATUS_DISABLED,
];
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({"program:read", "program:read:id", "slide:read", "search_engine", "objective:read", "homepage:read", "day:read", "simple", "survey:read",
* "program_list", "program_edit", "edit_day", "answer:read"})
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Groups({"program:read", "program:read:name", "program:write", "search_engine", "objective:read", "slide:read", "homepage:read", "day:read", "simple",
* "survey:read", "program_list", "program_edit", "edit_day", "answer:read", "objective_form_complete", "answer_recommended_objectives_edit"})
*/
private $name;
/**
* @ORM\Column(type="text", nullable=true)
* @Groups({"program:read", "program:read:content", "program:write", "search_engine", "objective:read", "slide:read", "program_edit", "program_list"})
*/
private $content = null;
/**
* @ORM\Column(type="datetime")
* @Groups({"program:read", "program:read:createdAt", "program_list"})
* @Gedmo\Timestampable(on="create")
*/
private $createdAt;
/**
* @ORM\Column(type="datetime")
* @Groups({"program:read", "program:read:updatedAt"})
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
/**
* @ORM\OneToMany(targetEntity=Day::class, mappedBy="program", orphanRemoval=true, cascade={"persist", "refresh", "remove"})
* @Groups({"program:read", "program:read:days"})
* @ApiSubresource(maxDepth=1)
*/
private $days;
/**
* @ORM\Column(type="integer")
* @Groups({"program:read", "program:read:daysCount", "program:write", "search_engine", "objective:read", "slide:read", "program_list", "program_edit", "program_list"})
*/
private $daysCount;
/**
* @ORM\Column(type="string", length=255)
* @Groups({"program:read", "program:read:status", "program_list", "program_list"})
*/
private $status = self::STATUS_NEW;
/**
* @ORM\Column(name="`rank`", type="integer")
* @Groups({"program:read", "program:read:rank", "program:write", "program_list"})
*/
private $rank;
/**
* @ORM\Column(type="boolean", options={"default": "0"})
* @Groups({"program:read", "program:read:reEducation", "program:write"})
*/
private $reEducation = false;
/**
* @ORM\ManyToMany(targetEntity=Survey::class, mappedBy="programs", cascade={"persist", "refresh", "remove"})
* @Groups({"program:read", "program:read:survey"})
*/
private $surveys;
/**
* @ORM\OneToMany(targetEntity=Slide::class, mappedBy="program")
*/
private $slides;
/**
* @ORM\ManyToOne(targetEntity=MediaObject::class)
* @Groups({"program:read", "program:read:picture", "program:write", "slide:read", "search_engine", "objective:read", "homepage:read", "program_edit", "program_list"})
*/
private $picture;
/**
* @ORM\ManyToOne(targetEntity=MediaObject::class)
* @Groups({"program:read", "program:read:avatar", "program:write", "search_engine", "objective:read", "homepage:read", "program_edit", "program_list"})
*/
private $avatar;
/**
* @ORM\ManyToOne(targetEntity=MediaObject::class)
* @Groups({"program:read", "program:read:illustration", "program:write", "slide:read", "search_engine", "objective:read", "homepage:read", "program_edit", "program_list"})
*/
private $illustration;
/**
* @ORM\ManyToOne(targetEntity=MediaObject::class)
* @Groups({"program:read", "program:read:tip", "program:write", "program_edit", "program_list"})
*/
private $tip;
/**
* @ORM\Column(type="boolean", options={"default": "0"})
* @Groups({"program:read", "program:read:active", "program:write"})
*/
private $active = false;
/**
* @ORM\ManyToMany(targetEntity=TvTag::class)
* @Groups({"program:read", "program:read:tvTags", "program:write", "program_edit"})
*/
private $tvTags;
/**
* @ORM\Column(type="text", nullable=true)
* @Groups({"program:read", "program:read:stringifyTags"})
*/
private $stringifyTags = '';
/**
* @ORM\ManyToOne(targetEntity=TvCompany::class, inversedBy="programs")
*/
private $tvCompany;
/**
* @ORM\ManyToOne(targetEntity=Company::class, inversedBy="programs")
* @Groups({"program:read", "program:read:company", "program:write", "program_edit"})
*/
private $company;
/**
* @ORM\OneToMany(targetEntity=ProgramEvent::class, mappedBy="program", cascade={"persist", "refresh", "remove"}, orphanRemoval=true)
*/
private $programEvents;
/**
* @ORM\ManyToMany(targetEntity=Objective::class, mappedBy="programs")
*/
private $objectives;
/**
* @ORM\Column(type="boolean", options={"default": 0})
* @Groups({"program:read", "program:read:itCanInterrest", "program:write"})
*/
private $itCanInterrest = false;
/**
* Custom field
* @var ArrayCollection|null
* Get experts from video's day
* @Groups({"program:read", "program:read:experts"})
*/
private $experts = null;
/**
* Custom field
* @var int|null
* @Groups({"program:read:expertsCount", "search_engine", "objective:read", "program_list"})
*/
private $expertsCount = null;
/**
* Custom field
* @var ArrayCollection|null
* Get videos from days
* @Groups({"program:read:videos"})
*/
private $videos = null;
/**
* Custom field
* @var int|null
* @Groups({"program:read:videosCount", "search_engine", "objective:read", "program_list"})
*/
private $videosCount = null;
/**
* Custom field
* @var ArrayCollection|null
* Get videos from days
* @Groups({"program:read:activeVideos"})
*/
private $activeVideos = null;
/**
* Custom field
* @var int|null
* @Groups({"program:read:activeVideosCount", "search_engine", "objective:read", "program_list"})
*/
private $activeVideosCount = null;
/**
* Custom field
* @var Day|null
* @Groups({"program:read", "program:read:currentDay"})
*/
public $currentDay = null;
/**
* Custom field
* @Groups({"program:read", "program:read:categories", "search_engine"})
*/
public $categories = null;
/**
* Custom field
* @var array
* @Groups({"program:read", "program:read:moodAfterPostResponses", "program_edit"})
*/
public $moodAfterPostResponses = null;
/**
* Custom field
* @Groups({"program:read", "program:read:flags", "program:write", "slide:read", "search_engine", "objective:read", "homepage:read"})
*/
public $flags = null;
/**
* Custom field
* @var ?int
* @Groups({"program:read", "program:read:daysCompletedCount", "program:write", "slide:read", "search_engine", "objective:read", "homepage:read"})
*/
public $daysCompletedCount = null;
public function __construct()
{
$this->days = new ArrayCollection();
$this->surveys = new ArrayCollection();
$this->slides = new ArrayCollection();
$this->tvTags = new ArrayCollection();
$this->programEvents = new ArrayCollection();
$this->objectives = new ArrayCollection();
}
public function __clone()
{
$this->id = null;
$this->company = null;
$this->status = self::STATUS_NEW;
$this->slides = new ArrayCollection();
// $this->tvTags = new ArrayCollection();
$this->programEvents = new ArrayCollection();
$this->objectives = new ArrayCollection();
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
$this->active = false;
// Clone Days
$days = new ArrayCollection();
foreach ($this->days->toArray() as $day) {
$newDay = clone $day;
$newDay->setProgram($this);
$days->add($newDay);
}
$this->days = $days;
// Add This Program into TvTags
// foreach($this->tvTags->toArray() as $tvTag) {
// $tvTag->addProgram($this);
// }
// @TODO : Dois-je copier les Questionnaires ?
$surveys = new ArrayCollection();
foreach($this->surveys->toArray() as $survey) {
$newSurvey = clone $survey;
$newSurvey->addProgram($this);
$surveys->add($newSurvey);
}
$this->surveys = $surveys;
// Clone des MediaObject : Doit-on copier les images ?
// $this->picture = clone $this->picture;
// $this->avatar = clone $this->avatar;
// $this->illustration = clone $this->illustration;
// $this->tip = clone $this->tip;
$this->picture = null;
$this->avatar = null;
$this->illustration = null;
$this->tip = null;
}
public function getId(): ?int
{
return $this->id;
}
public function setId(?int $id): self
{
$this->id = $id;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
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|Day[]
*/
public function getDays(): Collection
{
return $this->days;
}
public function addDay(Day $day): self
{
if (!$this->days->contains($day)) {
$this->days[] = $day;
$day->setProgram($this);
}
return $this;
}
public function removeDay(Day $day): self
{
if ($this->days->removeElement($day)) {
// set the owning side to null (unless already changed)
if ($day->getProgram() === $this) {
$day->setProgram(null);
}
}
return $this;
}
public function getDaysCount(): ?int
{
return $this->daysCount;
}
public function setDaysCount(int $daysCount): self
{
$this->daysCount = $daysCount;
return $this;
}
/**
* Creates a single day
* @param int $rank
* @return Day
*/
private function instantiateDay(int $rank = 0): Day
{
$day = new Day();
$day->setName("Jour $rank du programme: '{$this->name}'");
$day->setContent("Descriptif du jour $rank du programme: '{$this->name}'");
$day->setRank($rank);
$day->setProgram($this);
$day->setStatus($this->status);
return $day;
}
/**
* Appends days to the list
* @param int $count
* @param int $addon
*/
private function createDays(int $count, int $addon = 1){
$start = ($this->days->count() + $addon);
for ($n = 0; $n < $count; $n++) {
$this->addDay($this->instantiateDay($n + $start));
}
}
private function deleteDays(int $count){
$start = ($this->days->count() - $count);
if ($start < 0){
$start = 0;
}
foreach ($this->days as $key=>$day) {
if ($key >= $start){
$this->removeDay($day);
}
}
}
/**
* Instantiates the necessary number of days
*/
public function instantiateDays()
{
if ($this->id == null) {
$this->createDays($this->daysCount, 0);
} elseif ($this->daysCount != $this->days->count()) { //this means it's an update event
if ($this->daysCount > $this->days->count()){
$this->createDays($this->daysCount - $this->days->count());
}else{
$this->deleteDays($this->days->count() - $this->daysCount);
}
}
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
if ($this->status == self::STATUS_ACTIVE) {
$this->active = true;
} else {
$this->active = false;
}
return $this;
}
public function getRank(): ?int
{
return $this->rank;
}
public function setRank(int $rank): self
{
$this->rank = $rank;
return $this;
}
public function getReEducation(): ?bool
{
return $this->reEducation;
}
public function isReEducation(): ?bool
{
return $this->reEducation;
}
public function setReEducation(bool $reEducation): self
{
$this->reEducation = $reEducation;
return $this;
}
/**
* @return Collection|Survey[]
*/
public function getSurveys(): Collection
{
return $this->surveys;
}
public function addSurvey(Survey $survey): self
{
if (!$this->surveys->contains($survey)) {
$this->surveys[] = $survey;
$survey->addProgram($this);
}
return $this;
}
public function removeSurvey(Survey $survey): self
{
if ($this->surveys->removeElement($survey)) {
$survey->removeProgram($this);
}
return $this;
}
/**
* @return Collection|Slide[]
*/
public function getSlides(): Collection
{
return $this->slides;
}
public function addSlide(Slide $slide): self
{
if (!$this->slides->contains($slide)) {
$this->slides[] = $slide;
$slide->setProgram($this);
}
return $this;
}
public function removeSlide(Slide $slide): self
{
if ($this->slides->removeElement($slide)) {
// set the owning side to null (unless already changed)
if ($slide->getProgram() === $this) {
$slide->setProgram(null);
}
}
return $this;
}
public function getPicture(): ?MediaObject
{
return $this->picture;
}
public function setPicture(?MediaObject $picture): self
{
$this->picture = $picture;
return $this;
}
/**
* @Groups({"program:write"})
*/
public function setPictureFile($file = null): self
{
if($file instanceof UploadedFile) {
$picture = empty($this->picture) ? new MediaObject : $this->picture;
$picture->setFile($file);
$this->setPicture($picture);
}
return $this;
}
public function getAvatar(): ?MediaObject
{
return $this->avatar;
}
public function setAvatar(?MediaObject $avatar): self
{
$this->avatar = $avatar;
return $this;
}
/**
* @Groups({"program:write"})
*/
public function setAvatarFile($file = null): self
{
if($file instanceof UploadedFile) {
$avatar = empty($this->avatar) ? new MediaObject : $this->avatar;
$avatar->setFile($file);
$this->setAvatar($avatar);
}
return $this;
}
public function getIllustration(): ?MediaObject
{
return $this->illustration;
}
public function setIllustration(?MediaObject $illustration): self
{
$this->illustration = $illustration;
return $this;
}
/**
* @Groups({"program:write"})
*/
public function setIllustrationFile($file = null): self
{
if($file instanceof UploadedFile) {
$illustration = empty($this->illustration) ? new MediaObject : $this->illustration;
$illustration->setFile($file);
$this->setIllustration($illustration);
}
return $this;
}
public function getExperts(): ?Collection
{
$experts = new ArrayCollection;
foreach ($this->days as $day) {
foreach ($day->getPlaylist()->getVideos() as $video) {
if($video->getActive()) {
foreach ($video->getExperts() as $expert) {
if(!$experts->contains($expert)) {
$experts->add($expert);
}
}
}
}
}
if(!$experts->isEmpty()) $this->experts = $experts;
return $this->experts;
}
public function getExpertsCount(): ?int
{
if(!is_null($this->getExperts())) {
$this->expertsCount = $this->getExperts()->count();
}
return $this->expertsCount;
}
public function getVideos(): ?Collection
{
$videos = new ArrayCollection;
foreach ($this->days as $day) {
foreach ($day->getPlaylist()->getVideos() as $video) {
if(!$videos->contains($video)) {
$videos->add($video);
}
}
}
if(!$videos->isEmpty()) $this->videos = $videos;
return $this->videos;
}
public function getVideosCount(): ?int
{
if(!is_null($this->getVideos())) {
$this->videosCount = $this->getVideos()->count();
}
return $this->videosCount;
}
public function getActiveVideos(): ?Collection
{
$videos = new ArrayCollection;
foreach ($this->days as $day) {
foreach ($day->getPlaylist()->getVideos() as $video) {
if($video->getActive() && !$videos->contains($video)) {
$videos->add($video);
}
}
}
if(!$videos->isEmpty()) $this->activeVideos = $videos;
return $this->activeVideos;
}
public function getActiveVideosCount(): ?int
{
if(!is_null($this->getActiveVideos())) {
$this->activeVideosCount = $this->getActiveVideos()->count();
}
return $this->activeVideosCount;
}
/**
* @Groups({"program:read", "program:read:tipsCount", "search_engine", "objective:read"})
*/
public function getTipsCount(): int
{
$count = 0;
foreach ($this->days as $day) {
foreach ($day->getPlaylist()->getVideos() as $video) {
if ($video instanceof Video && $video->getTip() instanceof MediaObject) {
$count++;
}
}
}
return $count;
}
public function getTip(): ?MediaObject
{
return $this->tip;
}
public function setTip(?MediaObject $tip): self
{
$this->tip = $tip;
return $this;
}
public function getActive(): ?bool
{
return $this->active;
}
public function setActive(bool $active): self
{
$this->active = $active;
if ($this->active) {
$this->status = self::STATUS_ACTIVE;
} else {
$this->status = self::STATUS_DISABLED;
}
return $this;
}
/**
* @return Collection|TvTag[]
*/
public function getTvTags(): Collection
{
return $this->tvTags;
}
/**
* @return Program
* @Groups({"program:write"})
*/
public function setTvTags(Collection $tvTags): self
{
$this->tvTags = $tvTags;
foreach ($this->tvTags as $tvTag) {
$this->stringifyTags .= "#".$tvTag->getName();
}
return $this;
}
public function addTvTag(TvTag $tvTag): self
{
if (!$this->tvTags->contains($tvTag)) {
$this->tvTags[] = $tvTag;
}
return $this;
}
public function removeTvTag(TvTag $tvTag): self
{
$this->tvTags->removeElement($tvTag);
return $this;
}
public function getStringifyTags(): ?string
{
return $this->stringifyTags;
}
public function setStringifyTags(?string $stringifyTags): self
{
$this->stringifyTags = $stringifyTags;
return $this;
}
public function getTvCompany(): ?TvCompany
{
return $this->tvCompany;
}
public function setTvCompany(?TvCompany $tvCompany): self
{
$this->tvCompany = $tvCompany;
return $this;
}
public function getCompany(): ?Company
{
return $this->company;
}
public function setCompany(?Company $company): self
{
$this->company = $company;
return $this;
}
/**
* @return Collection|ProgramEvent[]
*/
public function getProgramEvents(): Collection
{
return $this->programEvents;
}
public function addProgramEvent(ProgramEvent $programEvent): self
{
if (!$this->programEvents->contains($programEvent)) {
$this->programEvents[] = $programEvent;
$programEvent->setProgram($this);
}
return $this;
}
public function removeProgramEvent(ProgramEvent $programEvent): self
{
if ($this->programEvents->removeElement($programEvent)) {
// set the owning side to null (unless already changed)
if ($programEvent->getProgram() === $this) {
$programEvent->setProgram(null);
}
}
return $this;
}
/**
* @return Collection|Objective[]
*/
public function getObjectives(): Collection
{
return $this->objectives;
}
public function addObjective(Objective $objective): self
{
if (!$this->objectives->contains($objective)) {
$this->objectives[] = $objective;
$objective->addProgram($this);
}
return $this;
}
public function removeObjective(Objective $objective): self
{
if ($this->objectives->removeElement($objective)) {
$objective->removeProgram($this);
}
return $this;
}
public function getItCanInterrest(): ?bool
{
return $this->itCanInterrest;
}
public function setItCanInterrest(bool $itCanInterrest): self
{
$this->itCanInterrest = $itCanInterrest;
return $this;
}
}