<?php
namespace App\Entity;
use App\Repository\EmailTemplateRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\AttributeOverrides;
use Doctrine\ORM\Mapping\AttributeOverride;
use Doctrine\ORM\Mapping\Column;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Serializable;
use Doctrine\Common\Collections\Criteria;
/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
* @ORM\HasLifecycleCallbacks()
* @UniqueEntity("username")
* @Vich\Uploadable
*/
class User implements \Utixodev\FicBundle\Entity\UserInterface, UserInterface, Serializable
{
const STATUS_ACTIVE = 'active';
const STATUS_SUSPENDED = 'suspended';
const STATUS_TERMINATED = 'terminated';
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=180, unique=true)
* @Assert\NotNull()
*/
private $username;
/**
* @ORM\Column(type="json")
*/
private $roles = [];
/**
* @var string The hashed password
* @ORM\Column(type="string")
* @Assert\NotNull()
*/
private $password;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Email()
* @Assert\NotNull()
*/
private $email;
/**
* @ORM\Column(type="datetime")
*/
private $created_at;
/**
* @ORM\Column(type="datetime", nullable=true)
* @Assert\NotNull
*/
private $last_login;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Contact", mappedBy="user", fetch="EXTRA_LAZY")
*/
private $contacts;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Email", mappedBy="user")
*/
private $emails;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Campaign", mappedBy="user", orphanRemoval=true)
*/
private $campaigns;
/**
* @ORM\OneToMany(targetEntity="App\Entity\ContactGroup", mappedBy="user", orphanRemoval=true)
*/
private $contactGroups;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $company;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $website;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $logo;
/**
* @Vich\UploadableField(mapping="uploads", fileNameProperty="logo")
*/
private $logo_file;
/**
* @ORM\Column(type="datetime")
*/
private $updated_at;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $address;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $from_address;
/**
* @ORM\OneToMany(targetEntity="App\Entity\ApiToken", mappedBy="user", orphanRemoval=true)
*/
private $apiTokens;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Form", mappedBy="user", orphanRemoval=true)
*/
private $forms;
/**
* @ORM\Column(type="json")
*/
private $send_count;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Plan", inversedBy="users")
* @Assert\NotNull()
*/
private $plan;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Task", mappedBy="user")
* @ORM\OrderBy({"created_at" = "DESC"})
*/
private $tasks;
/**
* @ORM\OneToMany(targetEntity=Notification::class, mappedBy="user")
*/
private $notifications;
/**
* @ORM\OneToMany(targetEntity=EmailTemplate::class, mappedBy="user")
*/
private $emailTemplates;
/**
* @ORM\OneToMany(targetEntity=Upload::class, mappedBy="user", orphanRemoval=true)
*/
private $uploads;
/**
* @ORM\Column(type="string", length=255)
*/
private $status;
/**
* @ORM\OneToMany(targetEntity=Domain::class, mappedBy="user", orphanRemoval=true)
*/
private $domains;
/**
* @ORM\OneToOne(targetEntity=CustomFields::class, mappedBy="user", cascade={"persist", "remove"})
*/
private $customFields;
/**
* @ORM\ManyToMany(targetEntity=Addon::class, inversedBy="users")
*/
private $addons;
public function __construct()
{
$this->contacts = new ArrayCollection();
$this->emails = new ArrayCollection();
$this->campaigns = new ArrayCollection();
$this->contactGroups = new ArrayCollection();
$this->apiTokens = new ArrayCollection();
$this->forms = new ArrayCollection();
$this->tasks = new ArrayCollection();
$this->notifications = new ArrayCollection();
$this->emailTemplates = new ArrayCollection();
$this->uploads = new ArrayCollection();
$this->domains = new ArrayCollection();
$this->addons = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUsername(): string
{
return (string) $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;
return $this;
}
/**
* Gets triggered only on insert
* @ORM\PrePersist
*/
public function setCreatedAtValue()
{
$this->setCreatedAt(new \DateTime());
}
/**
* Gets triggered only on update
* @ORM\PreUpdate
*/
public function updateLastLoginValue(){
$this->setLastLogin(new \DateTime());
}
public function getLastLogin(): ?\DateTimeInterface
{
return $this->last_login;
}
public function setLastLogin(?\DateTimeInterface $last_login): self
{
$this->last_login = $last_login;
return $this;
}
/**
* @param Bool $showDeleted
* @return Collection|Contact[]
*/
public function getContacts(bool $showDeleted = false): Collection
{
if($showDeleted){
return $this->contacts;
} else {
return $this->contacts->filter(function(Contact $contact){
return $contact->getStatus() != 'deleted' && $contact->getStatus() != 'unsubscribed';
});
}
}
/**
* @param String $status
* @return Collection|Contact[]
*/
public function getContactsByStatus($status): Collection
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('status', $status));
return $this->getContacts(true)->matching($criteria);
}
public function addContact(Contact $contact): self
{
if (!$this->contacts->contains($contact)) {
$this->contacts[] = $contact;
$contact->setUser($this);
}
return $this;
}
public function removeContact(Contact $contact): self
{
if ($this->contacts->contains($contact)) {
$this->contacts->removeElement($contact);
// set the owning side to null (unless already changed)
if ($contact->getUser() === $this) {
$contact->setUser(null);
}
}
return $this;
}
/**
* @return Collection|Email[]
*/
public function getEmails(): Collection
{
return $this->emails;
}
public function addEmail(Email $email): self
{
if (!$this->emails->contains($email)) {
$this->emails[] = $email;
$email->setUser($this);
}
return $this;
}
public function removeEmail(Email $email): self
{
if ($this->emails->contains($email)) {
$this->emails->removeElement($email);
// set the owning side to null (unless already changed)
if ($email->getUser() === $this) {
$email->setUser(null);
}
}
return $this;
}
/**
* @return Collection|Campaign[]
*/
public function getCampaigns(): Collection
{
return $this->campaigns;
}
/**
* @return Collection|Campaign[]
*/
public function getActiveCampaigns(): Collection
{
return $this->campaigns->filter(function(Campaign $campaign){
return $campaign->getActive() === true;
});
}
/**
* @return Collection|Campaign[]
*/
public function getCampaignsToSend(): Collection
{
return $this->campaigns->filter(function(Campaign $campaign){
return ($campaign->getActive() === true && $campaign->isSent() === false);
});
}
public function addCampaign(Campaign $campaign): self
{
if (!$this->campaigns->contains($campaign)) {
$this->campaigns[] = $campaign;
$campaign->setUser($this);
}
return $this;
}
public function removeCampaign(Campaign $campaign): self
{
if ($this->campaigns->contains($campaign)) {
$this->campaigns->removeElement($campaign);
// set the owning side to null (unless already changed)
if ($campaign->getUser() === $this) {
$campaign->setUser(null);
}
}
return $this;
}
/**
* @return Collection|ContactGroup[]
*/
public function getContactGroups(): Collection
{
return $this->contactGroups;
}
public function addContactGroup(ContactGroup $contactGroup): self
{
if (!$this->contactGroups->contains($contactGroup)) {
$this->contactGroups[] = $contactGroup;
$contactGroup->setUser($this);
}
return $this;
}
public function removeContactGroup(ContactGroup $contactGroup): self
{
if ($this->contactGroups->contains($contactGroup)) {
$this->contactGroups->removeElement($contactGroup);
// set the owning side to null (unless already changed)
if ($contactGroup->getUser() === $this) {
$contactGroup->setUser(null);
}
}
return $this;
}
public function getCompany(): ?string
{
return $this->company;
}
public function setCompany(string $company): self
{
$this->company = $company;
return $this;
}
public function getWebsite(): ?string
{
return $this->website;
}
public function setWebsite(?string $website): self
{
$this->website = $website;
return $this;
}
public function getLogo(): ?string
{
return $this->logo;
}
public function setLogo(?string $logo): self
{
$this->logo = $logo;
return $this;
}
public function getLogoFile(): ?File
{
return $this->logo_file;
}
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $imageFile
*/
public function setLogoFile(?File $imageFile = null): void
{
$this->logo_file = $imageFile;
if (null !== $imageFile) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updated_at = new \DateTimeImmutable();
}
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updated_at;
}
public function setUpdatedAt(\DateTimeInterface $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}
public function serialize()
{
return serialize([
$this->id,
$this->username,
$this->password,
$this->roles,
$this->email,
$this->created_at,
$this->updated_at,
$this->last_login,
//$this->contacts,
$this->emails,
//$this->campaigns,
//$this->contactGroups,
$this->website,
$this->company,
$this->logo
]);
}
public function unserialize($serialized)
{
list(
$this->id,
$this->username,
$this->password,
$this->roles,
$this->email,
$this->created_at,
$this->updated_at,
$this->last_login,
//$this->contacts,
$this->emails,
//$this->campaigns,
//$this->contactGroups,
$this->website,
$this->company,
$this->logo
) = unserialize($serialized);
}
public function getAddress(): ?string
{
return $this->address;
}
public function setAddress(string $address): self
{
$this->address = $address;
return $this;
}
public function getFromAddress(): ?string
{
return $this->from_address;
}
public function setFromAddress(string $from_address): self
{
$this->from_address = $from_address;
return $this;
}
/**
* @return Collection|ApiToken[]
*/
public function getApiTokens(): Collection
{
return $this->apiTokens;
}
public function addApiToken(ApiToken $apiToken): self
{
if (!$this->apiTokens->contains($apiToken)) {
$this->apiTokens[] = $apiToken;
$apiToken->setUser($this);
}
return $this;
}
public function removeApiToken(ApiToken $apiToken): self
{
if ($this->apiTokens->contains($apiToken)) {
$this->apiTokens->removeElement($apiToken);
// set the owning side to null (unless already changed)
if ($apiToken->getUser() === $this) {
$apiToken->setUser(null);
}
}
return $this;
}
/**
* @return Collection|Form[]
*/
public function getForms(): Collection
{
return $this->forms;
}
public function addForm(Form $form): self
{
if (!$this->forms->contains($form)) {
$this->forms[] = $form;
$form->setUser($this);
}
return $this;
}
public function removeForm(Form $form): self
{
if ($this->forms->contains($form)) {
$this->forms->removeElement($form);
// set the owning side to null (unless already changed)
if ($form->getUser() === $this) {
$form->setUser(null);
}
}
return $this;
}
public function getSendCount(): ?array
{
if(is_array($this->send_count) && count($this->send_count) === 31){
return $this->send_count;
} else {
return [];
}
}
public function resetSendCount(): self
{
$sendCount = array();
for($i = 0; $i < 31; $i++){
$sendCount[] = 0;
}
$this->setSendCount($sendCount);
return $this;
}
public function setSendCount(array $send_count): self
{
$this->send_count = $send_count;
return $this;
}
public function getPlan(): ?Plan
{
return $this->plan;
}
public function setPlan(?Plan $plan): self
{
$this->plan = $plan;
return $this;
}
public function updatePlan(?Plan $plan): self
{
/** @var Plan $currentPlan */
$currentPlan = $this->plan;
// if upgrade
if ($plan->getMonthlyLimit() > $currentPlan->getMonthlyLimit()) {
$this->plan = $plan;
} else {
// TODO if downgrade, only change plan at the end of plan cycle?
$this->plan = $plan;
}
return $this;
}
public function increaseSendCount(int $add = 1): self
{
// Get daily counts array
$sendCount = $this->getSendCount();
// Get last element of send count, increase count and put it back in array
$latestCount = array_pop($sendCount);
$sendCount[] = $latestCount + $add;
$this->setSendCount($sendCount);
return $this;
}
public function sendingAllowanceBalanced(): array
{
$allowance = array();
$plan = $this->getPlan();
$sendCount = $this->getSendCount();
if($plan->getDailyLimit() != 0){
$dayCount = $sendCount[count($sendCount) - 1];
$allowance['day'] = $dayAllowance = $plan->getDailyLimit() - $dayCount;
}
if($plan->getWeeklyLimit() != 0){
$i = count($sendCount) - 1;
$weekCount = 0;
while($i >= count($sendCount) - 7){
$weekCount += $sendCount[$i];
$i--;
}
$allowance['week'] = $weekAllowance = $plan->getWeeklyLimit() - $weekCount;
}
if($plan->getMonthlyLimit() != 0){
// Get number of days to this day the last month
$today = new \DateTime();
$monthAgo = new \DateTime();
$monthAgo->sub(new \DateInterval('P1M'));
$diff = date_diff($today, $monthAgo);
$monthDays = $diff->days;
$i = count($sendCount) - 1;
$monthCount = 0;
while($i >= count($sendCount) - $monthDays){
$monthCount += $sendCount[$i];
$i--;
}
$allowance['month'] = $monthAllowance = $plan->getMonthlyLimit() - $monthCount;
}
return $allowance;
}
public function sendingAllowanceCyclic(): array
{
$allowance = array();
$plan = $this->getPlan();
$sendCount = $this->getSendCount();
$baseDate = $this->getCreatedAt();
$now = new \DateTime();
$baseDate->setTime(0,0);
$now->setTime(0,0);
$diff = $baseDate->diff($now);
if($plan->getDailyLimit() != 0){
$dayCount = $sendCount[count($sendCount) - 1];
$allowance['day'] = $dayAllowance = $plan->getDailyLimit() - $dayCount;
}
if($plan->getWeeklyLimit() != 0){
$i = count($sendCount) - 1;
$weekCount = 0;
while($i >= count($sendCount) - ($diff->days % 7)){
$weekCount += $sendCount[$i];
$i--;
}
$allowance['week'] = $weekAllowance = $plan->getWeeklyLimit() - $weekCount;
}
if($plan->getMonthlyLimit() != 0){
$i = count($sendCount) - 1;
$monthCount = 0;
while($i >= count($sendCount) - ($diff->d)){
$monthCount += $sendCount[$i];
$i--;
}
$allowance['month'] = $monthAllowance = $plan->getMonthlyLimit() - $monthCount;
}
return $allowance;
}
public function sendingAllowanceCyclicDates(): array
{
$allowanceDates = array();
$plan = $this->getPlan();
$sendCount = $this->getSendCount();
$baseDate = $this->getCreatedAt();
$now = new \DateTime();
$baseDate->setTime(0,0);
$now->setTime(0,0);
$diff = $baseDate->diff($now);
if($plan->getDailyLimit() != 0){
$dayDate = clone $now;
$allowanceDates['day'] = $dayDate->add(new \DateInterval('P1D'));
}
if($plan->getWeeklyLimit() != 0){
$weekDate = clone $now;
$allowanceDates['week'] = $weekDate->add(new \DateInterval('P' . (7 - ($diff->days % 7)) . 'D'));
}
if($plan->getMonthlyLimit() != 0){
$monthDate = clone $now;
$allowanceDates['month'] = $monthDate->sub(new \DateInterval('P' . $diff->d . 'D'))->add(new \DateInterval('P1M'));
}
return $allowanceDates;
}
/**
* @return Collection|Task[]
*/
public function getTasks(): Collection
{
return $this->tasks;
}
/**
* @return Collection|Task[]
*/
public function getTasksNotUnfreeze(): Collection
{
return $this->tasks->filter(function (Task $task){
return $task->getType() != Task::TYPE_CAMPAIGN_UNFREEZE;
});
}
/**
* @return Collection|Task[]
*/
public function getPendingTasks(): Collection
{
return $this->tasks->filter(function (Task $task) {
return !$task->isFinished();
});
}
/**
* @return Collection|Task[]
*/
public function getPendingTasksNotUnfreeze(): Collection
{
return $this->tasks->filter(function (Task $task) {
return !$task->isFinished() && $task->getType() != Task::TYPE_CAMPAIGN_UNFREEZE;
});
}
/**
* @return Collection|Task[]
*/
public function getFinishedTasks(): Collection
{
return $this->tasks->filter(function (Task $task){
return $task->isFinished();
});
}
/**
* @return Collection|Task[]
*/
public function getFinishedTasksNotUnfreeze(): Collection
{
return $this->tasks->filter(function (Task $task){
return $task->isFinished() && $task->getType() != Task::TYPE_CAMPAIGN_UNFREEZE;
});
}
public function addTask(Task $task): self
{
if (!$this->tasks->contains($task)) {
$this->tasks[] = $task;
$task->setUser($this);
}
return $this;
}
public function removeTask(Task $task): self
{
if ($this->tasks->contains($task)) {
$this->tasks->removeElement($task);
// set the owning side to null (unless already changed)
if ($task->getUser() === $this) {
$task->setUser(null);
}
}
return $this;
}
/**
* @return Collection|Notification[]
*/
public function getNotifications(): Collection
{
return $this->notifications;
}
public function addNotification(Notification $notification): self
{
if (!$this->notifications->contains($notification)) {
$this->notifications[] = $notification;
$notification->setUser($this);
}
return $this;
}
public function removeNotification(Notification $notification): self
{
if ($this->notifications->contains($notification)) {
$this->notifications->removeElement($notification);
// set the owning side to null (unless already changed)
if ($notification->getUser() === $this) {
$notification->setUser(null);
}
}
return $this;
}
/**
* @return Collection|EmailTemplate[]
*/
public function getEmailTemplates(?bool $publishedOnly, ?string $version): Collection
{
$emailTemplates = $this->emailTemplates;
if ($publishedOnly === true) $emailTemplates = $emailTemplates->matching(EmailTemplateRepository::isPublishedCriteria());
if (isset($version)) $emailTemplates = $emailTemplates->matching(EmailTemplateRepository::editorVersionCriteria($version));
return $emailTemplates;
}
public function addEmailTemplate(EmailTemplate $emailTemplate): self
{
if (!$this->emailTemplates->contains($emailTemplate)) {
$this->emailTemplates[] = $emailTemplate;
$emailTemplate->setUser($this);
}
return $this;
}
public function removeEmailTemplate(EmailTemplate $emailTemplate): self
{
if ($this->emailTemplates->contains($emailTemplate)) {
$this->emailTemplates->removeElement($emailTemplate);
// set the owning side to null (unless already changed)
if ($emailTemplate->getUser() === $this) {
$emailTemplate->setUser(null);
}
}
return $this;
}
/**
* @return Collection|Upload[]
*/
public function getUploads(): Collection
{
return $this->uploads;
}
public function addUpload(Upload $upload): self
{
if (!$this->uploads->contains($upload)) {
$this->uploads[] = $upload;
$upload->setUser($this);
}
return $this;
}
public function removeUpload(Upload $upload): self
{
if ($this->uploads->contains($upload)) {
$this->uploads->removeElement($upload);
// set the owning side to null (unless already changed)
if ($upload->getUser() === $this) {
$upload->setUser(null);
}
}
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}
/**
* @return Collection|Domain[]
*/
public function getDomains(): Collection
{
return $this->domains;
}
public function addDomain(Domain $domain): self
{
if (!$this->domains->contains($domain)) {
$this->domains[] = $domain;
$domain->setUser($this);
}
return $this;
}
public function removeDomain(Domain $domain): self
{
if ($this->domains->removeElement($domain)) {
// set the owning side to null (unless already changed)
if ($domain->getUser() === $this) {
$domain->setUser(null);
}
}
return $this;
}
public function getCustomFields(): ?CustomFields
{
return $this->customFields;
}
public function setCustomFields(CustomFields $customFields): self
{
// set the owning side of the relation if necessary
if ($customFields->getUser() !== $this) {
$customFields->setUser($this);
}
$this->customFields = $customFields;
return $this;
}
/**
* @return Collection<int, Addon>
*/
public function getAddons(): Collection
{
return $this->addons;
}
/**
* @return $this
*/
public function clearAddons() : self
{
$this->addons->clear();
return $this;
}
public function addAddon(Addon $addon): self
{
if (!$this->addons->contains($addon)) {
$this->addons[] = $addon;
}
return $this;
}
public function removeAddon(Addon $addon): self
{
$this->addons->removeElement($addon);
return $this;
}
public function hasAddon($addon) : bool
{
if ($addon instanceof Addon) {
return $this->addons->contains($addon);
} else {
foreach ($this->addons as $userAddon) {
if ($userAddon->getName() === $addon) {
return true;
}
}
return false;
}
}
}