Export_Study_Data::exportAssociatedFiles()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 11
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 26
rs 9.9
1
<?php
2
3
/**
4
 Copyright (C) 2018-2020 KANOUN Salim
5
 This program is free software; you can redistribute it and/or modify
6
 it under the terms of the Affero GNU General Public v.3 License as published by
7
 the Free Software Foundation;
8
 This program is distributed in the hope that it will be useful,
9
 but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
 Affero GNU General Public Public for more details.
12
 You should have received a copy of the Affero GNU General Public Public along
13
 with this program; if not, write to the Free Software Foundation, Inc.,
14
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
 */
16
//SK faire evoluer vers generator pour eviter sortie memoire ?
17
18
/**
19
 * Export all data relative to a study
20
 */
21
class Export_Study_Data
22
{
23
24
	public $studyObject;
25
	private $allcreatedVisits;
26
27
	public function __construct(Study $studyObject)
28
	{
29
30
		$this->studyObject=$studyObject;
31
32
		$this->allcreatedVisits=[];
33
34
		$visitGroupArray=$this->studyObject->getAllPossibleVisitGroups();
35
36
		foreach ($visitGroupArray as $visitGroup) {
37
38
			try {
39
				$modalityCreatedVisits=$this->studyObject->getStudySpecificGroupManager($visitGroup->groupModality)->getCreatedVisits();
40
				$modalityDeletedVisits=$this->studyObject->getStudySpecificGroupManager($visitGroup->groupModality)->getCreatedVisits(true);
41
				array_push($this->allcreatedVisits, ...$modalityCreatedVisits, ...$modalityDeletedVisits);
42
			}catch (Exception $e) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
43
		}
44
	}
45
46
	/**
47
	 * Generate and fill the patients CSV
48
	 */
49
	public function exportPatientTable(): String
50
	{
51
52
		$patientCsv[]=array('Patient Code', 'Initials', 'Gender', 'Birthdate', 'Registration Date', 'Investigator Name', 'Center Code', 'Center Name', 'Country', 'Withdraw', 'Withdraw Reason', 'Withdraw Date');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$patientCsv was never initialized. Although not strictly required by PHP, it is generally a good practice to add $patientCsv = array(); before regardless.
Loading history...
53
54
		$patientsInStudy=$this->studyObject->getAllPatientsInStudy();
55
		foreach ($patientsInStudy as $patient) {
56
			$patientCenter=$patient->getPatientCenter();
57
			$patientCsv[]=array(
58
				$patient->patientCode, $patient->patientLastName.$patient->patientFirstName, $patient->patientGender,
59
				$patient->patientBirthDate, $patient->patientRegistrationDate, $patient->patientInvestigatorName, $patientCenter->code, $patientCenter->name, $patientCenter->countryName,
60
				$patient->patientWithdraw, $patient->patientWithdrawReason, $patient->patientWithdrawDateString
61
			);
62
		}
63
64
		$patientCsvString=$this->writeCsv($patientCsv);
65
66
		return $patientCsvString;
67
	}
68
69
70
	/**
71
	 * 
72
	 */
73
	public function exportAssociatedFiles()
74
	{
75
76
		$zip=new ZipArchive;
77
		$tempZip=tempnam(ini_get('upload_tmp_dir'), 'TMPZIPAF_');
78
		$zip->open($tempZip, ZipArchive::CREATE);
79
        
80
81
		foreach ($this->allcreatedVisits as $visitObject) {
82
			$reviewsObjects=$this->getAllreviewObjects($visitObject);
83
84
			foreach ($reviewsObjects as $reviewObject) {
85
86
				foreach ($reviewObject->associatedFiles as $associatedFileKey => $associatedFilePath) {
87
					$associatedFileLocation = $reviewObject->getAssociatedFilePath($associatedFileKey);
88
					$zip->addFile($associatedFileLocation);
89
90
				};
91
92
			}
93
94
		}
95
96
		$zip->close();
97
98
		return $tempZip;
99
100
	}
101
102
	/**
103
	 * Export the visit table relative to this study
104
	 */
105
	public function exportVisitTable(): String
106
	{
107
108
		$visitCSV=[];
109
110
		//Prepare visit CSV
111
		$visitCSV[]=array(
112
			'Patient Code', 'Visit Group', 'ID Visit', 'Code Status', 'Creator Name', 'Creator Date',
113
			'Type', 'Status', 'Reason For Not Done', 'Acquisition Date', 'Upload Status', 'Uploader',
114
			'Upload Date', 'State Investigator Form', 'State QC', 'QC done by', 'QC date', 'Review Status', 'Review Date', 'Review Conclusion', 'visit deleted'
115
		);
116
117
		foreach ($this->allcreatedVisits as $visit) {
118
			$codeStatus=$this->dertermineVisitStatusCode($visit);
119
			$visitCSV[]=array(
120
				$visit->patientCode, $visit->visitGroupObject->groupModality, $visit->id_visit, $codeStatus, $visit->creatorName, $visit->creationDate,
121
				$visit->visitType, $visit->statusDone, $visit->reasonForNotDone, $visit->acquisitionDate, $visit->uploadStatus, $visit->uploaderUsername,
122
				$visit->uploadDate, $visit->stateInvestigatorForm, $visit->stateQualityControl, $visit->controllerUsername, $visit->controlDate,
123
				$visit->reviewStatus, $visit->reviewConclusionDate, $visit->reviewConclusion, $visit->deleted
124
			);
125
		}
126
127
		$visitCsvString=$this->writeCsv($visitCSV);
128
129
		return $visitCsvString;
130
	}
131
132
	/**
133
	 * Export Data relative to Imaging stored data (Orthanc Stored Data)
134
	 */
135
	public function getImagingData()
136
	{
137
138
		//Prepare Orthanc Series data CSV
139
		$orthancCSV[]=array(
0 ignored issues
show
Comprehensibility Best Practice introduced by
$orthancCSV was never initialized. Although not strictly required by PHP, it is generally a good practice to add $orthancCSV = array(); before regardless.
Loading history...
140
			'ID Visit', 'Study Orthanc ID',
141
			'Study UID', 'Study Description', 'Dicom Patient Name', 'Dicom Patient ID', 'Serie Description', 'modality', 'Acquisition Date Time',
142
			'Serie Orthanc ID', 'Serie UID', 'Instance Number', 'Manufacturer', 'Disk Size', 'Serie Number', 'Patient Weight', 'Injected_Activity', 'Injected_Dose', 'Radiopharmaceutical', 'Half Life', 'Injected Time', 'Deleted'
143
		);
144
145
		$imagingVisit=array_filter($this->allcreatedVisits, function(Visit $visitObject) {
146
			$inArrayBool=in_array(
147
				$visitObject->visitGroupObject->groupModality,
148
				array(Visit_Group::GROUP_MODALITY_CT, Visit_Group::GROUP_MODALITY_PET, Visit_Group::GROUP_MODALITY_MR, Visit_Group::GROUP_MODALITY_RTSTRUCT)
149
			);
150
			return ($inArrayBool);
151
		});
152
153
		foreach ($imagingVisit as $visit) {
154
155
			$allSeries=$visit->getSeriesDetails();
156
157
			foreach ($allSeries as $serieObject) {
158
				$studyDetailsObject=$serieObject->studyDetailsObject;
159
				$orthancCSV[]=array(
160
					$studyDetailsObject->idVisit, $studyDetailsObject->studyOrthancId, $studyDetailsObject->studyUID,
161
					$studyDetailsObject->studyDescription, $studyDetailsObject->patientName, $studyDetailsObject->patientId, $serieObject->seriesDescription, $serieObject->modality, $serieObject->acquisitionDateTime, $serieObject->seriesOrthancID,
162
					$serieObject->serieUID, $serieObject->numberInstances, $serieObject->manufacturer, $serieObject->serieUncompressedDiskSize, $serieObject->seriesNumber, $serieObject->patientWeight, $serieObject->injectedActivity, $serieObject->injectedDose, $serieObject->radiopharmaceutical, $serieObject->halfLife, $serieObject->injectedDateTime, $serieObject->deleted
163
				);
164
			}
165
		}
166
167
		$orthancCsvFile=$this->writeCsv($orthancCSV);
168
169
		return $orthancCsvFile;
170
	}
171
172
	/**
173
	 * Return an associative array in which each CSV file reference will be stored
174
	 */
175
	public function getReviewData()
176
	{
177
178
		$mappedVisitByGroup=[];
179
180
		foreach ($this->allcreatedVisits as $visitObject) {
181
			$modality=$visitObject->visitGroupObject->groupModality;
182
			$visitName=$visitObject->visitType;
183
			$mappedVisitByGroup[$modality][$visitName][]=$visitObject;
184
		};
185
186
		foreach ($mappedVisitByGroup as $modality => $visitTypes) {
187
188
			$groupObject=$this->studyObject->getSpecificGroup($modality);
189
190
			foreach ($visitTypes as $visitType => $visitArray) {
191
				$csv=[];
192
193
				//Export Reviews
194
				$genericHeader=array('Patient Code', 'Visit Type', 'ID Visit', 'ID review', 'Reviewer', 'Review Date', 'Validated', 'Local Form', 'Adjudcation form', 'Review Deleted');
195
196
				$visitTypeObject=$groupObject->getVisitType($visitType);
197
				$specificFormTable=$visitTypeObject->getSpecificFormColumn();
198
				unset($specificFormTable[0]);
199
200
				$csv[]=array_merge($genericHeader, $specificFormTable);
201
202
				foreach ($visitArray as $visitObject) {
203
204
					array_push($csv, ...$this->getReviews($visitObject));
205
				}
206
207
				$reviewCsvFiles[$modality.'_'.$visitType]=$this->writeCsv($csv);
208
			}
209
		}
210
211
		return $reviewCsvFiles;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $reviewCsvFiles does not seem to be defined for all execution paths leading up to this point.
Loading history...
212
	}
213
214
	private function getAllreviewObjects(Visit $visitObject) : array {
215
216
		$localReviews=[];
217
		try {
218
			$localReviews[]=$visitObject->getReviewsObject(true);
219
		}catch (Exception $e) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
220
221
		$expertReviews=[];
0 ignored issues
show
Unused Code introduced by
The assignment to $expertReviews is dead and can be removed.
Loading history...
222
		try {
223
			$expertReviews=$visitObject->getReviewsObject(false, true);
224
		}catch (Exception $e) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
225
226
		//Merge all reviews in an array
227
		$reviewObjects=array_merge($localReviews, $expertReviews);
228
229
		return $reviewObjects;
230
231
	}
232
233
	/**
234
	 * Merge local and review form and call getReviewDatas function to build one line of the CSV array for each review
235
	 */
236
	private function getReviews(Visit $visitObject): array
237
	{
238
239
		$reviewObjects=$this->getAllreviewObjects($visitObject);
240
241
		$csv=[];
242
		foreach ($reviewObjects as $reviewObject) {
243
			$patientCode=$visitObject->patientCode;
244
			$visitType=$visitObject->visitType;
245
			$reviewData=$this->getReviewDatas($reviewObject);
246
			$csv[]=[$patientCode, $visitType, ...$reviewData];
247
		}
248
249
		return $csv;
250
	}
251
252
	/**
253
	 * Merge generic and specific column to build a CSV array
254
	 */
255
	private function getReviewDatas(Review $review): array
256
	{
257
		//Add to final map
258
		$reviewDatas=$this->getGenericData($review);
259
		$specificData=$review->getSpecificData();
260
		unset($specificData["id_review"]);
261
		$specificDataArray = [];
262
		if( !empty($specificData) ){
263
			$specificDataArray = array_values($specificData);
264
		}
265
		$reviewLine=[...$reviewDatas, ...$specificDataArray];
266
267
		return $reviewLine;
268
	}
269
270
	/**
271
	 * Build the generic part of the review array
272
	 */
273
	private function getGenericData(Review $review) : array
274
	{
275
		//Add to final map
276
		$reviewDatas=array(
277
			$review->id_visit, $review->id_review,
278
			$review->username, $review->reviewDate, $review->validated, $review->isLocal, $review->isAdjudication, $review->deleted
279
		);
280
281
		return $reviewDatas;
282
	}
283
284
	/**
285
	 * Write CSV Array to a temporary file
286
	 */
287
	private function writeCsv($csvArray) : String
288
	{
289
290
		$tempCsv=tempnam(ini_get('upload_tmp_dir'), 'TMPCSV_');
291
		$fichier_csv=fopen($tempCsv, 'w');
292
		foreach ($csvArray as $fields) {
293
			fputcsv($fichier_csv, $fields);
294
		}
295
		fclose($fichier_csv);
296
297
		return $tempCsv;
298
	}
299
300
301
	/**
302
	 * Return Code Status
303
	 * 0 Visit not Done
304
	 * 1 Done but DICOM and Form not sent
305
	 * 2 Done but upload not done (form sent)
306
	 * 3 done but investigator form not done (dicom sent)
307
	 * 4 QC not done
308
	 * 5 QC corrective action
309
	 * 6 QC refused
310
	 * 7 Review Not Done
311
	 * 8 Review ongoing
312
	 * 9 Review Wait adjudication
313
	 * 10 review done
314
	 * -1 If any of these case (should not happen)
315
	 * @param Visit $visitObject
316
	 * @return number
317
	 */
318
	private function dertermineVisitStatusCode(Visit $visitObject) : int
319
	{
320
321
		if ($visitObject->statusDone == Visit::NOT_DONE) {
322
			return 0;
323
		}else if ($visitObject->uploadStatus == Visit::NOT_DONE || $visitObject->stateInvestigatorForm == Visit::NOT_DONE) {
324
			if ($visitObject->uploadStatus == Visit::NOT_DONE && $visitObject->stateInvestigatorForm == Visit::NOT_DONE) {
325
				return 1;
326
			}else if ($visitObject->stateInvestigatorForm == Visit::NOT_DONE) {
327
				return 3;
328
			}else if ($visitObject->uploadStatus == Visit::NOT_DONE) {
329
				return 2;
330
			}
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 328 is false. This is incompatible with the type-hinted return integer. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
331
		}else if ($visitObject->qcStatus == Visit::QC_NOT_DONE) {
332
			return 4;
333
		}else if ($visitObject->qcStatus == Visit::QC_CORRECTIVE_ACTION_ASKED) {
334
			return 5;
335
		}else if ($visitObject->qcStatus == Visit::QC_REFUSED) {
336
			return 6;
337
		}else if ($visitObject->reviewStatus == Visit::NOT_DONE) {
338
			return 7;
339
		}else if ($visitObject->reviewStatus == Visit::REVIEW_ONGOING) {
340
			return 8;
341
		}else if ($visitObject->reviewStatus == Visit::REVIEW_WAIT_ADJUDICATION) {
342
			return 9;
343
		}else if ($visitObject->reviewStatus == Visit::REVIEW_DONE) {
344
			return 10;
345
		}else {
346
			//If none of these case return -1, should not happen
347
			return -1;
348
		}
349
	}
350
351
}
352