*/ #[ORM\ManyToMany(targetEntity: User::class)] #[ORM\JoinTable(name: 'chill_main_notification_addresses_user')] private Collection $addressees; /** * @var Collection */ #[ORM\ManyToMany(targetEntity: UserGroup::class)] #[ORM\JoinTable(name: 'chill_main_notification_addressee_user_group')] private Collection $addresseeUserGroups; /** * @deprecated * a list of destinee which will receive notifications * * @var array|string[] */ #[ORM\Column(type: Types::JSON, options: ['default' => '[]', 'jsonb' => true])] private array $addressesEmails = []; /** * @deprecated * a list of emails adresses which were added to the notification * * @var array|string[] */ private array $addressesEmailsAdded = []; private ?ArrayCollection $addressesOnLoad = null; /** * @var Collection */ #[ORM\OneToMany(mappedBy: 'notification', targetEntity: NotificationComment::class, orphanRemoval: true)] #[ORM\OrderBy(['createdAt' => \Doctrine\Common\Collections\Criteria::ASC])] private Collection $comments; #[ORM\Column(type: Types::DATETIME_IMMUTABLE)] private \DateTimeImmutable $date; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: Types::INTEGER)] private ?int $id = null; #[ORM\Column(type: Types::TEXT)] private string $message = ''; #[ORM\Column(type: Types::STRING, length: 255)] private string $relatedEntityClass = ''; #[ORM\Column(type: Types::INTEGER)] private int $relatedEntityId; private array $removedAddresses = []; #[ORM\ManyToOne(targetEntity: User::class)] #[ORM\JoinColumn(nullable: true)] private ?User $sender = null; #[Assert\NotBlank(message: 'notification.Title must be defined')] #[ORM\Column(type: Types::TEXT, options: ['default' => ''])] private string $title = ''; /** * @var Collection */ #[ORM\ManyToMany(targetEntity: User::class)] #[ORM\JoinTable(name: 'chill_main_notification_addresses_unread')] private Collection $unreadBy; #[ORM\Column(type: Types::DATETIME_IMMUTABLE)] private ?\DateTimeImmutable $updatedAt = null; #[ORM\ManyToOne(targetEntity: User::class)] private ?User $updatedBy = null; #[ORM\Column(name: 'type', type: Types::STRING, nullable: true)] private string $type; public function __construct() { $this->addressees = new ArrayCollection(); $this->addresseeUserGroups = new ArrayCollection(); $this->unreadBy = new ArrayCollection(); $this->comments = new ArrayCollection(); $this->setDate(new \DateTimeImmutable()); $this->accessKey = bin2hex(openssl_random_pseudo_bytes(24)); } public function addAddressee(User|UserGroup $addressee): self { if ($addressee instanceof User) { if (!$this->addressees->contains($addressee)) { $this->addressees->add($addressee); return $this; } } $this->addresseeUserGroups->add($addressee); return $this; } /** * @deprecated */ public function addAddressesEmail(string $email) { if (!\in_array($email, $this->addressesEmails, true)) { $this->addressesEmails[] = $email; $this->addressesEmailsAdded[] = $email; } } public function addComment(NotificationComment $comment): self { if (!$this->comments->contains($comment)) { $this->comments[] = $comment; $comment->setNotification($this); } return $this; } public function addUnreadBy(User $user): self { if (!$this->unreadBy->contains($user)) { $this->unreadBy[] = $user; } return $this; } /** * @param array $payload */ #[Assert\Callback] public function assertCountAddresses(ExecutionContextInterface $context, $payload): void { if (0 === (\count($this->getAddresseeUserGroups()) + \count($this->getAddressees()))) { $context->buildViolation('notification.At least one addressee') ->atPath('addressees') ->addViolation(); } } /** * @return Collection */ public function getAddresseeUserGroups(): Collection { return $this->addresseeUserGroups; } public function setAddresseeUserGroups(Collection $addresseeUserGroups): void { $this->addresseeUserGroups = $addresseeUserGroups; } public function getAccessKey(): string { return $this->accessKey; } public function getAddedAddresses(): array { return $this->addedAddresses; } /** * @return Collection|User[] */ public function getAddressees(): Collection { // keep a copy to compute changes later if (null === $this->addressesOnLoad) { $this->addressesOnLoad = new ArrayCollection($this->addressees->toArray()); } return $this->addressees; } public function getAllAddressees(): array { $allUsers = []; foreach ($this->getAddressees() as $user) { $allUsers[$user->getId()] = $user; } foreach ($this->getAddresseeUserGroups() as $userGroup) { foreach ($userGroup->getUsers() as $user) { $allUsers[$user->getId()] = $user; } } return array_values($allUsers); } /** * @return array|string[] * * @deprecated */ public function getAddressesEmails(): array { return $this->addressesEmails; } /** * @return array|string[] * * @deprecated */ public function getAddressesEmailsAdded(): array { return $this->addressesEmailsAdded; } public function getComments(): Collection { return $this->comments; } public function getDate(): ?\DateTimeImmutable { return $this->date; } public function getId(): ?int { return $this->id; } public function getMessage(): ?string { return $this->message; } public function getRelatedEntityClass(): ?string { return $this->relatedEntityClass; } public function getRelatedEntityId(): ?int { return $this->relatedEntityId; } public function getSender(): ?User { return $this->sender; } public function getTitle(): string { return $this->title; } public function getUnreadBy(): Collection { return $this->unreadBy; } public function getUpdatedAt(): ?\DateTimeImmutable { return $this->updatedAt; } public function getUpdatedBy(): ?User { return $this->updatedBy; } public function isReadBy(User $user): bool { return !$this->unreadBy->contains($user); } public function isSystem(): bool { return null === $this->sender; } public function markAsReadBy(User $user): self { return $this->removeUnreadBy($user); } public function markAsUnreadBy(User $user): self { return $this->addUnreadBy($user); } #[ORM\PreFlush] public function registerUnread() { foreach ($this->addedAddresses as $addressee) { $this->addUnreadBy($addressee); } foreach ($this->removedAddresses as $addressee) { $this->removeAddressee($addressee); } if (null !== $this->addressesOnLoad) { foreach ($this->addressees as $existingAddresse) { if (!$this->addressesOnLoad->contains($existingAddresse)) { $this->addUnreadBy($existingAddresse); } } foreach ($this->addressesOnLoad as $onLoadAddressee) { if (!$this->addressees->contains($onLoadAddressee)) { $this->removeUnreadBy($onLoadAddressee); } } } $this->removedAddresses = []; $this->addedAddresses = []; $this->addressesOnLoad = null; } public function removeAddressee(User|UserGroup $addressee): self { if ($addressee instanceof User) { if ($this->addressees->contains($addressee)) { $this->addressees->removeElement($addressee); return $this; } } $this->addresseeUserGroups->removeElement($addressee); return $this; } /** * @deprecated */ public function removeAddressesEmail(string $email) { if (\in_array($email, $this->addressesEmails, true)) { $this->addressesEmails = array_filter($this->addressesEmails, static fn ($e) => $e !== $email); $this->addressesEmailsAdded = array_filter($this->addressesEmailsAdded, static fn ($e) => $e !== $email); } } public function removeComment(NotificationComment $comment): self { $this->comments->removeElement($comment); return $this; } public function removeUnreadBy(User $user): self { $this->unreadBy->removeElement($user); return $this; } public function setDate(\DateTimeImmutable $date): self { $this->date = $date; return $this; } public function setMessage(?string $message): self { $this->message = (string) $message; return $this; } public function setRelatedEntityClass(string $relatedEntityClass): self { $this->relatedEntityClass = $relatedEntityClass; return $this; } public function setRelatedEntityId(int $relatedEntityId): self { $this->relatedEntityId = $relatedEntityId; return $this; } public function setSender(?User $sender): self { $this->sender = $sender; return $this; } public function setTitle(?string $title): Notification { $this->title = (string) $title; return $this; } public function setUpdatedAt(\DateTimeInterface $datetime): self { $this->updatedAt = $datetime; return $this; } public function setUpdatedBy(User $user): self { $this->updatedBy = $user; return $this; } public function setType(string $type): self { $this->type = $type; return $this; } public function getType(): string { return $this->type; } public function isSendImmediately(User $user): bool { $notificationFlags = $user->getNotificationFlags(); $notificationType = $this->getType(); // Check if the user has a preference for this notification type $emailPreference = $notificationFlags[$notificationType] ?? null; return 'immediate-email' === $emailPreference; } }