Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 137 |
|
0.00% |
0 / 19 |
CRAP | |
0.00% |
0 / 1 |
ResultTable | |
0.00% |
0 / 137 |
|
0.00% |
0 / 19 |
2162 | |
0.00% |
0 / 1 |
index | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
12 | |||
feedDataTable | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
export | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
exportSQL | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getTestTakerColumns | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
getDeliveryColumns | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getDeliveryExecutionColumns | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getGradeColumns | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getResponseColumns | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getTraceVariableColumns | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getColumnsProvider | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getExporterService | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
156 | |||
decodeColumns | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
getTime | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
getDeliveryUri | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getResultService | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
adjustColumnByLabelAndId | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
getColumnLabelProvider | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getColumnIdProvider | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation; under version 2 |
7 | * of the License (non-upgradable). |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | * |
18 | * Copyright (c) 2009-2012 (original work) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV); |
19 | * 2012-2022 Open Assessment Technologies SA; |
20 | * |
21 | */ |
22 | |
23 | namespace oat\taoOutcomeUi\controller; |
24 | |
25 | use common_Exception; |
26 | use oat\tao\model\taskQueue\TaskLogActionTrait; |
27 | use oat\taoOutcomeUi\model\export\ColumnsProvider; |
28 | use oat\generis\model\OntologyAwareTrait; |
29 | use oat\taoOutcomeUi\model\export\DeliveryCsvResultsExporterFactory; |
30 | use oat\taoOutcomeUi\model\export\DeliveryResultsExporterFactoryInterface; |
31 | use oat\taoOutcomeUi\model\export\DeliverySqlResultsExporterFactory; |
32 | use oat\taoOutcomeUi\model\export\ResultsExporter; |
33 | use oat\taoOutcomeUi\model\ResultsService; |
34 | use oat\taoOutcomeUi\model\table\ColumnDataProvider\ColumnIdProvider; |
35 | use oat\taoOutcomeUi\model\table\ColumnDataProvider\ColumnLabelProvider; |
36 | use oat\taoOutcomeUi\model\table\ResultsPayload; |
37 | use tao_helpers_Uri; |
38 | use oat\taoDeliveryRdf\model\DeliveryAssemblyService; |
39 | |
40 | /** |
41 | * Delivery Results export functionalities |
42 | * |
43 | * @author Gyula Szucs <gyula@taotesting.com> |
44 | */ |
45 | class ResultTable extends \tao_actions_CommonModule |
46 | { |
47 | use OntologyAwareTrait; |
48 | use TaskLogActionTrait; |
49 | |
50 | public const PARAMETER_COLUMNS = 'columns'; |
51 | public const PARAMETER_DELIVERY_URI = 'uri'; |
52 | public const PARAMETER_FILTER = 'filter'; |
53 | |
54 | public const PARAMETER_START_FROM = 'startfrom'; |
55 | public const PARAMETER_START_TO = 'startto'; |
56 | public const PARAMETER_END_FROM = 'endfrom'; |
57 | public const PARAMETER_END_TO = 'endto'; |
58 | |
59 | /** |
60 | * Return the Result Table entry page displaying the datatable and the filters to be applied. |
61 | * |
62 | * @throws \tao_models_classes_MissingRequestParameterException |
63 | */ |
64 | public function index() |
65 | { |
66 | $deliveryService = DeliveryAssemblyService::singleton(); |
67 | if ($this->getRequestParameter('classUri') !== $deliveryService->getRootClass()->getUri()) { |
68 | $filter = $this->getRequestParameter('filter'); |
69 | $uri = $this->getRequestParameter('uri'); |
70 | if (!\common_Utils::isUri(tao_helpers_Uri::decode($uri))) { |
71 | throw new \tao_models_classes_MissingRequestParameterException('uri'); |
72 | } |
73 | $this->setData('filter', $filter); |
74 | $this->setData('uri', $uri); |
75 | $this->setData( |
76 | 'allowSqlExport', |
77 | $this->getResultService()->getOption(ResultsService::OPTION_ALLOW_SQL_EXPORT) |
78 | ); |
79 | $this->setData( |
80 | 'allowTraceVariableExport', |
81 | $this->getResultService()->getOption( |
82 | ResultsService::OPTION_ALLOW_TRACE_VARIABLES_EXPORT, |
83 | false |
84 | ) |
85 | ); |
86 | $this->setView('resultTable.tpl'); |
87 | } else { |
88 | $this->setData('type', 'info'); |
89 | $message = 'No tests have been taken yet.' . |
90 | ' As soon as a test-taker will take a test his results will be displayed here.'; |
91 | $this->setData('error', __($message)); |
92 | $this->setView('index.tpl'); |
93 | } |
94 | } |
95 | |
96 | /** |
97 | * Feeds js datatable component with the values to be exported. |
98 | * |
99 | * @throws common_Exception |
100 | */ |
101 | public function feedDataTable() |
102 | { |
103 | if (!$this->isXmlHttpRequest()) { |
104 | throw new \Exception('Only ajax call allowed.'); |
105 | } |
106 | |
107 | if (!$this->hasRequestParameter(self::PARAMETER_COLUMNS)) { |
108 | throw new common_Exception('Parameter "' . self::PARAMETER_COLUMNS . '" missing'); |
109 | } |
110 | |
111 | $resultPayload = new ResultsPayload( |
112 | $this->getExporterService(new DeliveryCsvResultsExporterFactory())->getExporter() |
113 | ); |
114 | $this->returnJson( |
115 | $resultPayload->getPayload() |
116 | ); |
117 | } |
118 | |
119 | /** |
120 | * Exports results by a single delivery in csv format. |
121 | * |
122 | * Only creating the export task. |
123 | * |
124 | * @throws \Exception |
125 | */ |
126 | public function export() |
127 | { |
128 | if (!$this->isXmlHttpRequest()) { |
129 | throw new \Exception('Only ajax call allowed.'); |
130 | } |
131 | |
132 | return $this->returnTaskJson( |
133 | $this->getExporterService(new DeliveryCsvResultsExporterFactory())->createExportTask() |
134 | ); |
135 | } |
136 | |
137 | /** |
138 | * Exports results by a single delivery in sql format. |
139 | * |
140 | * Only creating the export task. |
141 | * |
142 | * @throws \Exception |
143 | */ |
144 | public function exportSQL() |
145 | { |
146 | if (!$this->isXmlHttpRequest()) { |
147 | throw new \Exception('Only ajax call allowed.'); |
148 | } |
149 | |
150 | return $this->returnTaskJson( |
151 | $this->getExporterService(new DeliverySqlResultsExporterFactory())->createExportTask() |
152 | ); |
153 | } |
154 | |
155 | /** |
156 | * Returns test taker metadata columns. |
157 | * |
158 | * @throws \Exception |
159 | */ |
160 | public function getTestTakerColumns() |
161 | { |
162 | if (!$this->isXmlHttpRequest()) { |
163 | throw new \Exception('Only ajax call allowed.'); |
164 | } |
165 | |
166 | return $this->returnJson([ |
167 | 'columns' => $this->adjustColumnByLabelAndId( |
168 | $this->getColumnsProvider()->getTestTakerColumns() |
169 | ), |
170 | 'first' => true |
171 | ]); |
172 | } |
173 | |
174 | /** |
175 | * Returns delivery metadata columns. |
176 | * |
177 | * @throws \Exception |
178 | */ |
179 | public function getDeliveryColumns() |
180 | { |
181 | if (!$this->isXmlHttpRequest()) { |
182 | throw new \common_exception_Error('Only ajax call allowed.'); |
183 | } |
184 | |
185 | return $this->returnJson([ |
186 | 'columns' => $this->adjustColumnByLabelAndId( |
187 | $this->getColumnsProvider()->getDeliveryColumns() |
188 | ) |
189 | ]); |
190 | } |
191 | |
192 | /** |
193 | * Returns delivery execution metadata columns. |
194 | * |
195 | * @throws \Exception |
196 | */ |
197 | public function getDeliveryExecutionColumns() |
198 | { |
199 | if (!$this->isXmlHttpRequest()) { |
200 | throw new \common_exception_Error('Only ajax call allowed.'); |
201 | } |
202 | |
203 | return $this->returnJson([ |
204 | 'columns' => $this->adjustColumnByLabelAndId( |
205 | $this->getColumnsProvider()->getDeliveryExecutionColumns() |
206 | ) |
207 | ]); |
208 | } |
209 | |
210 | /** |
211 | * Returns grade columns. |
212 | * |
213 | * @throws \Exception |
214 | */ |
215 | public function getGradeColumns() |
216 | { |
217 | if (!$this->isXmlHttpRequest()) { |
218 | throw new \common_exception_Error('Only ajax call allowed.'); |
219 | } |
220 | |
221 | return $this->returnJson([ |
222 | 'columns' => $this->adjustColumnByLabelAndId( |
223 | $this->getColumnsProvider()->getGradeColumns() |
224 | ) |
225 | ]); |
226 | } |
227 | |
228 | /** |
229 | * Returns response columns. |
230 | * |
231 | * @throws \Exception |
232 | */ |
233 | public function getResponseColumns() |
234 | { |
235 | if (!$this->isXmlHttpRequest()) { |
236 | throw new \Exception('Only ajax call allowed.'); |
237 | } |
238 | return $this->returnJson([ |
239 | 'columns' => $this->adjustColumnByLabelAndId( |
240 | $this->getColumnsProvider()->getResponseColumns() |
241 | ) |
242 | ]); |
243 | } |
244 | |
245 | /** |
246 | * Returns trace variables columns. |
247 | * |
248 | * @throws \Exception |
249 | */ |
250 | public function getTraceVariableColumns() |
251 | { |
252 | if (!$this->isXmlHttpRequest()) { |
253 | throw new \Exception('Only ajax call allowed.'); |
254 | } |
255 | |
256 | return $this->returnJson([ |
257 | 'columns' => $this->getColumnsProvider()->getTraceVariablesColumns() |
258 | ]); |
259 | } |
260 | |
261 | /** |
262 | * @throws \common_exception_NotFound |
263 | * @throws common_Exception |
264 | */ |
265 | private function getColumnsProvider(): ColumnsProvider |
266 | { |
267 | return new ColumnsProvider($this->getDeliveryUri(), ResultsService::singleton()); |
268 | } |
269 | |
270 | /** |
271 | * @throws \common_exception_MissingParameter |
272 | * @throws \common_exception_NotFound |
273 | * @throws common_Exception |
274 | */ |
275 | private function getExporterService( |
276 | DeliveryResultsExporterFactoryInterface $deliveryResultsExporterFactory |
277 | ): ResultsExporter { |
278 | /** @var ResultsExporter $exporter */ |
279 | $exporter = $this->propagate( |
280 | new ResultsExporter( |
281 | $this->getDeliveryUri(), |
282 | ResultsService::singleton(), |
283 | $deliveryResultsExporterFactory |
284 | ) |
285 | ); |
286 | |
287 | if ($this->hasRequestParameter(self::PARAMETER_COLUMNS)) { |
288 | $exporter->setColumnsToExport( |
289 | $this->decodeColumns($this->getRawParameter(self::PARAMETER_COLUMNS)) |
290 | ); |
291 | } |
292 | |
293 | if ($this->hasRequestParameter(self::PARAMETER_FILTER)) { |
294 | $exporter->setVariableToExport($this->getRequestParameter(self::PARAMETER_FILTER)); |
295 | } |
296 | |
297 | $filters = []; |
298 | if ($this->hasRequestParameter(self::PARAMETER_START_FROM)) { |
299 | $time = $this->getTime($this->getRequestParameter(self::PARAMETER_START_FROM)); |
300 | if ($time) { |
301 | $filters[self::PARAMETER_START_FROM] = $time; |
302 | } |
303 | } |
304 | if ($this->hasRequestParameter(self::PARAMETER_START_TO)) { |
305 | $time = $this->getTime($this->getRequestParameter(self::PARAMETER_START_TO)); |
306 | if ($time) { |
307 | $filters[self::PARAMETER_START_TO] = $time; |
308 | } |
309 | } |
310 | if ($this->hasRequestParameter(self::PARAMETER_END_FROM)) { |
311 | $time = $this->getTime($this->getRequestParameter(self::PARAMETER_END_FROM)); |
312 | if ($time) { |
313 | $filters[self::PARAMETER_END_FROM] = $time; |
314 | } |
315 | } |
316 | if ($this->hasRequestParameter(self::PARAMETER_END_TO)) { |
317 | $time = $this->getTime($this->getRequestParameter(self::PARAMETER_END_TO)); |
318 | if ($time) { |
319 | $filters[self::PARAMETER_END_TO] = $time; |
320 | } |
321 | } |
322 | |
323 | if (count($filters)) { |
324 | $exporter->setFiltersToExport($filters); |
325 | } |
326 | |
327 | return $exporter; |
328 | } |
329 | |
330 | private function decodeColumns(string $columnsJson): array |
331 | { |
332 | return ($columnsData = json_decode($columnsJson, true)) !== null && json_last_error() === JSON_ERROR_NONE |
333 | ? (array)$columnsData |
334 | : []; |
335 | } |
336 | |
337 | private function getTime($date = '') |
338 | { |
339 | return $date ? strtotime($date) : 0; |
340 | } |
341 | |
342 | /** |
343 | * @throws common_Exception |
344 | */ |
345 | private function getDeliveryUri(): string |
346 | { |
347 | if (!$this->hasRequestParameter(self::PARAMETER_DELIVERY_URI)) { |
348 | throw new common_Exception('Parameter "' . self::PARAMETER_DELIVERY_URI . '" missing'); |
349 | } |
350 | |
351 | return \tao_helpers_Uri::decode($this->getRequestParameter(self::PARAMETER_DELIVERY_URI)); |
352 | } |
353 | |
354 | private function getResultService(): ResultsService |
355 | { |
356 | return $this->getServiceLocator()->get(ResultsService::SERVICE_ID); |
357 | } |
358 | |
359 | private function adjustColumnByLabelAndId(array $columns): array |
360 | { |
361 | $columnIdProvider = $this->getColumnIdProvider(); |
362 | $columnLabelProvider = $this->getColumnLabelProvider(); |
363 | |
364 | return array_map(static function (array $record) use ($columnIdProvider, $columnLabelProvider) { |
365 | $record['label'] = $columnLabelProvider->provideFromColumnArray($record); |
366 | $record['columnId'] = $columnIdProvider->provideFromColumnArray($record); |
367 | |
368 | return $record; |
369 | }, $columns); |
370 | } |
371 | |
372 | private function getColumnLabelProvider(): ColumnLabelProvider |
373 | { |
374 | return $this->getServiceLocator()->getContainer()->get(ColumnLabelProvider::class); |
375 | } |
376 | |
377 | private function getColumnIdProvider(): ColumnIdProvider |
378 | { |
379 | return $this->getServiceLocator()->getContainer()->get(ColumnIdProvider::class); |
380 | } |
381 | } |