<?php
namespace Tionvel\WorkflowBundle\Entity;
use App\Entity\User;
use App\Util\DateUtils;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Exception;
/**
* Class WorkflowState
* @package Tionvel\WorkflowBundle\Entity
* @ORM\Entity()
* @ORM\Table(
* name="workflow_states",
* indexes={
* @ORM\Index(name="idx_ws_state_current", columns={"state", "current"})
* }
* )
*/
class WorkflowState
{
const START_STATE = '_process_start';
const START_TRANS = '_process_start';
/**
* @var int
* @ORM\Id @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @ORM\Column(type="string")
*/
private $state;
/**
* @var WorkflowProcess
* @ORM\ManyToOne(
* targetEntity="Tionvel\WorkflowBundle\Entity\WorkflowProcess",
* inversedBy="states"
* )
* @ORM\JoinColumn(
* onDelete="CASCADE"
* )
*/
private $process;
/**
* @var ArrayCollection|WorkflowAssignee[]
* @ORM\OneToMany(
* targetEntity="Tionvel\WorkflowBundle\Entity\WorkflowAssignee",
* mappedBy="state",
* fetch="EAGER",
* cascade={"persist", "remove"},
* orphanRemoval=true
* )
*/
private $assignees;
/**
* @var bool
* @ORM\Column(type="boolean")
*/
private $current = false;
/**
* @var DateTime
* @ORM\Column(type="datetime")
*/
private $startedAt;
/**
* @var DateTime
* @ORM\Column(type="datetime", nullable=true)
*/
private $completedAt;
/**
* @var DateTime
* @ORM\Column(type="datetime", nullable=true)
*/
private $deadline;
/**
* @var integer
* @ORM\Column(type="bigint")
*/
private $elapsedTime = 0;
/**
* @var WorkflowState
* @ORM\OneToOne(targetEntity="Tionvel\WorkflowBundle\Entity\WorkflowState", cascade={"persist"})
* @ORM\JoinColumn(name="prev_id", nullable=true, onDelete="SET NULL")
*/
private $prev;
/**
* @var WorkflowState
* @ORM\OneToOne(targetEntity="Tionvel\WorkflowBundle\Entity\WorkflowState", cascade={"persist"})
* @ORM\JoinColumn(name="next_id", nullable=true, onDelete="SET NULL")
*/
private $next;
/**
* @var string
* @ORM\Column(type="string", nullable=true)
*/
private $inTransition;
/**
* @var string
* @ORM\Column(type="string", nullable=true)
*/
private $outTransition;
/**
* @var User
* @ORM\ManyToOne(targetEntity="App\Entity\User")
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $startedBy;
/**
* @var User
* @ORM\ManyToOne(targetEntity="App\Entity\User")
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $completedBy;
/**
* @var array
* @ORM\Column(type="array")
*/
private $metadata;
/**
* WorkflowState constructor.
* @throws Exception
*/
public function __construct()
{
$this->assignees = new ArrayCollection;
$this->startedAt = new DateTime;
}
/**
* @param WorkflowProcess $process
* @param $state
* @param User $startedBy
* @param string $transition
* @return WorkflowState
* @throws Exception
*/
public static function start(
WorkflowProcess $process,
$startedBy,
$state = WorkflowState::START_STATE,
$transition = WorkflowState::START_TRANS
) {
$self = new self;
$self->setProcess($process);
$self->setState($state);
$self->setCurrent(true);
$self->setStartedBy($startedBy);
$self->setStartedAt(new DateTime);
$self->setInTransition($transition);
return $self;
}
/**
* @param WorkflowState $next
* @param User $completedBy
* @param $transition
* @throws Exception
*/
public function finish(WorkflowState $next, $completedBy, $transition)
{
$this->setCurrent(false);
$this->setNext($next);
$this->setCompletedAt(new DateTime);
$this->setCompletedBy($completedBy);
$this->setOutTransition($transition);
}
/**
* @return string
*/
public function __toString()
{
return $this->state;
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getState()
{
return $this->state;
}
/**
* @param string $state
*/
public function setState(string $state)
{
$this->state = $state;
}
/**
* @param $state
* @return bool
*/
public function isState($state)
{
return $this->state === $state;
}
/**
* @return WorkflowProcess
*/
public function getProcess()
{
return $this->process;
}
/**
* @param WorkflowProcess $process
*/
public function setProcess(WorkflowProcess $process)
{
$this->process = $process;
}
/**
* @return ArrayCollection
*/
public function getAssignees()
{
return $this->assignees;
}
/**
* @param ArrayCollection $assignees
*/
public function setAssignees(ArrayCollection $assignees)
{
$this->assignees = $assignees;
}
/**
* @param WorkflowAssignee $assignee
*/
public function addAssignee(WorkflowAssignee $assignee)
{
if (!$this->assignees->contains($assignee)) {
$this->assignees->add($assignee);
$assignee->setState($this);
}
}
/**
* @param WorkflowAssignee $assignee
*/
public function removeAssignee(WorkflowAssignee $assignee)
{
if ($this->assignees->contains($assignee)) {
$this->assignees->removeElement($assignee);
}
}
/**
* @param $key
*/
public function removeAssigneeByKey($key)
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('name', $key))
;
$this->assignees->matching($criteria)
->map(function (WorkflowAssignee $assignee) {
$this->removeAssignee($assignee);
})
;
}
/**
* @return bool
*/
public function isCurrent()
{
return $this->current;
}
/**
* @param bool $current
*/
public function setCurrent(bool $current)
{
$this->current = $current;
}
/**
* @return DateTime
*/
public function getStartedAt()
{
return $this->startedAt;
}
/**
* @param DateTime $startedAt
*/
public function setStartedAt(DateTime $startedAt)
{
$this->startedAt = $startedAt;
}
/**
* @return DateTime
*/
public function getCompletedAt()
{
return $this->completedAt;
}
/**
* @param DateTime|null $completedAt
*/
public function setCompletedAt(?DateTime $completedAt)
{
$this->completedAt = $completedAt;
if($completedAt) {
$this->elapsedTime = $completedAt->getTimestamp() - $this->startedAt->getTimestamp();
}
else {
$this->elapsedTime = 0;
}
}
/**
* @return DateTime
*/
public function getDeadline()
{
return $this->deadline;
}
/**
* @param DateTime $deadline
* @return WorkflowState
*/
public function setDeadline(DateTime $deadline)
{
$this->deadline = $deadline;
return $this;
}
/**
* @return int
*/
public function getElapsedTime()
{
return $this->elapsedTime;
}
/**
* @return string
* @throws Exception
*/
public function getElapsedTimeFormatted()
{
return DateUtils::dateIntervalFormat(($this->completedAt ?: new DateTime)->diff($this->startedAt));
}
/**
* @return WorkflowState
*/
public function getPrev()
{
return $this->prev;
}
/**
* @param WorkflowState $prev
*/
public function setPrev(WorkflowState $prev = null)
{
$this->prev = $prev;
}
/**
* @return WorkflowState
*/
public function getNext()
{
return $this->next;
}
/**
* @param WorkflowState $next
*/
public function setNext(WorkflowState $next = null)
{
$this->next = $next;
}
/**
* @return string
*/
public function getInTransition()
{
return $this->inTransition;
}
/**
* @param string $inTransition
*/
public function setInTransition(string $inTransition)
{
$this->inTransition = $inTransition;
}
/**
* @return string
*/
public function getOutTransition()
{
return $this->outTransition;
}
/**
* @param string $outTransition
*/
public function setOutTransition(string $outTransition)
{
$this->outTransition = $outTransition;
}
/**
* @return User
*/
public function getStartedBy()
{
return $this->startedBy;
}
/**
* @param User $startedBy
*/
public function setStartedBy($startedBy = null)
{
$this->startedBy = $startedBy;
}
/**
* @return User
*/
public function getCompletedBy()
{
return $this->completedBy;
}
/**
* @param User $completedBy
*/
public function setCompletedBy($completedBy = null)
{
$this->completedBy = $completedBy;
}
/**
* @return array
*/
public function getMetadata()
{
return $this->metadata;
}
/**
* @param array $metadata
*/
public function setMetadata(array $metadata)
{
$this->metadata = $metadata;
}
/**
* @param $key
* @param $value
* @return WorkflowState
*/
public function addMetadata($key, $value)
{
$this->metadata[$key] = $value;
return $this;
}
}