<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\ExistsFilter;
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
use App\Repository\NotificationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass=NotificationRepository::class)
* @ApiResource(
* normalizationContext={"groups"={"notification:read"}},
* denormalizationContext={"groups"={"notification:write"}},
* itemOperations={
* "get"={
* "security"="is_granted('ROLE_ADMIN') or is_granted('ROLE_COMPANY')",
* "security_message"="You are not allowed to access this ressource"
* },
* "patch"={
* "security"="is_granted('ROLE_ADMIN') or is_granted('ROLE_COMPANY')"
* },
* "delete"={
* "security"="is_granted('ROLE_ADMIN') or is_granted('ROLE_COMPANY')"
* }
* },
* collectionOperations={
* "get"={
* "security"="is_granted('ROLE_ADMIN') or is_granted('ROLE_COMPANY')"
* },
* "post"={
* "security"="is_granted('ROLE_ADMIN') or is_granted('ROLE_COMPANY')"
* },
* "get_last_unread_by_user"={
* "description"="Get last notifications by User (for App).",
* "path"="/users/{id}/last-unread-notifications",
* "method"="GET",
* "controller"="App\Controller\Api\NotificationController::getLastUnreadNotificationsByUser",
* "security"="is_granted('ROLE_ADMIN') or is_granted('ROLE_CLIENT')"
* }
* }
* )
* @ApiFilter(OrderFilter::class,
* properties={
* "id", "title", "message", "planFor", "sendAt", "status", "template", "active",
* "createdAt", "updatedAt", "type.name"
* }
* )
* @ApiFilter(SearchFilter::class, properties={
* "type.name": "partial", "title": "partial", "message": "partial", "status"
* })
* @ApiFilter(BooleanFilter::class, properties={"active", "template"})
* @ApiFilter(DateFilter::class, properties={"planFor", "sendAt", "createdAt"})
* @ApiFilter(ExistsFilter::class, properties={"title", "message", "link", "planFor", "sendAt"})
* @ApiFilter(PropertyFilter::class,
* arguments={
* "parameterName"="fields",
* "overrideDefaultProperties"=true
* }
* )
*/
class Notification
{
const STATUS_PENDING = "pending";
const STATUS_SUCCESS = "success";
const STATUS_FAILURE = "failure";
const STATUS_CANCELED = "canceled";
const STATUS_SENT = "sent";
const STATUS_SCHEDULED = "scheduled";
const STATUSES = [
self::STATUS_PENDING,
self::STATUS_SUCCESS,
self::STATUS_FAILURE,
self::STATUS_CANCELED,
self::STATUS_SENT,
self::STATUS_SCHEDULED,
];
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({"notification:read", "notification:read:id"})
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=NotificationType::class, inversedBy="notifications")
* @Groups({"notification:read", "notification:write", "notification:read:type"})
*/
private $type;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Groups({"notification:read", "notification:write", "notification:read:title"})
*/
private $title;
/**
* @ORM\Column(type="text", nullable=true)
* @Groups({"notification:read", "notification:write", "notification:read:message"})
*/
private $message;
/**
* @ORM\Column(type="json", nullable=true)
* @Groups({"notification:read", "notification:write", "notification:read:body"})
*/
private $body = [];
/**
* @ORM\Column(type="datetime", nullable=true)
* @Groups({"notification:read", "notification:write", "notification:read:planFor"})
*/
private $planFor;
/**
* @ORM\Column(type="datetime", nullable=true)
* @Groups({"notification:read", "notification:write", "notification:read:sendAt"})
*/
private $sendAt;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\Choice(choices=self::STATUSES)
* @Groups({"notification:read", "notification:write", "notification:read:status"})
*/
private $status = self::STATUS_PENDING;
/**
* @ORM\Column(type="boolean", nullable=true, options={"default": "0"})
* @Assert\NotNull()
* @Groups({"notification:read", "notification:write", "notification:read:template"})
*/
private $template = false;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Groups({"notification:read", "notification:write", "notification:read:link"})
*/
private $link;
/**
* @ORM\Column(type="boolean", nullable=true, options={"default": "1"})
* @Assert\NotNull()
* @Groups({"notification:read", "notification:write", "notification:read:active"})
*/
private $active = true;
/**
* @ORM\Column(type="json", nullable=true)
* @Groups({"notification:read"})
*/
private $metadata = [];
/**
* @ORM\Column(type="datetime", nullable=true)
* @Gedmo\Timestampable(on="create")
* @Groups({"notification:read", "notification:read:createdAt"})
*/
private $createdAt;
/**
* @ORM\Column(type="datetime", nullable=true)
* @Gedmo\Timestampable(on="update")
* @Groups({"notification:read"})
*/
private $updatedAt;
/**
* @ORM\OneToMany(targetEntity=UserNotification::class, mappedBy="notification", orphanRemoval=true, cascade={"persist", "remove"})
*/
private $userNotifications;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Groups({"notification:read", "notification:write"})
*/
private $onesignalId;
/**
* @ORM\Column(type="json", nullable=true)
* @Groups({"notification:read", "notification:write"})
*/
private $deviceTokens = [];
/**
* Custom Fields
*/
/**
* Summary of companies
* @var mixed
* @Groups({"notification:read", "notification:write"})
*/
private $companies;
/**
* Summary of $users
* @var mixed
* @Groups({"notification:read", "notification:write"})
*/
private $users;
/**
* @Groups({"notification:read"})
* @var int|null
*/
private $usersCount = 0;
/**
* @Groups({"notification:read"})
* @var int|null
*/
private $companiesCount = 0;
public function __construct()
{
$this->companies = new ArrayCollection();
$this->users = new ArrayCollection();
$this->userNotifications = new ArrayCollection();
$this->createdAt = (new \DateTime("now", new \DateTimeZone("Europe/Paris")));
$this->updatedAt = (new \DateTime("now", new \DateTimeZone("Europe/Paris")));
}
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?NotificationType
{
return $this->type;
}
public function setType(?NotificationType $type): self
{
$this->type = $type;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
return $this;
}
public function getBody(): ?array
{
return $this->body;
}
public function setBody(?array $body): self
{
$this->body = $body;
return $this;
}
public function getPlanFor(): ?\DateTimeInterface
{
return $this->planFor;
}
public function setPlanFor(?\DateTimeInterface $planFor): self
{
$this->planFor = $planFor;
return $this;
}
public function getSendAt(): ?\DateTimeInterface
{
return $this->sendAt;
}
public function setSendAt(?\DateTimeInterface $sendAt): self
{
$this->sendAt = $sendAt;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): self
{
$this->status = $status;
return $this;
}
public function isTemplate(): ?bool
{
return $this->template;
}
public function setTemplate(?bool $template): self
{
$this->template = $template;
return $this;
}
public function isActive(): ?bool
{
return $this->active;
}
public function setActive(?bool $active): self
{
$this->active = $active;
return $this;
}
public function getMetadata(): ?array
{
return $this->metadata;
}
public function setMetadata(?array $metadata): self
{
$this->metadata = $metadata;
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;
}
public function getMessage(): ?string
{
return $this->message;
}
public function setMessage(?string $message): self
{
$this->message = $message;
return $this;
}
public function getLink(): ?string
{
return $this->link;
}
public function setLink(?string $link): self
{
$this->link = $link;
return $this;
}
/**
* @return Collection<int, UserNotification>
*/
public function getUserNotifications(): Collection
{
return $this->userNotifications;
}
public function setUserNotifications(array $userNotifications): self
{
$this->userNotifications = new ArrayCollection($userNotifications);
return $this;
}
public function addUserNotification(UserNotification $userNotification): self
{
if (!$this->userNotifications->contains($userNotification)) {
$this->userNotifications[] = $userNotification;
$userNotification->setNotification($this);
}
return $this;
}
public function removeUserNotification(UserNotification $userNotification): self
{
if ($this->userNotifications->removeElement($userNotification)) {
// set the owning side to null (unless already changed)
if ($userNotification->getNotification() === $this) {
$userNotification->setNotification(null);
}
}
return $this;
}
/**
* @Groups({"notification:read"})
* @return Collection<int, Company>
*/
public function getCompanies(): Collection
{
if(empty($this->companies)) $this->companies = new ArrayCollection;
foreach($this->userNotifications as $userNotification) {
if(empty($userNotification->getUser()) && $userNotification->getCompany() instanceof Company) {
$this->companies->add($userNotification->getCompany());
}
}
return $this->companies ?? new ArrayCollection;
}
public function setCompanies(array $companies)
{
$this->companies = new ArrayCollection;
foreach ($companies as $company) {
$this->addCompany($company);
}
return $this;
}
public function addCompany(Company $company)
{
if(!$this->companies->contains($company)) {
$userNotification = new UserNotification;
$userNotification
->setNotification($this)
->setCompany($company)
;
}
return $this->addUserNotification($userNotification);
}
public function removeCompany(Company $company)
{
if($this->companies->contains($company)) {
foreach ($this->userNotifications as $userNotification) {
if(empty($userNotification->getUser()) && $userNotification->getCompany() instanceof Company) {
return $this->removeUserNotification($userNotification);
}
}
}
return $this;
}
/**
* @Groups({"notification:read"})
* @return Collection<int, User>
*/
public function getUsers(): Collection
{
if(empty($this->users)) $this->users = new ArrayCollection;
foreach($this->userNotifications as $userNotification) {
if($userNotification->getUser() instanceof User) {
$this->users->add($userNotification->getUser());
}
}
return $this->users;
}
public function addUser(User $user)
{
foreach ($this->getUserNotifications() as $userNotification) {
if ($userNotification->getUser() === $user) {
return $this;
}
}
$userNotification = (new UserNotification())
->setUser($user)
->setDeviceToken($user->getDeviceToken() ?: null)
->setCompany($user->getCompany())
->setNotification($this);
return $this->addUserNotification($userNotification);
}
public function removeUser(User $user)
{
foreach ($this->getUserNotifications() as $userNotification) {
if ($userNotification->getUser() === $user) {
return $this->removeUserNotification($userNotification);
}
}
return $this;
}
public function getOnesignalId(): ?string
{
return $this->onesignalId;
}
public function setOnesignalId(?string $onesignalId): self
{
$this->onesignalId = $onesignalId;
return $this;
}
public function getDeviceTokens(): ?array
{
return $this->deviceTokens;
}
public function setDeviceTokens(?array $deviceTokens): self
{
$this->deviceTokens = $deviceTokens;
return $this;
}
public function getUsersCount()
{
foreach ($this->getUserNotifications() as $userNotification) {
if($userNotification instanceof UserNotification
&& $userNotification->getUser() instanceof User
) {
$this->usersCount ++;
}
}
return $this->usersCount;
}
public function getCompaniesCount()
{
foreach ($this->getUserNotifications() as $userNotification) {
if($userNotification instanceof UserNotification
&& empty($userNotification->getUser())
&& $userNotification->getCompany() instanceof Company
) {
$this->companiesCount ++;
}
}
return $this->companiesCount;
}
public function metadataActionsCount(?string $action = null)
{
$sentCount = $canceledCount= 0;
foreach ($this->metadata as $date => $metadata) {
switch ($metadata['action'] ?? null) {
case self::STATUS_SENT:
$sentCount++;
break;
case self::STATUS_CANCELED:
$canceledCount++;
break;
default:
break;
}
}
switch ($action ?? null) {
case self::STATUS_SENT:
return $sentCount;
case self::STATUS_CANCELED:
return $canceledCount;
default:
return [
'sentCount' => $sentCount,
'canceledCount' => $canceledCount,
];
}
}
/**
* @Groups({"notification:read"})
* @return int
*/
public function getMetadataSentCount(): int
{
return $this->metadataActionsCount(self::STATUS_SENT);
}
/**
* @Groups({"notification:read"})
* @return int
*/
public function getMetadataCanceledCount(): int
{
return $this->metadataActionsCount(self::STATUS_CANCELED);
}
}