Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 140
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ReportBuilder
0.00% covered (danger)
0.00%
0 / 140
0.00% covered (danger)
0.00%
0 / 6
1332
0.00% covered (danger)
0.00%
0 / 1
 buildByResult
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 1
380
 buildByException
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 createAndAddSubReport
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 createReportByResults
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
42
 createReportByException
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
20
 getReportType
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
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) 2022 (original work) Open Assessment Technologies SA.
19 */
20
21declare(strict_types=1);
22
23namespace oat\tao\model\StatisticalMetadata\Import\Builder;
24
25use ErrorException;
26use Throwable;
27use oat\oatbox\reporting\Report;
28use oat\tao\model\StatisticalMetadata\Import\Result\ImportResult;
29use oat\tao\model\StatisticalMetadata\Import\Exception\ErrorValidationException;
30use oat\tao\model\StatisticalMetadata\Import\Exception\HeaderValidationException;
31use oat\tao\model\StatisticalMetadata\Import\Exception\WarningValidationException;
32use oat\tao\model\StatisticalMetadata\Import\Exception\AbstractValidationException;
33
34class ReportBuilder
35{
36    public function buildByResult(ImportResult $result): Report
37    {
38        $reportType = $this->getReportType($result);
39
40        $subReport = $this
41            ->createReportByResults($reportType, $result)
42            ->setData([]);
43        $report = $this
44            ->createReportByResults($reportType, $result)
45            ->add($subReport);
46
47        $onlyWarningReports = [];
48        $warningAndErrorReports = [];
49
50        /** @var AbstractValidationException $exceptions */
51        foreach ($result->getWarningsAndErrors() as $line => $exceptions) {
52            $headerExceptionReports = [];
53            $warningReports = [];
54            $errorReports = [];
55
56            foreach ($exceptions as $exception) {
57                if ($exception instanceof HeaderValidationException) {
58                    $headerExceptionReports[] = $this->createReportByException($exception);
59
60                    continue;
61                }
62
63                if ($exception instanceof WarningValidationException) {
64                    $warningReports[] = $this->createReportByException($exception);
65
66                    continue;
67                }
68
69                if ($exception instanceof ErrorValidationException) {
70                    $errorReports[] = $this->createReportByException($exception);
71                }
72            }
73
74            if (empty($headerExceptionReports) && empty($errorReports) && empty($warningReports)) {
75                continue;
76            }
77
78            $lineMainReportType = empty($headerExceptionReports) && empty($errorReports)
79                ? Report::TYPE_WARNING
80                : Report::TYPE_ERROR;
81            $lineMainReport = Report::create($lineMainReportType, 'line %s: %s', [$line, '']);
82
83            foreach ($headerExceptionReports as $headerExceptionReport) {
84                $lineMainReport->add($headerExceptionReport);
85            }
86
87            foreach ($warningReports as $warningReport) {
88                $lineMainReport->add($warningReport);
89            }
90
91            foreach ($errorReports as $errorReport) {
92                $lineMainReport->add($errorReport);
93            }
94
95            if (empty($errorReports)) {
96                $onlyWarningReports[$line] = $lineMainReport;
97            }
98
99            if (!empty($errorReports)) {
100                $warningAndErrorReports[$line] = $lineMainReport;
101            }
102        }
103
104        if (!empty($headerExceptionReports)) {
105            $this->createAndAddSubReport(
106                $report,
107                $headerExceptionReports,
108                Report::TYPE_ERROR,
109                'Header contain error(s)'
110            );
111
112            return $report;
113        }
114
115        if (!empty($warningAndErrorReports)) {
116            $this->createAndAddSubReport(
117                $report,
118                $warningAndErrorReports,
119                Report::TYPE_ERROR,
120                '%s line(s) contain error(s) and cannot be imported'
121            );
122        }
123
124        if (!empty($onlyWarningReports)) {
125            $this->createAndAddSubReport(
126                $report,
127                $onlyWarningReports,
128                Report::TYPE_WARNING,
129                '%s line(s) are imported with warning(s)'
130            );
131        }
132
133        return $report;
134    }
135
136    public function buildByException(Throwable $exception): Report
137    {
138        $report = Report::create(Report::TYPE_ERROR, 'CSV import failed');
139        $report->add(
140            Report::create(
141                Report::TYPE_ERROR,
142                'An unexpected error occurred during the CSV import. The system returned the following error: %s',
143                [
144                    $exception->getMessage(),
145                ]
146            )
147        );
148
149        return $report;
150    }
151
152    private function createAndAddSubReport(
153        Report $mainReport,
154        array $reports,
155        string $reportType,
156        string $message
157    ): void {
158        $newReport = Report::create($reportType, $message, [count($reports)]);
159
160        foreach ($reports as $subReport) {
161            $newReport->add($subReport);
162        }
163
164        $mainReport->add($newReport);
165    }
166
167    private function createReportByResults(string $type, ImportResult $result): Report
168    {
169        if ($result->getTotalHeaderErrors()) {
170            return Report::create(
171                $type,
172                'CSV import failed: header is not valid (%d error(s))',
173                [$result->getTotalHeaderErrors()]
174            );
175        }
176
177        if ($result->getTotalImportedRecords() === 0 || $result->getTotalScannedRecords() === 0) {
178            return Report::create(
179                $type,
180                'CSV import failed: %d/%d line(s) are imported',
181                [
182                    $result->getTotalImportedRecords(),
183                    $result->getTotalScannedRecords(),
184                ]
185            );
186        }
187
188        if ($result->getTotalErrors() === 0 && $result->getTotalWarnings() === 0) {
189            return Report::create(
190                $type,
191                'CSV import successful: %d/%d line(s) are imported',
192                [
193                    $result->getTotalImportedRecords(),
194                    $result->getTotalScannedRecords(),
195                ]
196            );
197        }
198
199        return Report::create(
200            $type,
201            'CSV import partially successful: %d/%d line(s) are imported (%d warning(s), %d error(s))',
202            [
203                $result->getTotalImportedRecords(),
204                $result->getTotalScannedRecords(),
205                $result->getTotalWarnings(),
206                $result->getTotalErrors(),
207            ]
208        );
209    }
210
211    private function createReportByException(AbstractValidationException $exception): Report
212    {
213        if ($exception instanceof HeaderValidationException) {
214            return Report::create(
215                Report::TYPE_ERROR,
216                $exception->getMessage(),
217                $exception->getInterpolationData()
218            );
219        }
220
221        if ($exception instanceof WarningValidationException) {
222            return Report::create(
223                Report::TYPE_WARNING,
224                $exception->getMessage(),
225                $exception->getInterpolationData()
226            );
227        }
228
229        if ($exception instanceof ErrorValidationException) {
230            return Report::create(
231                Report::TYPE_ERROR,
232                $exception->getMessage(),
233                $exception->getInterpolationData()
234            );
235        }
236
237        throw new ErrorException(
238            sprintf(
239                'Exception "%s:%s" not support to generate statistical report',
240                get_class($exception),
241                $exception->getMessage()
242            )
243        );
244    }
245
246    private function getReportType(ImportResult $result): string
247    {
248        if ($result->getTotalImportedRecords() === 0) {
249            return Report::TYPE_ERROR;
250        }
251
252        if ($result->getTotalWarnings() === 0 && $result->getTotalErrors() === 0) {
253            return Report::TYPE_SUCCESS;
254        }
255
256        return Report::TYPE_WARNING;
257    }
258}