<?php
namespace MedBrief\MSR\Entity;
use DH\Auditor\Provider\Doctrine\Auditing\Annotation as Audit;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use MedBrief\MSR\Repository\SeriesRepository;
/**
* Series
*
* @ORM\Table(name="Series", indexes={@ORM\Index(name="orthanc_series_id_index", columns={"orthanc_series_id"})})
*
* @ORM\Entity(repositoryClass=SeriesRepository::class)
*
* @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
*
* @Audit\Auditable
*
* @Audit\Security(view={"ROLE_ALLOWED_TO_AUDIT"})
*/
class Series
{
public const ORTHANC_SYNC_STATUS_PENDING = 1;
public const ORTHANC_SYNC_STATUS_FAILED = 2;
public const ORTHANC_SYNC_STATUS_SUCCESS = 3;
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\Id
*
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \DateTime|null
*
* @ORM\Column(name="deletedAt", type="datetime", nullable=true)
*/
private $deletedAt;
/**
* @var string|null
*
* @ORM\Column(name="dicom_series_name", type="string", nullable=true)
*/
private $dicom_series_name;
/**
* @var string|null
*
* @ORM\Column(name="dicom_series_description", type="string", nullable=true)
*/
private $dicom_series_description;
/**
* @var string|null
*
* @ORM\Column(name="dicom_series_number", type="string", nullable=true)
*/
private $dicom_series_number;
/**
* @var string|null
*
* @ORM\Column(name="dicom_series_id", type="string", nullable=true)
*/
private $dicom_series_id;
/**
* @var int|null
*
* @ORM\Column(name="orthanc_sync_status", type="integer", nullable=true)
*/
private $orthanc_sync_status;
/**
* @var string|null
*
* @ORM\Column(name="orthanc_series_id", type="string", nullable=true)
*/
private $orthanc_series_id;
/**
* @var string|null
*
* @ORM\Column(name="orthanc_parent_study_id", type="string", length=255, nullable=true)
*/
private $orthanc_parent_study_id;
/**
* @ORM\Column(type="string", nullable=true)
*/
private ?string $name;
/**
* @ORM\Column(type="string", nullable=true)
*/
private ?string $description;
/**
* @var \DateTime
*
* @ORM\Column(name="created", type="datetime")
*
* @Gedmo\Timestampable(on="create")
*/
private $created;
/**
* @var \DateTime
*
* @ORM\Column(name="updated", type="datetime")
*
* @Gedmo\Timestampable(on="update")
*/
private $updated;
/**
* @var Collection
*
* @ORM\OneToMany(targetEntity="MedBrief\MSR\Entity\OrthancTransaction", mappedBy="series", cascade={"all"})
*/
private $orthancTransactions;
/**
* @var Study
*
* @ORM\ManyToOne(targetEntity="MedBrief\MSR\Entity\Study", inversedBy="series")
*
* @ORM\JoinColumns({
*
* @ORM\JoinColumn(name="study_id", referencedColumnName="id", nullable=true)
* })
*/
private $study;
/**
* @var Project
*
* @ORM\ManyToOne(targetEntity="MedBrief\MSR\Entity\Project", inversedBy="series")
*
* @ORM\JoinColumns({
*
* @ORM\JoinColumn(name="project_id", referencedColumnName="id", nullable=false)
* })
*/
private $project;
/**
* @ORM\OneToMany(targetEntity=Instance::class, mappedBy="parentSeries", orphanRemoval=true)
*/
private $instances;
/**
* Constructor
*/
public function __construct()
{
$this->orthancTransactions = new ArrayCollection();
$this->instances = new ArrayCollection();
}
public function __clone()
{
if ($this->id) {
$this->id = null;
$this->instances = new ArrayCollection();
$this->orthancTransactions = new ArrayCollection();
}
}
public function __toString()
{
return $this->getName();
}
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set dicom_series_name
*
* @param string $dicomSeriesName
*
* @return Series
*/
public function setDicomSeriesName($dicomSeriesName)
{
$this->dicom_series_name = $dicomSeriesName;
return $this;
}
/**
* Get dicom_series_name
*
* @return string
*/
public function getDicomSeriesName()
{
return $this->dicom_series_name;
}
/**
* Set dicom_series_id
*
* @param string $dicomSeriesId
*
* @return Series
*/
public function setDicomSeriesId($dicomSeriesId)
{
$this->dicom_series_id = $dicomSeriesId;
return $this;
}
/**
* Get dicom_series_id
*
* @return string
*/
public function getDicomSeriesId()
{
return $this->dicom_series_id;
}
/**
* Set created
*
* @param \DateTime $created
*
* @return Series
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* @param \DateTime $updated
*
* @return Series
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* @return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set study
*
* @param Study $study
*
* @return Series
*/
public function setStudy(Study $study)
{
$this->study = $study;
return $this;
}
/**
* Get study
*
* @return Study
*/
public function getStudy()
{
return $this->study;
}
/**
* Set project
*
* @param Project $project
*
* @return Series
*/
public function setProject(Project $project)
{
$this->project = $project;
return $this;
}
/**
* Get project
*
* @return Project
*/
public function getProject()
{
return $this->project;
}
/**
* Set dicom_series_description
*
* @param string $dicomSeriesDescription
*
* @return Series
*/
public function setDicomSeriesDescription($dicomSeriesDescription)
{
$this->dicom_series_description = $dicomSeriesDescription;
return $this;
}
/**
* Get dicom_series_description
*
* @return string
*/
public function getDicomSeriesDescription()
{
return $this->dicom_series_description;
}
/**
* Set dicom_series_number
*
* @param string $dicomSeriesNumber
*
* @return Series
*/
public function setDicomSeriesNumber($dicomSeriesNumber)
{
$this->dicom_series_number = $dicomSeriesNumber;
return $this;
}
/**
* Get dicom_series_number
*
* @return string
*/
public function getDicomSeriesNumber()
{
return $this->dicom_series_number;
}
/**
* Set orthancSeriesId
*
* @param string $orthancSeriesId
*
* @return Series
*/
public function setOrthancSeriesId($orthancSeriesId)
{
$this->orthanc_series_id = $orthancSeriesId;
return $this;
}
/**
* Get orthancSeriesId
*
* @return string
*/
public function getOrthancSeriesId()
{
return $this->orthanc_series_id;
}
/**
* Add orthancTransaction
*
* @param OrthancTransaction $orthancTransaction
*
* @return Series
*/
public function addOrthancTransaction(OrthancTransaction $orthancTransaction)
{
$this->orthancTransactions[] = $orthancTransaction;
// based on the type of the transaction, we run the appropriate function
// on this Series
switch ($orthancTransaction->getType()) {
case OrthancTransaction::TYPE_SERIES_DETAILS:
$this->processOrthancSeriesDetailsTransaction($orthancTransaction);
break;
default:
throw new \Exception('Invalid OrthancTransaction Type Assigned to Series: ' . $orthancTransaction->getType());
}
return $this;
}
/**
* Given the orthancTransaction (which is assumed to be of type SERIES DETAILS)
* We update the appropriate values on this Series to indicate the various
* orthanc data returned by the storage transaction
*
* @param OrthancTransaction $orthancTransaction
*/
public function processOrthancSeriesDetailsTransaction(OrthancTransaction $orthancTransaction)
{
// first - set the submissions status to pending at the outset
$this->setOrthancSyncStatus(self::ORTHANC_SYNC_STATUS_PENDING);
// if the given transaction wasn't a success, the storage status of this
// document is automatically also a fail
if ($orthancTransaction->getTransactionStatus() != OrthancTransaction::TRANSACTION_STATUS_SUCCESS) {
$this->setOrthancSyncStatus(self::ORTHANC_SYNC_STATUS_FAILED);
return false;
}
$jsonObject = json_decode($orthancTransaction->getTransactionResponse());
$this->setOrthancParentStudyId($jsonObject->ParentStudy);
// set the status as successful
$this->setOrthancSyncStatus(self::ORTHANC_SYNC_STATUS_SUCCESS);
}
/**
* Remove orthancTransaction
*
* @param OrthancTransaction $orthancTransaction
*/
public function removeOrthancTransaction(OrthancTransaction $orthancTransaction)
{
$this->orthancTransactions->removeElement($orthancTransaction);
}
/**
* Get orthancTransactions
*
* @return Collection
*/
public function getOrthancTransactions()
{
return $this->orthancTransactions;
}
/**
* Set orthancSyncStatus
*
* @param int $orthancSyncStatus
*
* @return Series
*/
public function setOrthancSyncStatus($orthancSyncStatus)
{
$this->orthanc_sync_status = $orthancSyncStatus;
return $this;
}
/**
* Get orthancSyncStatus
*
* @return int
*/
public function getOrthancSyncStatus()
{
return $this->orthanc_sync_status;
}
/**
* Set orthancParentStudyId
*
* @param string $orthancParentStudyId
*
* @return Series
*/
public function setOrthancParentStudyId($orthancParentStudyId)
{
$this->orthanc_parent_study_id = $orthancParentStudyId;
return $this;
}
/**
* Get orthancParentStudyId
*
* @return string
*/
public function getOrthancParentStudyId()
{
return $this->orthanc_parent_study_id;
}
/**
* Returns a Associative Array which is a json_decoded array from the latest Orthanc
* Transaction that performed a details request for this Series
*
* @return array
*/
public function getOrthancDetails()
{
// get the latest successfull Series Detals Transaction
$latestOrthancSeriesDetailsTransaction = $this->getLatestOrthancSeriesDetailsTransaction();
// if there isn't one, then we return null
if (!$latestOrthancSeriesDetailsTransaction) {
return null;
}
// otherwise we return the json decoded response
$transactionResponse = $latestOrthancSeriesDetailsTransaction->getTransactionResponse();
return json_decode($transactionResponse, true);
}
/**
* Returns the most recent Orthanc Series Details Transaction linked to this
* Series. If there is one, then it will contain all the details about
* this Series that are currently stored in Orthanc
*
* @return OrthancTransaction
*/
public function getLatestOrthancSeriesDetailsTransaction()
{
// create some criteria that will find sucessful transactions of the
// appropriate type, ordered latest first
$criteria = Criteria::create()
->andWhere(Criteria::expr()->eq('transaction_status', OrthancTransaction::TRANSACTION_STATUS_SUCCESS))
->andWhere(Criteria::expr()->eq('type', OrthancTransaction::TYPE_SERIES_DETAILS))
->orderBy(['created' => Criteria::DESC])
;
// apply the criteria
$matchingTransactions = $this->getOrthancTransactions()->matching($criteria);
// if there are not matches, then return null
if ($matchingTransactions->isEmpty()) {
return null;
}
// else return the first match
return $matchingTransactions->first();
}
public function getOrthancDicomModality()
{
// first prize is that this Study has already been synced to Orthanc
// and the details have already been retrieved for this Study
$orthancDetails = $this->getOrthancDetails();
// if not then we need to at least return something
if (!$orthancDetails) {
return 'Unknown Modality';
}
// otherwise we assume that our Orthanc Details are structured correctly
// and we return the Study Description
return $orthancDetails['MainDicomTags']['Modality'] ?: 'Unknown Modality';
}
public function getOrthancDicomSeriesDescription()
{
// first prize is that this Study has already been synced to Orthanc
// and the details have already been retrieved for this Study
$orthancDetails = $this->getOrthancDetails();
// if not then we need to at least return something
if (!$orthancDetails) {
return 'No Series Description';
}
// otherwise we assume that our Orthanc Details are structured correctly
// and we return the Study Description
return @$orthancDetails['MainDicomTags']['SeriesDescription'] ?: 'No Series Description';
}
public function getOrthancDicomSeriesNumber()
{
// first prize is that this Study has already been synced to Orthanc
// and the details have already been retrieved for this Study
$orthancDetails = $this->getOrthancDetails();
// if not then we need to at least return something
if (!$orthancDetails) {
return 'No Series Number';
}
// otherwise we assume that our Orthanc Details are structured correctly
// and we return the Study Description
return @$orthancDetails['MainDicomTags']['SeriesNumber'] ?: 'No Series Number';
}
/**
* @param \DateTime $deletedAt
*
* @return Series
*/
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
return $this;
}
/**
* @return \DateTime
*/
public function getDeletedAt()
{
return $this->deletedAt;
}
/**
* @return string
*/
public function getName(): string
{
return ($this->name ?? $this->getDicomSeriesName()) ?? 'Unknown Series';
}
/**
* @param string|null $name
*
* @return Series
*/
public function setName(?string $name): Series
{
$this->name = $name;
return $this;
}
/**
* @return string|null
*/
public function getDescription(): ?string
{
return $this->description ?? $this->getOrthancDicomSeriesDescription();
}
/**
* @param string|null $description
*
* @return Series
*/
public function setDescription(?string $description): Series
{
$this->description = $description;
return $this;
}
/**
* @return Collection<int, Instance>
*/
public function getInstances(): Collection
{
return $this->instances;
}
/**
* @param Instance $instance
*
* @return $this
*/
public function addInstance(Instance $instance): self
{
if (!$this->instances->contains($instance)) {
$this->instances[] = $instance;
$instance->setParentSeries($this);
}
return $this;
}
/**
* @param Instance $instance
*
* @return $this
*/
public function removeInstance(Instance $instance): self
{
if ($this->instances->removeElement($instance)) {
// set the owning side to null (unless already changed)
if ($instance->getParentSeries() === $this) {
$instance->setParentSeries(null);
}
}
return $this;
}
}