Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractTestExport
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 9
552
0.00% covered (danger)
0.00%
0 / 1
 getLabel
n/a
0 / 0
n/a
0 / 0
0
 getFormTitle
n/a
0 / 0
n/a
0 / 0
0
 getExportForm
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTestExporter
n/a
0 / 0
n/a
0 / 0
0
 getFormData
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 export
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
210
 triggerTestExportEvent
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getExportingFileName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEmptyManifest
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getResourceService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getServiceManager
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getZip
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
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) 2014-2022 (original work) Open Assessment Technologies SA;
19 */
20
21declare(strict_types=1);
22
23namespace oat\taoQtiTest\models\export;
24
25use common_Exception;
26use common_exception_Error;
27use core_kernel_classes_Class as ResourcesClass;
28use core_kernel_classes_Resource as Resource;
29use Laminas\ServiceManager\ServiceLocatorAwareTrait;
30use oat\generis\model\OntologyAwareTrait;
31use oat\oatbox\event\EventManagerAwareTrait;
32use oat\oatbox\PhpSerializable;
33use oat\oatbox\PhpSerializeStateless;
34use oat\oatbox\reporting\Report;
35use oat\oatbox\reporting\ReportInterface;
36use oat\oatbox\service\ServiceManager;
37use oat\tao\model\resources\SecureResourceServiceInterface;
38use oat\taoQtiTest\models\event\QtiTestExportEvent;
39use oat\taoQtiTest\models\QtiTestUtils;
40use tao_helpers_File;
41use tao_helpers_form_Form as Form;
42use tao_models_classes_export_ExportHandler as ExportHandler;
43use ZipArchive;
44
45abstract class AbstractTestExport implements ExportHandler, PhpSerializable
46{
47    use PhpSerializeStateless;
48    use EventManagerAwareTrait;
49    use ServiceLocatorAwareTrait;
50    use OntologyAwareTrait;
51
52    protected ZipArchive $zip;
53
54    abstract public function getLabel(): string;
55
56    abstract protected function getFormTitle(): string;
57
58    /** @throws common_Exception */
59    public function getExportForm(Resource $resource): Form
60    {
61        return (new ExportForm($this->getFormData($resource), [], $this->getFormTitle()))->getForm();
62    }
63
64    abstract protected function getTestExporter(Resource $instance): QtiTestExporterInterface;
65
66    protected function getFormData(Resource $resource): array
67    {
68        $formData = [];
69
70        if ($resource instanceof ResourcesClass) {
71            $formData['items'] = $this->getResourceService()->getAllChildren($resource);
72            $formData['file_name'] = $resource->getLabel();
73        } else {
74            $formData['instance'] = $resource;
75        }
76
77        return $formData;
78    }
79
80    /**
81     * @param array $formValues
82     * @param string $destination
83     * @throws common_Exception
84     * @throws common_exception_Error
85     */
86    public function export($formValues, $destination): Report
87    {
88        if (empty($formValues['filename'])) {
89            return Report::createError(__('Missing filename for QTI Test export'));
90        }
91
92        $instances = is_string($formValues['instances'])
93            ? [$formValues['instances']]
94            : $formValues['instances'];
95
96        if (!count($instances)) {
97            return Report::createError(__('No instance in form to export'));
98        }
99
100        $report = Report::createSuccess('');
101
102        $path = tao_helpers_File::concat([$destination, $this->getExportingFileName($formValues['filename'])]);
103
104        if (tao_helpers_File::securityCheck($path, true) === false) {
105            throw new common_Exception('Unauthorized file name for QTI Test ZIP archive.');
106        }
107
108        // Create a new ZIP archive to store data related to the QTI Test.
109        $this->zip = new ZipArchive();
110        if ($this->zip->open($path, ZipArchive::CREATE) !== true) {
111            throw new common_Exception(sprintf('Unable to create ZIP archive for QTI Test at location "%s".', $path));
112        }
113
114        $manifest = $this->getServiceManager()->get(QtiTestUtils::SERVICE_ID)->emptyImsManifest(static::VERSION);
115
116        foreach ($instances as $instance) {
117            $subReport = $this->getTestExporter($this->getResource($instance))->export(['manifest' => $manifest]);
118            if (
119                $report->getType() !== ReportInterface::TYPE_ERROR &&
120                ($subReport->containsError() || $subReport->getType() === ReportInterface::TYPE_ERROR)
121            ) {
122                $report->setType(ReportInterface::TYPE_ERROR);
123                $report->setMessage(__('Not all test could be exported'));
124            }
125            $report->add($subReport);
126        }
127
128        $this->zip->close();
129
130        if (!isset($formValues['uri']) && !isset($formValues['classUri'])) {
131            $report->add(Report::createError(__('Export failed. Key uri nor classUri in formValues are not defined')));
132        } else {
133            $subjectUri = $formValues['uri'] ?? $formValues['classUri'];
134        }
135
136        if (isset($subjectUri) && !$report->containsError()) {
137            $this->triggerTestExportEvent($this->getResource($subjectUri));
138            $report->setMessage(__('Resource(s) successfully exported.'));
139        }
140
141        $report->setData(['path' => $path]);
142
143        return $report;
144    }
145
146    protected function triggerTestExportEvent(Resource $test)
147    {
148        $this->getEventManager()->trigger(new QtiTestExportEvent($test));
149    }
150
151    protected function getExportingFileName(string $userDefinedName): string
152    {
153        return sprintf('%s_%d.zip', $userDefinedName, time());
154    }
155
156    protected function getEmptyManifest()
157    {
158        return $this->getServiceManager()->get(QtiTestUtils::SERVICE_ID)->emptyImsManifest(static::VERSION);
159    }
160
161    /** @noinspection PhpIncompatibleReturnTypeInspection */
162    protected function getResourceService(): SecureResourceServiceInterface
163    {
164        return $this->getServiceManager()->get(SecureResourceServiceInterface::SERVICE_ID);
165    }
166
167    protected function getServiceManager(): ServiceManager
168    {
169        return ServiceManager::getServiceManager();
170    }
171
172    protected function getZip(): ZipArchive
173    {
174        return $this->zip;
175    }
176}