Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
99.15% covered (success)
99.15%
116 / 117
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ReportBuilder
99.15% covered (success)
99.15%
116 / 117
83.33% covered (warning)
83.33%
5 / 6
30
0.00% covered (danger)
0.00%
0 / 1
 buildByResults
98.08% covered (success)
98.08%
51 / 52
0.00% covered (danger)
0.00%
0 / 1
15
 buildByException
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 createAndAddSubReport
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 createReportByResults
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
5
 createReportByException
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 getReportType
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
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) 2021  (original work) Open Assessment Technologies SA;
19 */
20
21declare(strict_types=1);
22
23namespace oat\taoQtiItem\model\import\Report;
24
25use core_kernel_classes_Resource;
26use oat\oatbox\reporting\Report;
27use oat\oatbox\service\ConfigurableService;
28use oat\taoQtiItem\model\import\ItemImportResult;
29use oat\taoQtiItem\model\import\Validator\AbstractValidationException;
30use oat\taoQtiItem\model\import\Validator\ErrorValidationException;
31use oat\taoQtiItem\model\import\Validator\WarningValidationException;
32use Throwable;
33
34class ReportBuilder extends ConfigurableService
35{
36    public function buildByResults(ItemImportResult $results, core_kernel_classes_Resource $resource = null): Report
37    {
38        $reportType = $this->getReportType($results);
39        $subReportType = in_array($reportType, [Report::TYPE_INFO, Report::TYPE_SUCCESS])
40            ? Report::TYPE_SUCCESS
41            : $reportType;
42
43        $subReport = $this->createReportByResults($subReportType, $results);
44        $subReport->setData($resource ?? []);
45
46        $report = $this->createReportByResults($reportType, $results);
47        $report->setData($resource ?? []);
48        $report->add($subReport);
49
50        $onlyWarningReports = [];
51        $warningAndErrorReports = [];
52
53        /** @var WarningValidationException[]|ErrorValidationException[] $exceptions */
54        foreach ($results->getErrorsAndWarnings() as $lineNumber => $exceptions) {
55            $warningReports = [];
56            $errorReports = [];
57
58            foreach ($exceptions as $exception) {
59                if ($exception instanceof WarningValidationException) {
60                    $warningReports[] = $this->createReportByException($exception);
61                }
62
63                if ($exception instanceof ErrorValidationException) {
64                    $errorReports[] = $this->createReportByException($exception);
65                }
66            }
67
68            if (empty($errorReports) && empty($warningReports)) {
69                continue;
70            }
71
72            $lineMainReport = Report::create(
73                empty($errorReports) ? Report::TYPE_WARNING : Report::TYPE_ERROR,
74                'line %s: %s',
75                [
76                    $lineNumber,
77                    '',
78                ]
79            );
80
81            foreach ($errorReports as $errorReport) {
82                $lineMainReport->add($errorReport);
83            }
84
85            foreach ($warningReports as $warningReport) {
86                $lineMainReport->add($warningReport);
87            }
88
89            if (empty($errorReports)) {
90                $onlyWarningReports[$lineNumber] = $lineMainReport;
91            }
92
93            if (!empty($errorReports)) {
94                $warningAndErrorReports[$lineNumber] = $lineMainReport;
95            }
96        }
97
98        if (!empty($warningAndErrorReports)) {
99            $this->createAndAddSubReport(
100                $report,
101                $warningAndErrorReports,
102                Report::TYPE_ERROR,
103                '%s line(s) contain(s) an error and cannot be imported'
104            );
105        }
106
107        if (!empty($onlyWarningReports)) {
108            $this->createAndAddSubReport(
109                $report,
110                $onlyWarningReports,
111                Report::TYPE_WARNING,
112                '%s line(s) are imported with warnings'
113            );
114        }
115
116        return $report;
117    }
118
119    public function buildByException(Throwable $exception): Report
120    {
121        $report = Report::create(Report::TYPE_ERROR, 'CSV import failed');
122        $report->add(
123            Report::create(
124                Report::TYPE_ERROR,
125                'An unexpected error occurred during the CSV import. The system returned the following error: `%s`',
126                [
127                    $exception->getMessage(),
128                ]
129            )
130        );
131
132        return $report;
133    }
134
135    private function createAndAddSubReport(
136        Report $mainReport,
137        array $reports,
138        string $reportType,
139        string $message
140    ): void {
141        $newReport = Report::create(
142            $reportType,
143            $message,
144            [
145                count($reports),
146            ]
147        );
148
149        foreach ($reports as $subReport) {
150            $newReport->add($subReport);
151        }
152
153        $mainReport->add($newReport);
154    }
155
156    private function createReportByResults(string $type, ItemImportResult $results): Report
157    {
158        if (0 === $results->getTotalSuccessfulImport() || $results->getTotalScannedItems() === 0) {
159            return Report::create(
160                $type,
161                'CSV import failed: %s/%s line(s) are imported',
162                [
163                    $results->getTotalSuccessfulImport(), $results->getTotalScannedItems()
164                ]
165            );
166        }
167
168        if (0 === $results->getTotalErrors() && 0 === $results->getTotalWarnings()) {
169            return Report::create(
170                $type,
171                'CSV import successful: %s/%s line(s) are imported',
172                [
173                    $results->getTotalSuccessfulImport(),
174                    $results->getTotalScannedItems()
175                ]
176            );
177        }
178
179        return Report::create(
180            $type,
181            'CSV import partially successful: %s/%s line(s) are imported (%s warning(s), %s error(s))',
182            [
183                $results->getTotalSuccessfulImport(),
184                $results->getTotalScannedItems(),
185                $results->getTotalWarnings(),
186                $results->getTotalErrors()
187            ]
188        );
189    }
190
191    private function createReportByException(AbstractValidationException $exception): Report
192    {
193        if ($exception instanceof WarningValidationException) {
194            return Report::create(
195                Report::TYPE_WARNING,
196                $exception->getMessage(),
197                $exception->getInterpolationData()
198            );
199        }
200
201        if ($exception instanceof ErrorValidationException) {
202            return Report::create(
203                Report::TYPE_ERROR,
204                $exception->getMessage(),
205                $exception->getInterpolationData()
206            );
207        }
208    }
209
210    private function getReportType(ItemImportResult $results): string
211    {
212        if ($results->getTotalSuccessfulImport() === 0) {
213            return Report::TYPE_ERROR;
214        }
215
216        if ($results->getTotalWarnings() === 0 && $results->getTotalErrors() === 0) {
217            return Report::TYPE_SUCCESS;
218        }
219
220        return Report::TYPE_INFO;
221    }
222}