Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
AssemblyImporterService
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 7
600
0.00% covered (danger)
0.00%
0 / 1
 importDelivery
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
 getDeliveryManifest
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getAdditionalProperties
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 getRdfResourceIterator
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 importDeliveryResource
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
6
 getDeliveryUri
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
 importDeliveryFiles
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
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) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 *
20 */
21
22namespace oat\taoDeliveryRdf\model\import;
23
24use common_Utils;
25use oat\generis\model\OntologyAwareTrait;
26use ZipArchive;
27use common_report_Report;
28use core_kernel_classes_Resource;
29use core_kernel_classes_Class;
30use oat\generis\model\kernel\persistence\file\FileIterator;
31use oat\generis\model\OntologyRdfs;
32use oat\oatbox\log\LoggerAwareTrait;
33use oat\oatbox\service\ConfigurableService;
34use oat\taoDeliveryRdf\model\DeliveryAssemblyService;
35use oat\generis\model\OntologyRdf;
36
37/**
38 * AssemblyImporterService Class.
39 *
40 * Im- and export a compiled delivery
41 *
42 * @access public
43 * @package taoDeliveryRdf
44 */
45class AssemblyImporterService extends ConfigurableService
46{
47    use LoggerAwareTrait;
48    use OntologyAwareTrait;
49
50    public const MANIFEST_FILE = 'manifest.json';
51
52    public const RDF_FILE = 'delivery.rdf';
53
54    /**
55     * @param core_kernel_classes_Class $deliveryClass
56     * @param string $archiveFile
57     * @param boolean $useOriginalUri Use original delivery URI from assembly package
58     *
59     * @return common_report_Report
60     */
61    public function importDelivery(core_kernel_classes_Class $deliveryClass, $archiveFile, $useOriginalUri = false)
62    {
63        try {
64            $tmpImportFolder = \tao_helpers_File::createTempDir();
65            $zip = new ZipArchive();
66            if ($zip->open($archiveFile) !== true) {
67                return  common_report_Report::createFailure(__('Unable to import Archive'));
68            }
69            $zip->extractTo($tmpImportFolder);
70            $zip->close();
71
72            $this->importDeliveryFiles($tmpImportFolder);
73
74            $deliveryUri = $this->getDeliveryUri($useOriginalUri, $tmpImportFolder);
75            $delivery = $this->importDeliveryResource($deliveryClass, $deliveryUri, $tmpImportFolder);
76
77            $report = common_report_Report::createSuccess(
78                __('Delivery "%s" successfully imported', $delivery->getUri()),
79                $delivery
80            );
81
82            return $report;
83        } catch (AssemblyImportFailedException $e) {
84            return common_report_Report::createFailure($e->getMessage());
85        } catch (\Exception $e) {
86            $this->logError($e->getMessage());
87
88            return common_report_Report::createFailure('Unknown error during import');
89        }
90    }
91
92    /**
93     * @param string $tmpImportFolder
94     *
95     * @return array
96     * @throws AssemblyImportFailedException
97     */
98    private function getDeliveryManifest($tmpImportFolder)
99    {
100        $manifestPath = $tmpImportFolder . self::MANIFEST_FILE;
101        if (!file_exists($manifestPath)) {
102            throw new AssemblyImportFailedException('Manifest not found in assembly.');
103        }
104
105        $manifest = json_decode(file_get_contents($manifestPath), true);
106        if (!is_array($manifest) || json_last_error() !== JSON_ERROR_NONE) {
107            throw new AssemblyImportFailedException('Manifest file is not valid.');
108        }
109
110        return $manifest;
111    }
112
113    /**
114     * @param $folder
115     * @return array
116     */
117    protected function getAdditionalProperties(FileIterator $rdfIterator)
118    {
119        $properties = [];
120        $blacklist = [OntologyRdf::RDF_TYPE];
121        foreach ($rdfIterator as $triple) {
122            if (!in_array($triple->predicate, $blacklist)) {
123                if (!isset($properties[$triple->predicate])) {
124                    $properties[$triple->predicate] = [];
125                }
126                $properties[$triple->predicate][] = $triple->object;
127            }
128        }
129
130        return $properties;
131    }
132
133    /**
134     * @param $tmpImportFolder
135     * @return FileIterator
136     *
137     * @throws AssemblyImportFailedException
138     */
139    protected function getRdfResourceIterator($tmpImportFolder)
140    {
141        $rdfPath = $tmpImportFolder . self::RDF_FILE;
142        if (!file_exists($rdfPath)) {
143            throw new AssemblyImportFailedException("Delivery rdf file {$rdfPath} does not exist");
144        }
145
146        return new FileIterator($rdfPath, 1);
147    }
148
149    /**
150     * @param core_kernel_classes_Class $deliveryClass
151     * @param string $deliveryUri
152     * @param string $tmpImportFolder
153     *
154     * @return core_kernel_classes_Resource
155     * @throws AssemblyImportFailedException
156     */
157    protected function importDeliveryResource(core_kernel_classes_Class $deliveryClass, $deliveryUri, $tmpImportFolder)
158    {
159        $manifest       = $this->getDeliveryManifest($tmpImportFolder);
160        $label          = $manifest['label'];
161        $dirs           = $manifest['dir'];
162        $serviceCall    = \tao_models_classes_service_ServiceCall::fromString(base64_decode($manifest['runtime']));
163
164        $properties = $this->getAdditionalProperties($this->getRdfResourceIterator($tmpImportFolder));
165        $properties = array_merge($properties, [
166            OntologyRdfs::RDFS_LABEL                          => $label,
167            DeliveryAssemblyService::PROPERTY_DELIVERY_DIRECTORY => array_keys($dirs),
168            DeliveryAssemblyService::PROPERTY_DELIVERY_TIME      => time(),
169            DeliveryAssemblyService::PROPERTY_DELIVERY_RUNTIME   => $serviceCall->toOntology(),
170        ]);
171
172        $delivery = $this->getResource($deliveryUri);
173        if ($delivery->exists()) {
174            throw new AssemblyImportFailedException("Delivery with this URI already exist: {$deliveryUri}");
175        }
176
177        $delivery->setType($deliveryClass);
178        $delivery->setPropertiesValues($properties);
179
180        return $delivery;
181    }
182
183    /**
184     * @param boolean   $useOriginalUri
185     * @param string    $tmpImportFolder
186     * @return string
187     *
188     * @throws AssemblyImportFailedException
189     */
190    private function getDeliveryUri($useOriginalUri, $tmpImportFolder)
191    {
192        if ($useOriginalUri === false) {
193            return common_Utils::getNewUri();
194        }
195
196        $deliveryUri = null;
197        foreach ($this->getRdfResourceIterator($tmpImportFolder) as $triple) {
198            if ($triple->predicate == OntologyRdf::RDF_TYPE && $triple->object == DeliveryAssemblyService::CLASS_URI) {
199                $deliveryUri = $triple->subject;
200                break;
201            }
202        }
203
204        if ($deliveryUri === null) {
205            throw new AssemblyImportFailedException('Cannot find original delivery uri in delivery rdf file.');
206        }
207
208        return $deliveryUri;
209    }
210
211    /**
212     * @param $tmpImportFolder
213     * @throws \common_Exception
214     */
215    protected function importDeliveryFiles($tmpImportFolder)
216    {
217        $manifest = $this->getDeliveryManifest($tmpImportFolder);
218        $dirs     = $manifest['dir'];
219        foreach ($dirs as $id => $relPath) {
220            \tao_models_classes_service_FileStorage::singleton()->import($id, $tmpImportFolder . $relPath);
221        }
222    }
223}