mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-28 04:56:13 +00:00
705 lines
19 KiB
PHP
705 lines
19 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\CalendarBundle\Entity;
|
|
|
|
use Chill\ActivityBundle\Entity\Activity;
|
|
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
|
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
|
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
|
use Chill\MainBundle\Entity\Embeddable\PrivateCommentEmbeddable;
|
|
use Chill\MainBundle\Entity\HasCentersInterface;
|
|
use Chill\MainBundle\Entity\Location;
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
use Doctrine\Common\Collections\Collection;
|
|
use Doctrine\Common\Collections\Criteria;
|
|
use Doctrine\Common\Collections\ReadableCollection;
|
|
use Doctrine\Common\Collections\Selectable;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
|
use Symfony\Component\Validator\Constraints\Range;
|
|
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
|
|
|
#[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['chill_calendar_calendar' => Calendar::class])]
|
|
#[ORM\Entity]
|
|
#[ORM\Table(name: 'chill_calendar.calendar')]
|
|
#[ORM\UniqueConstraint(name: 'idx_calendar_remote', columns: ['remoteId'], options: ['where' => "remoteId <> ''"])]
|
|
class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCentersInterface
|
|
{
|
|
use RemoteCalendarTrait;
|
|
|
|
use TrackCreationTrait;
|
|
|
|
use TrackUpdateTrait;
|
|
|
|
final public const SMS_CANCEL_PENDING = 'sms_cancel_pending';
|
|
|
|
final public const SMS_PENDING = 'sms_pending';
|
|
|
|
final public const SMS_SENT = 'sms_sent';
|
|
|
|
final public const STATUS_CANCELED = 'canceled';
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
final public const STATUS_MOVED = 'moved';
|
|
|
|
final public const STATUS_VALID = 'valid';
|
|
|
|
/**
|
|
* a list of invite which have been added during this session.
|
|
*
|
|
* @var array|Invite[]
|
|
*/
|
|
public array $newInvites = [];
|
|
|
|
/**
|
|
* a list of invite which have been removed during this session.
|
|
*
|
|
* @var array|Invite[]
|
|
*/
|
|
public array $oldInvites = [];
|
|
|
|
public ?CalendarRange $previousCalendarRange = null;
|
|
|
|
public ?User $previousMainUser = null;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read'])]
|
|
#[ORM\ManyToOne(targetEntity: AccompanyingPeriod::class, inversedBy: 'calendars')]
|
|
private ?AccompanyingPeriod $accompanyingPeriod = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: Activity::class)]
|
|
private ?Activity $activity = null;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read'])]
|
|
#[ORM\OneToOne(targetEntity: CalendarRange::class, inversedBy: 'calendar')]
|
|
private ?CalendarRange $calendarRange = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: CancelReason::class)]
|
|
private ?CancelReason $cancelReason = null;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read', 'docgen:read'])]
|
|
#[ORM\Embedded(class: CommentEmbeddable::class, columnPrefix: 'comment_')]
|
|
private CommentEmbeddable $comment;
|
|
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: false, options: ['default' => 0])]
|
|
private int $dateTimeVersion = 0;
|
|
|
|
/**
|
|
* @var Collection<CalendarDoc>
|
|
*/
|
|
#[ORM\OneToMany(mappedBy: 'calendar', targetEntity: CalendarDoc::class, orphanRemoval: true)]
|
|
private Collection $documents;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
|
#[Assert\NotNull(message: 'calendar.An end date is required')]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: false)]
|
|
private ?\DateTimeImmutable $endDate = null;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
|
#[ORM\Id]
|
|
#[ORM\GeneratedValue]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
|
private ?int $id = null;
|
|
|
|
/**
|
|
* @var Collection&Selectable<int, Invite>
|
|
*/
|
|
#[Serializer\Groups(['read', 'docgen:read'])]
|
|
#[ORM\OneToMany(mappedBy: 'calendar', targetEntity: Invite::class, cascade: ['persist', 'remove', 'merge', 'detach'], orphanRemoval: true)]
|
|
#[ORM\JoinTable(name: 'chill_calendar.calendar_to_invites')]
|
|
private Collection&Selectable $invites;
|
|
|
|
#[Serializer\Groups(['read', 'docgen:read'])]
|
|
#[Assert\NotNull(message: 'calendar.A location is required')]
|
|
#[ORM\ManyToOne(targetEntity: Location::class)]
|
|
private ?Location $location = null;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
|
#[Assert\NotNull(message: 'calendar.A main user is mandatory')]
|
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
|
#[Serializer\Context(normalizationContext: ['read'], groups: ['calendar:light'])]
|
|
private ?User $mainUser = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: Person::class)]
|
|
#[ORM\JoinColumn(nullable: true)]
|
|
private ?Person $person = null;
|
|
|
|
/**
|
|
* @var Collection<Person>
|
|
*/
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
|
#[Assert\Count(min: 1, minMessage: 'calendar.At least {{ limit }} person is required.')]
|
|
#[ORM\ManyToMany(targetEntity: Person::class, inversedBy: 'calendars')]
|
|
#[ORM\JoinTable(name: 'chill_calendar.calendar_to_persons')]
|
|
#[Serializer\Context(normalizationContext: ['read'], groups: ['calendar:light'])]
|
|
private Collection $persons;
|
|
|
|
#[Serializer\Groups(['calendar:read'])]
|
|
#[ORM\Embedded(class: PrivateCommentEmbeddable::class, columnPrefix: 'privateComment_')]
|
|
private PrivateCommentEmbeddable $privateComment;
|
|
|
|
/**
|
|
* @var Collection<ThirdParty>
|
|
*/
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
|
#[ORM\ManyToMany(targetEntity: ThirdParty::class)]
|
|
#[ORM\JoinTable(name: 'chill_calendar.calendar_to_thirdparties')]
|
|
#[Serializer\Context(normalizationContext: ['read'], groups: ['calendar:light'])]
|
|
private Collection $professionals;
|
|
|
|
#[Serializer\Groups(['docgen:read'])]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, nullable: true)]
|
|
private ?bool $sendSMS = false;
|
|
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => Calendar::SMS_PENDING])]
|
|
private string $smsStatus = self::SMS_PENDING;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
|
#[Assert\NotNull(message: 'calendar.A start date is required')]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: false)]
|
|
#[Serializer\Context(normalizationContext: ['read'], groups: ['calendar:light'])]
|
|
private ?\DateTimeImmutable $startDate = null;
|
|
|
|
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light'])]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255, nullable: false, options: ['default' => 'valid'])]
|
|
#[Serializer\Context(normalizationContext: ['read'], groups: ['calendar:light'])]
|
|
private string $status = self::STATUS_VALID;
|
|
|
|
#[Serializer\Groups(['docgen:read'])]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, nullable: true)]
|
|
private ?bool $urgent = false;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->comment = new CommentEmbeddable();
|
|
$this->documents = new ArrayCollection();
|
|
$this->privateComment = new PrivateCommentEmbeddable();
|
|
$this->persons = new ArrayCollection();
|
|
$this->professionals = new ArrayCollection();
|
|
$this->invites = new ArrayCollection();
|
|
}
|
|
|
|
/**
|
|
* @internal use @{CalendarDoc::__construct} instead
|
|
*/
|
|
public function addDocument(CalendarDoc $calendarDoc): self
|
|
{
|
|
if ($this->documents->contains($calendarDoc)) {
|
|
$this->documents[] = $calendarDoc;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @internal Use {@link (Calendar::addUser)} instead
|
|
*/
|
|
public function addInvite(Invite $invite): self
|
|
{
|
|
if ($invite->getCalendar() instanceof Calendar && $invite->getCalendar() !== $this) {
|
|
throw new \LogicException('Not allowed to move an invitation to another Calendar');
|
|
}
|
|
|
|
$this->invites[] = $invite;
|
|
$this->newInvites[] = $invite;
|
|
|
|
$invite->setCalendar($this);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addPerson(Person $person): self
|
|
{
|
|
$this->persons[] = $person;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addProfessional(ThirdParty $professional): self
|
|
{
|
|
$this->professionals[] = $professional;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addUser(User $user): self
|
|
{
|
|
if (!$this->getUsers()->contains($user) && $this->getMainUser() !== $user) {
|
|
$this->addInvite((new Invite())->setUser($user));
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getAccompanyingPeriod(): ?AccompanyingPeriod
|
|
{
|
|
return $this->accompanyingPeriod;
|
|
}
|
|
|
|
public function getActivity(): ?Activity
|
|
{
|
|
return $this->activity;
|
|
}
|
|
|
|
public function getCalendarRange(): ?CalendarRange
|
|
{
|
|
return $this->calendarRange;
|
|
}
|
|
|
|
public function getCancelReason(): ?CancelReason
|
|
{
|
|
return $this->cancelReason;
|
|
}
|
|
|
|
public function getCenters(): ?iterable
|
|
{
|
|
return match ($this->getContext()) {
|
|
'person' => [$this->getPerson()->getCenter()],
|
|
'accompanying_period' => $this->getAccompanyingPeriod()->getCenters(),
|
|
default => throw new \LogicException('context not supported: '.$this->getContext()),
|
|
};
|
|
}
|
|
|
|
public function getComment(): CommentEmbeddable
|
|
{
|
|
return $this->comment;
|
|
}
|
|
|
|
/**
|
|
* @return 'person'|'accompanying_period'|null
|
|
*/
|
|
public function getContext(): ?string
|
|
{
|
|
if (null !== $this->getAccompanyingPeriod()) {
|
|
return 'accompanying_period';
|
|
}
|
|
|
|
if (null !== $this->getPerson()) {
|
|
return 'person';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Each time the date and time is update, this version is incremented.
|
|
*/
|
|
public function getDateTimeVersion(): int
|
|
{
|
|
return $this->dateTimeVersion;
|
|
}
|
|
|
|
public function getDocuments(): Collection
|
|
{
|
|
return $this->documents;
|
|
}
|
|
|
|
#[Serializer\Groups(['docgen:read'])]
|
|
public function getDuration(): ?\DateInterval
|
|
{
|
|
if (null === $this->getStartDate() || null === $this->getEndDate()) {
|
|
return null;
|
|
}
|
|
|
|
return $this->getStartDate()->diff($this->getEndDate());
|
|
}
|
|
|
|
public function getEndDate(): ?\DateTimeImmutable
|
|
{
|
|
return $this->endDate;
|
|
}
|
|
|
|
public function getId(): ?int
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function getInviteForUser(User $user): ?Invite
|
|
{
|
|
$criteria = Criteria::create();
|
|
$criteria->where(Criteria::expr()->eq('user', $user));
|
|
|
|
$matchings = $this->invites
|
|
->matching($criteria);
|
|
|
|
if (1 === $matchings->count()) {
|
|
return $matchings->first();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return Collection|Invite[]
|
|
*/
|
|
public function getInvites(): Collection
|
|
{
|
|
return $this->invites;
|
|
}
|
|
|
|
public function getLocation(): ?Location
|
|
{
|
|
return $this->location;
|
|
}
|
|
|
|
public function getMainUser(): ?User
|
|
{
|
|
return $this->mainUser;
|
|
}
|
|
|
|
public function getPerson(): ?Person
|
|
{
|
|
return $this->person;
|
|
}
|
|
|
|
/**
|
|
* @return Collection|Person[]
|
|
*/
|
|
public function getPersons(): Collection
|
|
{
|
|
return $this->persons;
|
|
}
|
|
|
|
public function getPersonsAssociated(): array
|
|
{
|
|
if (null !== $this->accompanyingPeriod) {
|
|
$personsAssociated = [];
|
|
|
|
foreach ($this->accompanyingPeriod->getParticipations() as $participation) {
|
|
if ($this->persons->contains($participation->getPerson())) {
|
|
$personsAssociated[] = $participation->getPerson();
|
|
}
|
|
}
|
|
|
|
return $personsAssociated;
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
public function getPersonsNotAssociated(): array
|
|
{
|
|
if (null !== $this->accompanyingPeriod) {
|
|
$personsNotAssociated = [];
|
|
|
|
foreach ($this->persons as $person) {
|
|
if (!\in_array($person, $this->getPersonsAssociated(), true)) {
|
|
$personsNotAssociated[] = $person;
|
|
}
|
|
}
|
|
|
|
return $personsNotAssociated;
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
public function getPrivateComment(): PrivateCommentEmbeddable
|
|
{
|
|
return $this->privateComment;
|
|
}
|
|
|
|
/**
|
|
* @return Collection|ThirdParty[]
|
|
*/
|
|
public function getProfessionals(): Collection
|
|
{
|
|
return $this->professionals;
|
|
}
|
|
|
|
public function getSendSMS(): ?bool
|
|
{
|
|
return $this->sendSMS;
|
|
}
|
|
|
|
public function getSmsStatus(): string
|
|
{
|
|
return $this->smsStatus;
|
|
}
|
|
|
|
public function getStartDate(): ?\DateTimeImmutable
|
|
{
|
|
return $this->startDate;
|
|
}
|
|
|
|
/**
|
|
* get the date of the calendar.
|
|
*
|
|
* Useful for showing the date of the calendar event, required by twig in some places.
|
|
*/
|
|
public function getDate(): ?\DateTimeImmutable
|
|
{
|
|
return $this->getStartDate();
|
|
}
|
|
|
|
public function getStatus(): ?string
|
|
{
|
|
return $this->status;
|
|
}
|
|
|
|
public function getThirdParties(): Collection
|
|
{
|
|
return $this->getProfessionals();
|
|
}
|
|
|
|
public function getUrgent(): ?bool
|
|
{
|
|
return $this->urgent;
|
|
}
|
|
|
|
/**
|
|
* @return ReadableCollection<(int|string), User>
|
|
*/
|
|
#[Serializer\Groups(['calendar:read', 'read'])]
|
|
public function getUsers(): ReadableCollection
|
|
{
|
|
return $this->getInvites()->map(static fn (Invite $i) => $i->getUser());
|
|
}
|
|
|
|
public function hasCalendarRange(): bool
|
|
{
|
|
return null !== $this->calendarRange;
|
|
}
|
|
|
|
public function hasLocation(): bool
|
|
{
|
|
return null !== $this->getLocation();
|
|
}
|
|
|
|
/**
|
|
* return true if the user is invited.
|
|
*/
|
|
public function isInvited(User $user): bool
|
|
{
|
|
if ($this->getMainUser() === $user) {
|
|
return false;
|
|
}
|
|
|
|
return $this->getUsers()->contains($user);
|
|
}
|
|
|
|
public static function loadValidatorMetadata(ClassMetadata $metadata): void
|
|
{
|
|
$metadata->addPropertyConstraint('startDate', new NotBlank());
|
|
$metadata->addPropertyConstraint('startDate', new Range([
|
|
'min' => '2 years ago',
|
|
'max' => '+ 2 years',
|
|
]));
|
|
$metadata->addPropertyConstraint('endDate', new NotBlank());
|
|
$metadata->addPropertyConstraint('endDate', new Range([
|
|
'min' => '2 years ago',
|
|
'max' => '+ 2 years',
|
|
]));
|
|
}
|
|
|
|
/**
|
|
* @internal use @{CalendarDoc::setCalendar} with null instead
|
|
*/
|
|
public function removeDocument(CalendarDoc $calendarDoc): self
|
|
{
|
|
if ($calendarDoc->getCalendar() !== $this) {
|
|
throw new \LogicException('cannot remove document of another calendar');
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @internal Use {@link (Calendar::removeUser)} instead
|
|
*/
|
|
public function removeInvite(Invite $invite): self
|
|
{
|
|
if ($this->invites->removeElement($invite)) {
|
|
$invite->setCalendar(null);
|
|
$this->oldInvites[] = $invite;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removePerson(Person $person): self
|
|
{
|
|
$this->persons->removeElement($person);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeProfessional(ThirdParty $professional): self
|
|
{
|
|
$this->professionals->removeElement($professional);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeUser(User $user): self
|
|
{
|
|
if (!$this->getUsers()->contains($user)) {
|
|
return $this;
|
|
}
|
|
|
|
$invite = $this->invites
|
|
->filter(static fn (Invite $invite) => $invite->getUser() === $user)
|
|
->first();
|
|
$this->removeInvite($invite);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
|
|
{
|
|
$this->accompanyingPeriod = $accompanyingPeriod;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setActivity(?Activity $activity): self
|
|
{
|
|
$this->activity = $activity;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCalendarRange(?CalendarRange $calendarRange): self
|
|
{
|
|
if ($this->calendarRange !== $calendarRange) {
|
|
$this->previousCalendarRange = $this->calendarRange;
|
|
|
|
if (null !== $this->previousCalendarRange) {
|
|
$this->previousCalendarRange->setCalendar(null);
|
|
}
|
|
}
|
|
|
|
$this->calendarRange = $calendarRange;
|
|
|
|
if ($this->calendarRange instanceof CalendarRange) {
|
|
$this->calendarRange->setCalendar($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCancelReason(?CancelReason $cancelReason): self
|
|
{
|
|
$this->cancelReason = $cancelReason;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setComment(CommentEmbeddable $comment): self
|
|
{
|
|
$this->comment = $comment;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setEndDate(\DateTimeImmutable $endDate): self
|
|
{
|
|
if (null === $this->endDate || $this->endDate->getTimestamp() !== $endDate->getTimestamp()) {
|
|
$this->increaseaDatetimeVersion();
|
|
}
|
|
|
|
$this->endDate = $endDate;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setLocation(?Location $location): Calendar
|
|
{
|
|
$this->location = $location;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setMainUser(?User $mainUser): self
|
|
{
|
|
if ($this->mainUser !== $mainUser) {
|
|
$this->previousMainUser = $this->mainUser;
|
|
}
|
|
|
|
$this->mainUser = $mainUser;
|
|
$this->removeUser($mainUser);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setPerson(?Person $person): Calendar
|
|
{
|
|
$this->person = $person;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setPrivateComment(PrivateCommentEmbeddable $privateComment): self
|
|
{
|
|
$this->privateComment = $privateComment;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setSendSMS(?bool $sendSMS): self
|
|
{
|
|
$this->sendSMS = $sendSMS;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setSmsStatus(string $smsStatus): self
|
|
{
|
|
$this->smsStatus = $smsStatus;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setStartDate(\DateTimeImmutable $startDate): self
|
|
{
|
|
if (null === $this->startDate || $this->startDate->getTimestamp() !== $startDate->getTimestamp()) {
|
|
$this->increaseaDatetimeVersion();
|
|
}
|
|
|
|
$this->startDate = $startDate;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setStatus(string $status): self
|
|
{
|
|
$this->status = $status;
|
|
|
|
if (self::STATUS_CANCELED === $status && self::SMS_SENT === $this->getSmsStatus()) {
|
|
$this->setSmsStatus(self::SMS_CANCEL_PENDING);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setUrgent(bool $urgent): self
|
|
{
|
|
$this->urgent = $urgent;
|
|
|
|
return $this;
|
|
}
|
|
|
|
private function increaseaDatetimeVersion(): void
|
|
{
|
|
++$this->dateTimeVersion;
|
|
}
|
|
}
|