subscriberToFinal = new ArrayCollection(); $this->subscriberToStep = new ArrayCollection(); $this->comments = new ArrayCollection(); $this->steps = new ArrayCollection(); $initialStep = new EntityWorkflowStep(); $initialStep ->setCurrentStep('initial'); $this->addStep($initialStep); } public function addComment(EntityWorkflowComment $comment): self { if (!$this->comments->contains($comment)) { $this->comments[] = $comment; $comment->setEntityWorkflow($this); } return $this; } /** * @internal You should prepare a step and run a workflow transition instead of manually adding a step */ public function addStep(EntityWorkflowStep $step): self { if (!$this->steps->contains($step)) { $this->steps[] = $step; $step->setEntityWorkflow($this); if ($this->isFinalize()) { $step->setFinalizeAfter(true); } } return $this; } public function addSubscriberToFinal(User $user): self { if (!$this->subscriberToFinal->contains($user)) { $this->subscriberToFinal[] = $user; } return $this; } public function addSubscriberToStep(User $user): self { if (!$this->subscriberToStep->contains($user)) { $this->subscriberToStep[] = $user; } return $this; } public function getComments(): Collection { return $this->comments; } public function getCurrentStep(): ?EntityWorkflowStep { $step = $this->steps->last(); if (false !== $step) { return $step; } return null; } public function getCurrentStepCreatedAt(): ?DateTimeInterface { if (null !== $previous = $this->getPreviousStepIfAny()) { return $previous->getTransitionAt(); } return null; } public function getCurrentStepCreatedBy(): ?User { if (null !== $previous = $this->getPreviousStepIfAny()) { return $previous->getTransitionBy(); } return null; } public function getId(): ?int { return $this->id; } public function getRelatedEntityClass(): string { return $this->relatedEntityClass; } public function getRelatedEntityId(): int { return $this->relatedEntityId; } /** * Method used by MarkingStore. * * get a string representation of the step */ public function getStep(): string { return $this->getCurrentStep()->getCurrentStep(); } public function getStepAfter(EntityWorkflowStep $step): ?EntityWorkflowStep { $iterator = $this->steps->getIterator(); if ($iterator instanceof Iterator) { $iterator->rewind(); while ($iterator->valid()) { $curStep = $iterator->current(); if ($curStep === $step) { $iterator->next(); if ($iterator->valid()) { return $iterator->current(); } return null; } $iterator->next(); } return null; } throw new RuntimeException(); } /** * @return ArrayCollection|Collection */ public function getSteps() { return $this->steps; } public function getStepsChained(): array { $iterator = $this->steps->getIterator(); $previous = $next = $current = null; $steps = []; $iterator->rewind(); while ($iterator->valid()) { $previous = $current; $steps[] = $current = $iterator->current(); $current->setPrevious($previous); $iterator->next(); if ($iterator->valid()) { $next = $iterator->current(); } else { $next = null; } $current->setNext($next); } return $steps; } /** * @return ArrayCollection|Collection */ public function getSubscriberToFinal() { return $this->subscriberToFinal; } /** * @return ArrayCollection|Collection */ public function getSubscriberToStep() { return $this->subscriberToStep; } /** * get the step which is transitionning. Should be called only by event which will * concern the transition. */ public function getTransitionningStep(): ?EntityWorkflowStep { return $this->transitionningStep; } public function getWorkflowName(): string { return $this->workflowName; } public function isFinalize(): bool { $steps = $this->getStepsChained(); if (1 === count($steps)) { // the initial step cannot be finalized return false; } /** @var EntityWorkflowStep $last */ $last = end($steps); return $last->getPrevious()->isFinalizeAfter(); } public function isFreeze(): bool { $steps = $this->getStepsChained(); if (1 === count($steps)) { // the initial step cannot be finalized return false; } /** @var EntityWorkflowStep $last */ $last = end($steps); return $last->getPrevious()->isFreezeAfter(); } public function isUserSubscribedToFinal(User $user): bool { return $this->subscriberToFinal->contains($user); } public function isUserSubscribedToStep(User $user): bool { return $this->subscriberToStep->contains($user); } public function prepareStepBeforeTransition(EntityWorkflowStep $step): self { $this->transitionningStep = $step; return $this; } public function removeComment(EntityWorkflowComment $comment): self { if ($this->comments->removeElement($comment)) { $comment->setEntityWorkflow(null); } return $this; } public function removeStep(EntityWorkflowStep $step): self { if ($this->steps->removeElement($step)) { $step->setEntityWorkflow(null); } return $this; } public function removeSubscriberToFinal(User $user): self { $this->subscriberToFinal->removeElement($user); return $this; } public function removeSubscriberToStep(User $user): self { $this->subscriberToStep->removeElement($user); return $this; } public function setRelatedEntityClass(string $relatedEntityClass): EntityWorkflow { $this->relatedEntityClass = $relatedEntityClass; return $this; } public function setRelatedEntityId(int $relatedEntityId): EntityWorkflow { $this->relatedEntityId = $relatedEntityId; return $this; } /** * Method use by marking store. * * @return $this */ public function setStep(string $step): self { $newStep = new EntityWorkflowStep(); $newStep->setCurrentStep($step); // copy the freeze if ($this->getCurrentStep()->isFreezeAfter()) { $newStep->setFreezeAfter(true); } $this->addStep($newStep); return $this; } public function setWorkflowName(string $workflowName): EntityWorkflow { $this->workflowName = $workflowName; return $this; } private function getPreviousStepIfAny(): ?EntityWorkflowStep { if (1 === count($this->steps)) { return null; } return $this->steps->get($this->steps->count() - 2); } }