Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.00% covered (success)
96.00%
72 / 75
88.89% covered (warning)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
CreateService
96.00% covered (success)
96.00%
72 / 75
88.89% covered (warning)
88.89%
8 / 9
14
0.00% covered (danger)
0.00%
0 / 1
 create
100.00% covered (success)
100.00%
35 / 35
100.00% covered (success)
100.00%
1 / 1
1
 getSharedStimulusName
40.00% covered (danger)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 getTempFileName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOntology
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUploadService
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSharedStimulusImporter
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTemplateFilePath
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultTemplateContent
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 saveTemporaryFile
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
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) 2020 (original work) Open Assessment Technologies SA;
19 */
20
21declare(strict_types=1);
22
23namespace oat\taoMediaManager\model\sharedStimulus\service;
24
25use common_Exception;
26use common_exception_Error;
27use core_kernel_classes_Class;
28use ErrorException;
29use oat\generis\model\data\Ontology;
30use oat\oatbox\service\ConfigurableService;
31use oat\tao\model\upload\UploadService;
32use oat\taoMediaManager\model\MediaService;
33use oat\taoMediaManager\model\sharedStimulus\CreateCommand;
34use oat\taoMediaManager\model\sharedStimulus\SharedStimulus;
35use oat\taoMediaManager\model\SharedStimulusImporter;
36use tao_models_classes_FileNotFoundException;
37
38class CreateService extends ConfigurableService
39{
40    public const DEFAULT_NAME = 'passage NEW';
41    public const OPTION_TEMP_UPLOAD_PATH = 'temp_upload_path';
42    public const OPTION_TEMPLATE_PATH = 'template_path';
43
44    /**
45     * @throws common_Exception
46     * @throws common_exception_Error
47     * @throws tao_models_classes_FileNotFoundException
48     * @throws ErrorException
49     */
50    public function create(CreateCommand $command): SharedStimulus
51    {
52        $defaultContent = $this->getDefaultTemplateContent();
53        $fileName = $this->getTempFileName();
54        $filePath = $this->saveTemporaryFile($fileName, $defaultContent);
55
56        $uploadService = $this->getUploadService();
57
58        $uploadResponse = $uploadService
59            ->uploadFile(
60                [
61                    'name' => $fileName,
62                    'tmp_name' => $filePath
63                ],
64                DIRECTORY_SEPARATOR
65            );
66
67        $kernelClass = $this->getOntology()->getClass($command->getClassId());
68
69        $sharedStimulusName = $this->getSharedStimulusName($command, $kernelClass);
70
71        $importResponse = $this->getSharedStimulusImporter()
72            ->import(
73                $kernelClass,
74                [
75                    'lang' => $command->getLanguageId(),
76                    'source' => [
77                        'name' => $sharedStimulusName,
78                        'type' => MediaService::SHARED_STIMULUS_MIME_TYPE,
79                    ],
80                    'uploaded_file' => DIRECTORY_SEPARATOR
81                        . $uploadService->getUserDirectoryHash()
82                        . DIRECTORY_SEPARATOR
83                        . $uploadResponse['uploaded_file']
84                ]
85            );
86
87        return new SharedStimulus(
88            current($importResponse->getChildren())->getData()['uriResource'],
89            $sharedStimulusName,
90            $command->getLanguageId(),
91            $defaultContent
92        );
93    }
94
95    private function getSharedStimulusName(CreateCommand $command, core_kernel_classes_Class $kernelClass): string
96    {
97        if ($command->getName()) {
98            return $command->getName();
99        }
100
101        $totalInstances = count($kernelClass->getInstances());
102
103        $name = $totalInstances === 0 ? self::DEFAULT_NAME : (self::DEFAULT_NAME . ' ' . $totalInstances);
104        return $name . '.xml';
105    }
106
107    private function getTempFileName(): string
108    {
109        return 'shared_stimulus_' . uniqid() . '.xml';
110    }
111
112    private function getOntology(): Ontology
113    {
114        return $this->getServiceLocator()->get(Ontology::SERVICE_ID);
115    }
116
117    private function getUploadService(): UploadService
118    {
119        return $this->getServiceLocator()->get(UploadService::SERVICE_ID);
120    }
121
122    private function getSharedStimulusImporter(): SharedStimulusImporter
123    {
124        return $this->getServiceLocator()->get(SharedStimulusImporter::class);
125    }
126
127    private function getTemplateFilePath(): string
128    {
129        return $this->getOption(self::OPTION_TEMPLATE_PATH) ?? __DIR__
130            . DIRECTORY_SEPARATOR
131            . '..'
132            . DIRECTORY_SEPARATOR
133            . '..'
134            . DIRECTORY_SEPARATOR
135            . '..'
136            . DIRECTORY_SEPARATOR
137            . 'views'
138            . DIRECTORY_SEPARATOR
139            . 'templates'
140            . DIRECTORY_SEPARATOR
141            . 'sharedStimulus'
142            . DIRECTORY_SEPARATOR
143            . 'empty_template.xml';
144    }
145
146    /**
147     * @throws tao_models_classes_FileNotFoundException
148     */
149    private function getDefaultTemplateContent(): string
150    {
151        $templatePath = $this->getTemplateFilePath();
152
153        if (!is_readable($templatePath)) {
154            throw new tao_models_classes_FileNotFoundException(
155                sprintf('Shared Stimulus template not found: %s', $templatePath)
156            );
157        }
158
159        return file_get_contents($templatePath);
160    }
161
162    /**
163     * @throws ErrorException
164     */
165    private function saveTemporaryFile(string $fileName, string $templateContent): string
166    {
167        $fileDirectory = $this->getOption(self::OPTION_TEMP_UPLOAD_PATH) ?? sys_get_temp_dir();
168
169        $filePath = $fileDirectory . DIRECTORY_SEPARATOR . $fileName;
170
171        if (!is_writable($fileDirectory) || file_put_contents($filePath, $templateContent) === false) {
172            throw new ErrorException(
173                sprintf(
174                    'Could not save Shared Stimulus to temporary path %s',
175                    $filePath
176                )
177            );
178        }
179
180        return $filePath;
181    }
182}