File: /home/timetracker.panomity.com/tm.old/Entity/Task.php
<?php
/*
* This file is part of the TaskManagementBundle for Kimai 2.
* All rights reserved by Kevin Papst (www.kevinpapst.de).
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace KimaiPlugin\TaskManagementBundle\Entity;
use App\Entity\Activity;
use App\Entity\Project;
use App\Entity\Tag;
use App\Entity\Team;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Export\Annotation as Exporter;
use DateTime;
use DateTimeZone;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
use Swagger\Annotations as SWG;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table(name="kimai2_tasks",
* indexes={
* @ORM\Index(columns={"user_id", "status", "start_time", "end_time"}),
* @ORM\Index(columns={"team_id", "status", "start_time", "end_time"})
* }
* )
* @ORM\Entity(repositoryClass="KimaiPlugin\TaskManagementBundle\Repository\TaskRepository")
* @Exporter\Order({"id", "title", "status", "end", "todo", "estimation", "user", "team", "customer", "project", "activity", "description"})
* @Exporter\Expose("customer", label="label.customer", exp="object.getProject() === null ? null : object.getProject().getCustomer().getName()")
* @Exporter\Expose("project", label="label.project", exp="object.getProject() === null ? null : object.getProject().getName()")
* @Exporter\Expose("activity", label="label.activity", exp="object.getActivity() === null ? null : object.getActivity().getName()")
* @Exporter\Expose("user", label="label.user", exp="object.getUser() === null ? null : object.getUser().getDisplayName()")
* @Exporter\Expose("team", label="label.team", exp="object.getTeam() === null ? null : object.getTeam().getName()")
*
* @Serializer\ExclusionPolicy("all")
* @Serializer\VirtualProperty(
* "TagsAsArray",
* exp="object.getTagsAsArray()",
* options={
* @Serializer\SerializedName("tags"),
* @Serializer\Type(name="array<string>"),
* @Serializer\Groups({"Default"})
* }
* )
*/
class Task
{
public const STATUS_PENDING = 'pending';
public const STATUS_IN_PROGRESS = 'progress';
public const STATUS_DONE = 'closed';
/**
* @var int|null
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
*
* @Exporter\Expose(label="label.id", type="integer")
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
*
* @Exporter\Expose(label="label.title")
*
* @ORM\Column(name="title", type="string", length=100, nullable=false)
* @Assert\NotBlank()
* @Assert\Length(min=2, max=100)
*/
private $title;
/**
* @var string
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
*
* @Exporter\Expose(label="task.status")
*
* @ORM\Column(name="status", type="string", length=20, nullable=false)
* @Assert\NotBlank()
* @Assert\Length(max=20)
*/
private $status = self::STATUS_PENDING;
/**
* @var string|null
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
*
* @Exporter\Expose(label="label.task_todo")
*
* @ORM\Column(name="todo", type="text", nullable=true)
*/
private $todo;
/**
* @var string|null
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
*
* @Exporter\Expose(label="label.description")
*
* @ORM\Column(name="description", type="text", nullable=true)
*/
private $description;
/**
* @var Project
*
* @Serializer\Expose()
* @Serializer\Groups({"Subresource", "Expanded"})
* @SWG\Property(ref="#/definitions/ProjectExpanded")
*
* @ORM\ManyToOne(targetEntity="App\Entity\Project")
* @ORM\JoinColumn(onDelete="CASCADE", nullable=false)
* @Assert\NotNull()
*/
private $project;
/**
* @var Activity
*
* @Serializer\Expose()
* @Serializer\Groups({"Subresource", "Expanded"})
* @SWG\Property(ref="#/definitions/ActivityExpanded")
*
* @ORM\ManyToOne(targetEntity="App\Entity\Activity")
* @ORM\JoinColumn(onDelete="CASCADE", nullable=false)
* @Assert\NotNull()
*/
private $activity;
/**
* Assigned user that is working on that task.
*
* @var User
*
* @Serializer\Expose()
* @Serializer\Groups({"Subresource", "Expanded"})
* @SWG\Property(ref="#/definitions/User")
*
* @ORM\ManyToOne(targetEntity="App\Entity\User")
* @ORM\JoinColumn(onDelete="CASCADE", nullable=true)
*
* @SWG\Property(ref="#/definitions/User")
*/
private $user;
/**
* If set, only this team can see the task.
*
* @var Team
*
* @Serializer\Expose()
* @Serializer\Groups({"Subresource", "Expanded"})
* @SWG\Property(ref="#/definitions/Team")
*
* @ORM\ManyToOne(targetEntity="App\Entity\Team")
* @ORM\JoinColumn(onDelete="CASCADE", nullable=true)
*/
private $team;
/**
* @var DateTime
*
* @ORM\Column(name="start_time", type="datetime", nullable=true)
*/
private $begin;
/**
* @var DateTime
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
* @Serializer\Type(name="DateTime")
* @Serializer\Accessor(getter="getEnd")
*
* Attention: Accessor MUST be used, otherwise date will be serialized in UTC.
*
* @Exporter\Expose(label="label.end", type="datetime")
*
* @ORM\Column(name="end_time", type="datetime", nullable=true)
*/
private $end;
/**
* @var string
*
* @ORM\Column(name="timezone", type="string", length=64, nullable=true)
*/
private $timezone;
/**
* @var bool
*/
private $localized = false;
/**
* @var Collection<Tag>
*
* @ORM\ManyToMany(targetEntity="App\Entity\Tag", cascade={"persist"})
* @ORM\JoinTable(
* name="kimai2_task_tags",
* joinColumns={
* @ORM\JoinColumn(name="task_id", referencedColumnName="id", onDelete="CASCADE")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="tag_id", referencedColumnName="id", onDelete="CASCADE")
* }
* )
*/
private $tags;
/**
* @var Collection<Timesheet>
*
* @ORM\ManyToMany(targetEntity="App\Entity\Timesheet", cascade={"persist"})
* @ORM\JoinTable(
* name="kimai2_task_timesheets",
* joinColumns={
* @ORM\JoinColumn(name="task_id", referencedColumnName="id", onDelete="CASCADE")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="timesheet_id", referencedColumnName="id", onDelete="CASCADE", unique=true)
* }
* )
* @ORM\OrderBy({"begin" = "DESC","id" = "DESC"})
*/
private $timesheets;
/**
* Estimated duration for the task in seconds or null if no estimation was added
*
* @var int|null
*
* @Serializer\Expose()
* @Serializer\Groups({"Default"})
*
* @Exporter\Expose(label="label.estimation", type="integer")
*
* @ORM\Column(name="estimation", type="integer", nullable=true)
* @Assert\GreaterThanOrEqual(0)
*/
private $estimation;
public function __construct()
{
$this->tags = new ArrayCollection();
$this->timesheets = new ArrayCollection();
}
/**
* Get entry id, returns null for new entities which were not persisted.
*
* @return int|null
*/
public function getId(): ?int
{
return $this->id;
}
/**
* Make sure begin and end date have the correct timezone.
* This will be called once for each item after being loaded from the database.
*/
protected function localizeDates(): void
{
if ($this->localized) {
return;
}
if (null !== $this->begin) {
$this->begin->setTimeZone(new DateTimeZone($this->timezone));
}
if (null !== $this->end) {
$this->end->setTimeZone(new DateTimeZone($this->timezone));
}
$this->localized = true;
}
public function getBegin(): ?DateTime
{
$this->localizeDates();
return $this->begin;
}
public function setBegin(?DateTime $begin): Task
{
$this->begin = $begin;
if (null !== $begin) {
$this->timezone = $begin->getTimezone()->getName();
}
return $this;
}
public function getEnd(): ?DateTime
{
$this->localizeDates();
return $this->end;
}
public function setEnd(?DateTime $end): Task
{
$this->end = $end;
if (null !== $end) {
$this->timezone = $end->getTimezone()->getName();
}
return $this;
}
public function setUser(?User $user): Task
{
$this->user = $user;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setActivity(Activity $activity): Task
{
$this->activity = $activity;
return $this;
}
public function getActivity(): ?Activity
{
return $this->activity;
}
public function setProject(Project $project): Task
{
$this->project = $project;
return $this;
}
public function getProject(): ?Project
{
return $this->project;
}
public function setDescription(?string $description): Task
{
$this->description = $description;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function getTimezone(): string
{
return $this->timezone;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): Task
{
$this->title = $title;
return $this;
}
public function getTeam(): ?Team
{
return $this->team;
}
public function setTeam(?Team $team): Task
{
$this->team = $team;
return $this;
}
public function getStatus(): string
{
return $this->status;
}
public function isPending(): bool
{
return $this->status === self::STATUS_PENDING;
}
public function isInProgress(): bool
{
return $this->status === self::STATUS_IN_PROGRESS;
}
public function setStatus(string $status): Task
{
if (!\in_array($status, [self::STATUS_PENDING, self::STATUS_IN_PROGRESS, self::STATUS_DONE])) {
throw new \InvalidArgumentException(sprintf('Unknown task status: %s', $status));
}
$this->status = $status;
return $this;
}
public function getActiveRecord(?User $user): ?Timesheet
{
/** @var Timesheet $timesheet */
foreach ($this->timesheets as $timesheet) {
if (null === $timesheet->getEnd() && ($user === null || $timesheet->getUser()->getId() === $user->getId())) {
return $timesheet;
}
}
return null;
}
/**
* @Serializer\VirtualProperty
* @Serializer\Expose
* @Serializer\SerializedName("activeTimesheets"),
* @SWG\Property(type="array", @SWG\Items(ref="#/definitions/TimesheetEntityExpanded")),
* @Serializer\Groups({"Subresource", "Expanded"})
*
* @return array
*/
public function getActiveRecords(): array
{
$all = [];
/** @var Timesheet $timesheet */
foreach ($this->timesheets as $timesheet) {
if (null === $timesheet->getEnd()) {
$all[] = $timesheet;
}
}
return $all;
}
public function hasActiveRecord(User $user): bool
{
/** @var Timesheet $timesheet */
foreach ($this->timesheets as $timesheet) {
if (null === $timesheet->getEnd() && $timesheet->getUser()->getId() === $user->getId()) {
return true;
}
}
return false;
}
public function addTimesheet(Timesheet $timesheet): Task
{
$this->timesheets->add($timesheet);
return $this;
}
/**
* @return Collection<Timesheet>
*/
public function getTimesheets(): Collection
{
return $this->timesheets;
}
public function getDuration(): ?int
{
if ($this->timesheets->count() === 0) {
return null;
}
$fullDuration = 0;
/** @var Timesheet $timesheet */
foreach ($this->timesheets as $timesheet) {
$duration = $timesheet->getDuration();
if (null === $timesheet->getEnd()) {
$now = new DateTime('now', $timesheet->getBegin()->getTimezone());
$duration = $now->getTimestamp() - $timesheet->getBegin()->getTimestamp();
}
$fullDuration += $duration;
}
return $fullDuration;
}
public function isOverdue(): bool
{
if ($this->end !== null) {
$now = new DateTime('now', $this->end->getTimezone());
if ($now->getTimestamp() > $this->end->getTimestamp()) {
return true;
}
}
if ($this->estimation !== null) {
$duration = $this->getDuration();
if ($duration === null) {
return false;
}
if ($duration > $this->estimation) {
return true;
}
}
return false;
}
public function isClosed(): bool
{
return $this->status === self::STATUS_DONE;
}
public function addTag(Tag $tag): Task
{
if ($this->tags->contains($tag)) {
return $this;
}
$this->tags->add($tag);
return $this;
}
public function removeTag(Tag $tag): void
{
if (!$this->tags->contains($tag)) {
return;
}
$this->tags->removeElement($tag);
}
/**
* @return Collection<Tag>
*/
public function getTags(): Collection
{
return $this->tags;
}
/**
* @return string[]
*/
public function getTagsAsArray(): array
{
return array_map(
function (Tag $element) {
return $element->getName();
},
$this->getTags()->toArray()
);
}
public function getEstimation(): ?int
{
return $this->estimation;
}
public function setEstimation(?int $estimation): Task
{
$this->estimation = $estimation;
return $this;
}
public function getTodo(): ?string
{
return $this->todo;
}
public function setTodo(?string $todo): void
{
$this->todo = $todo;
}
public function __clone()
{
if ($this->id) {
$this->id = null;
}
$this->timesheets = new ArrayCollection();
$previousTags = $this->tags;
$this->tags = new ArrayCollection();
foreach ($previousTags as $tag) {
$this->addTag($tag);
}
}
}