src/Entity/Patient.php line 24

Open in your IDE?
  1. <?php
  2. namespace MedBrief\MSR\Entity;
  3. use DH\Auditor\Provider\Doctrine\Auditing\Annotation as Audit;
  4. use Doctrine\Common\Collections\Criteria;
  5. use Doctrine\ORM\Mapping as ORM;
  6. use Gedmo\Mapping\Annotation as Gedmo;
  7. use MedBrief\MSR\Repository\PatientRepository;
  8. /**
  9. * Patient
  10. *
  11. * @ORM\Table(name="Patient", indexes={@ORM\Index(name="orthanc_patient_id_index", columns={"orthanc_patient_id"})})
  12. *
  13. * @ORM\Entity(repositoryClass=PatientRepository::class)
  14. *
  15. * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
  16. *
  17. * @Audit\Auditable
  18. *
  19. * @Audit\Security(view={"ROLE_ALLOWED_TO_AUDIT"})
  20. */
  21. class Patient
  22. {
  23. public const ORTHANC_SYNC_STATUS_PENDING = 1;
  24. public const ORTHANC_SYNC_STATUS_FAILED = 2;
  25. public const ORTHANC_SYNC_STATUS_SUCCESS = 3;
  26. /**
  27. * @var int
  28. *
  29. * @ORM\Column(name="id", type="integer")
  30. *
  31. * @ORM\Id
  32. *
  33. * @ORM\GeneratedValue(strategy="IDENTITY")
  34. */
  35. private $id;
  36. /**
  37. * @var \DateTime|null
  38. *
  39. * @ORM\Column(name="deletedAt", type="datetime", nullable=true)
  40. */
  41. private $deletedAt;
  42. /**
  43. * @var string|null
  44. *
  45. * @ORM\Column(name="dicom_patient_name", type="string", nullable=true)
  46. */
  47. private $dicom_patient_name;
  48. /**
  49. * @var string|null
  50. *
  51. * @ORM\Column(name="dicom_patient_id", type="string", nullable=true)
  52. */
  53. private $dicom_patient_id;
  54. /**
  55. * @var int|null
  56. *
  57. * @ORM\Column(name="orthanc_sync_status", type="integer", nullable=true)
  58. */
  59. private $orthanc_sync_status;
  60. /**
  61. * @var string|null
  62. *
  63. * @ORM\Column(name="orthanc_patient_id", type="string", nullable=true)
  64. */
  65. private $orthanc_patient_id;
  66. /**
  67. * @var \DateTime
  68. *
  69. * @ORM\Column(name="created", type="datetime")
  70. *
  71. * @Gedmo\Timestampable(on="create")
  72. */
  73. private $created;
  74. /**
  75. * @var \DateTime
  76. *
  77. * @ORM\Column(name="updated", type="datetime")
  78. *
  79. * @Gedmo\Timestampable(on="update")
  80. */
  81. private $updated;
  82. /**
  83. * @var \Doctrine\Common\Collections\Collection
  84. *
  85. * @ORM\OneToMany(targetEntity="MedBrief\MSR\Entity\Study", mappedBy="patient")
  86. */
  87. private $studies;
  88. /**
  89. * @var \Doctrine\Common\Collections\Collection
  90. *
  91. * @ORM\OneToMany(targetEntity="MedBrief\MSR\Entity\OrthancTransaction", mappedBy="patient", cascade={"all"})
  92. */
  93. private $orthancTransactions;
  94. /**
  95. * @var Project
  96. *
  97. * @ORM\ManyToOne(targetEntity="MedBrief\MSR\Entity\Project", inversedBy="patients")
  98. *
  99. * @ORM\JoinColumns({
  100. *
  101. * @ORM\JoinColumn(name="project_id", referencedColumnName="id", nullable=false)
  102. * })
  103. */
  104. private $project;
  105. /**
  106. * Constructor
  107. */
  108. public function __construct()
  109. {
  110. $this->studies = new \Doctrine\Common\Collections\ArrayCollection();
  111. $this->orthancTransactions = new \Doctrine\Common\Collections\ArrayCollection();
  112. }
  113. public function __clone()
  114. {
  115. if ($this->id) {
  116. $this->id = null;
  117. $this->studies = new \Doctrine\Common\Collections\ArrayCollection();
  118. $this->orthancTransactions = new \Doctrine\Common\Collections\ArrayCollection();
  119. }
  120. }
  121. public function __toString()
  122. {
  123. return $this->getOrthancPatientName();
  124. }
  125. /**
  126. * Get id
  127. *
  128. * @return int
  129. */
  130. public function getId()
  131. {
  132. return $this->id;
  133. }
  134. /**
  135. * Set dicom_patient_name
  136. *
  137. * @param string $dicomPatientName
  138. *
  139. * @return Patient
  140. */
  141. public function setDicomPatientName($dicomPatientName)
  142. {
  143. $this->dicom_patient_name = $dicomPatientName;
  144. return $this;
  145. }
  146. /**
  147. * Get dicom_patient_name
  148. *
  149. * @return string
  150. */
  151. public function getDicomPatientName()
  152. {
  153. return $this->dicom_patient_name;
  154. }
  155. /**
  156. * Set dicom_patient_id
  157. *
  158. * @param string $dicomPatientId
  159. *
  160. * @return Patient
  161. */
  162. public function setDicomPatientId($dicomPatientId)
  163. {
  164. $this->dicom_patient_id = $dicomPatientId;
  165. return $this;
  166. }
  167. /**
  168. * Get dicom_patient_id
  169. *
  170. * @return string
  171. */
  172. public function getDicomPatientId()
  173. {
  174. return $this->dicom_patient_id;
  175. }
  176. /**
  177. * Set created
  178. *
  179. * @param \DateTime $created
  180. *
  181. * @return Patient
  182. */
  183. public function setCreated($created)
  184. {
  185. $this->created = $created;
  186. return $this;
  187. }
  188. /**
  189. * Get created
  190. *
  191. * @return \DateTime
  192. */
  193. public function getCreated()
  194. {
  195. return $this->created;
  196. }
  197. /**
  198. * Set updated
  199. *
  200. * @param \DateTime $updated
  201. *
  202. * @return Patient
  203. */
  204. public function setUpdated($updated)
  205. {
  206. $this->updated = $updated;
  207. return $this;
  208. }
  209. /**
  210. * Get updated
  211. *
  212. * @return \DateTime
  213. */
  214. public function getUpdated()
  215. {
  216. return $this->updated;
  217. }
  218. /**
  219. * Add studies
  220. *
  221. * @param Study $studies
  222. *
  223. * @return Patient
  224. */
  225. public function addStudy(Study $studies)
  226. {
  227. $this->studies[] = $studies;
  228. return $this;
  229. }
  230. /**
  231. * Remove studies
  232. *
  233. * @param Study $studies
  234. */
  235. public function removeStudy(Study $studies)
  236. {
  237. $this->studies->removeElement($studies);
  238. }
  239. /**
  240. * Get studies
  241. *
  242. * @return \Doctrine\Common\Collections\Collection|Study[]
  243. */
  244. public function getStudies()
  245. {
  246. return $this->studies;
  247. }
  248. /**
  249. * Set project
  250. *
  251. * @param Project $project
  252. *
  253. * @return Patient
  254. */
  255. public function setProject(Project $project)
  256. {
  257. $this->project = $project;
  258. return $this;
  259. }
  260. /**
  261. * Get project
  262. *
  263. * @return Project
  264. */
  265. public function getProject()
  266. {
  267. return $this->project;
  268. }
  269. /**
  270. * Set orthancPatientId
  271. *
  272. * @param string $orthancPatientId
  273. *
  274. * @return Patient
  275. */
  276. public function setOrthancPatientId($orthancPatientId)
  277. {
  278. $this->orthanc_patient_id = $orthancPatientId;
  279. return $this;
  280. }
  281. /**
  282. * Get orthancPatientId
  283. *
  284. * @return string
  285. */
  286. public function getOrthancPatientId()
  287. {
  288. return $this->orthanc_patient_id;
  289. }
  290. /**
  291. * Add orthancTransaction
  292. *
  293. * @param OrthancTransaction $orthancTransaction
  294. *
  295. * @return Patient
  296. */
  297. public function addOrthancTransaction(OrthancTransaction $orthancTransaction)
  298. {
  299. $this->orthancTransactions[] = $orthancTransaction;
  300. // based on the type of the transaction, we run the appropriate function
  301. // on this Patient
  302. switch ($orthancTransaction->getType()) {
  303. case OrthancTransaction::TYPE_PATIENT_DETAILS:
  304. $this->processOrthancPatientDetailsTransaction($orthancTransaction);
  305. break;
  306. default:
  307. throw new \Exception('Invalid OrthancTransaction Type Assigned to Patient: ' . $orthancTransaction->getType());
  308. }
  309. return $this;
  310. }
  311. /**
  312. * Given the orthancTransaction (which is assumed to be of type PATIENT DETAILS)
  313. * We update the appropriate values on this Patient to indicate the various
  314. * orthanc data returned by the storage transaction.
  315. *
  316. * @todo at the moment we dont actually store any extra information on the
  317. * Patient
  318. *
  319. * @param OrthancTransaction $orthancTransaction
  320. */
  321. public function processOrthancPatientDetailsTransaction(OrthancTransaction $orthancTransaction)
  322. {
  323. // first - set the submissions status to pending at the outset
  324. $this->setOrthancSyncStatus(self::ORTHANC_SYNC_STATUS_PENDING);
  325. // if the given transaction wasn't a success, the storage status of this
  326. // document is automatically also a fail
  327. if ($orthancTransaction->getTransactionStatus() != OrthancTransaction::TRANSACTION_STATUS_SUCCESS) {
  328. $this->setOrthancSyncStatus(self::ORTHANC_SYNC_STATUS_FAILED);
  329. return false;
  330. }
  331. //$jsonObject = json_decode($orthancTransaction->getTransactionResponse());
  332. //$this->setOrthancParentPatientId($jsonObject->ParentPatient);
  333. // set the status as successful
  334. $this->setOrthancSyncStatus(self::ORTHANC_SYNC_STATUS_SUCCESS);
  335. }
  336. /**
  337. * Remove orthancTransaction
  338. *
  339. * @param OrthancTransaction $orthancTransaction
  340. */
  341. public function removeOrthancTransaction(OrthancTransaction $orthancTransaction)
  342. {
  343. $this->orthancTransactions->removeElement($orthancTransaction);
  344. }
  345. /**
  346. * Get orthancTransactions
  347. *
  348. * @return \Doctrine\Common\Collections\Collection
  349. */
  350. public function getOrthancTransactions()
  351. {
  352. return $this->orthancTransactions;
  353. }
  354. /**
  355. * Set orthancSyncStatus
  356. *
  357. * @param int $orthancSyncStatus
  358. *
  359. * @return Patient
  360. */
  361. public function setOrthancSyncStatus($orthancSyncStatus)
  362. {
  363. $this->orthanc_sync_status = $orthancSyncStatus;
  364. return $this;
  365. }
  366. /**
  367. * Get orthancSyncStatus
  368. *
  369. * @return int
  370. */
  371. public function getOrthancSyncStatus()
  372. {
  373. return $this->orthanc_sync_status;
  374. }
  375. /**
  376. * Returns a Associative Array which is a json_decoded array from the latest Orthanc
  377. * Transaction that performed a details request for this Patient
  378. *
  379. * @return array
  380. */
  381. public function getOrthancDetails()
  382. {
  383. // get the latest successfull Patient Detals Transaction
  384. $latestOrthancPatientDetailsTransaction = $this->getLatestOrthancPatientDetailsTransaction();
  385. // if there isn't one, then we return null
  386. if (!$latestOrthancPatientDetailsTransaction) {
  387. return null;
  388. }
  389. // otherwise we return the json decoded response
  390. $transactionResponse = $latestOrthancPatientDetailsTransaction->getTransactionResponse();
  391. return json_decode($transactionResponse, true);
  392. }
  393. /**
  394. * Returns the most recent Orthanc Patient Details Transaction linked to this
  395. * Patient. If there is one, then it will contain all the details about
  396. * this Patient that are currently stored in Orthanc
  397. *
  398. * @return mixed
  399. */
  400. public function getLatestOrthancPatientDetailsTransaction()
  401. {
  402. // create some criteria that will find sucessful transactions of the
  403. // appropriate type, ordered latest first
  404. $criteria = Criteria::create()
  405. ->andWhere(Criteria::expr()->eq('transaction_status', OrthancTransaction::TRANSACTION_STATUS_SUCCESS))
  406. ->andWhere(Criteria::expr()->eq('type', OrthancTransaction::TYPE_PATIENT_DETAILS))
  407. ->orderBy(['created' => Criteria::DESC])
  408. ;
  409. // apply the criteria
  410. $matchingTransactions = $this->getOrthancTransactions()->matching($criteria);
  411. // if there are not matches, then return null
  412. if ($matchingTransactions->isEmpty()) {
  413. return null;
  414. }
  415. // else return the first match
  416. $firstMatchingTransaction = $matchingTransactions->first();
  417. return $firstMatchingTransaction;
  418. }
  419. public function getOrthancPatientName()
  420. {
  421. // first prize is that this Patient has already been synced to Orthanc
  422. // and the details have already been retrieved for this patient
  423. $orthancDetails = $this->getOrthancDetails();
  424. // if not then we need to at least return something
  425. if (!$orthancDetails) {
  426. return 'Unknown Patient';
  427. }
  428. // otherwise we assume that our Orthanc Details are structured correctly
  429. // and we return the Patient Name
  430. // note the leading ampersands which suppress notices, which we can't
  431. // have in the __toString method;
  432. $patientName = @$orthancDetails['MainDicomTags']['PatientName'] ?: @$orthancDetails['MainDicomTags']['PatientID'];
  433. if (empty($patientName)) {
  434. $patientName = 'No Patient Name';
  435. }
  436. return $patientName;
  437. }
  438. public function getOrthancDicomId()
  439. {
  440. // first prize is that this Patient has already been synced to Orthanc
  441. // and the details have already been retrieved for this patient
  442. $orthancDetails = $this->getOrthancDetails();
  443. // if not then we need to at least return something
  444. if (!$orthancDetails) {
  445. return 'Unknown Patient';
  446. }
  447. // otherwise we assume that our Orthanc Details are structured correctly
  448. // and we return the Patient Name
  449. $patientId = $orthancDetails['MainDicomTags']['PatientID'];
  450. if (empty($patientId)) {
  451. $patientId = 'No Patient Id';
  452. }
  453. return $patientId;
  454. }
  455. /**
  456. * Set deletedAt
  457. *
  458. * @param \DateTime $deletedAt
  459. *
  460. * @return Patient
  461. */
  462. public function setDeletedAt($deletedAt)
  463. {
  464. $this->deletedAt = $deletedAt;
  465. return $this;
  466. }
  467. /**
  468. * Get deletedAt
  469. *
  470. * @return \DateTime
  471. */
  472. public function getDeletedAt()
  473. {
  474. return $this->deletedAt;
  475. }
  476. }