Passed
Push — 1.11.x ( 08587c...c85e98 )
by Yannick
10:54
created

H5pPackageTools   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 311
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 24
eloc 146
c 1
b 0
f 0
dl 0
loc 311
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A deleteH5pPackage() 0 18 3
A checkPackageIntegrity() 0 33 3
B storeH5pPackage() 0 67 5
A getCoreAssets() 0 27 5
A getCoreSettings() 0 33 2
A getJson() 0 17 3
A h5pDependenciesToLibraryList() 0 12 2
A getContentSettings() 0 31 1
1
<?php
2
3
// For licensing terms, see /license.txt
4
5
namespace Chamilo\PluginBundle\H5pImport\H5pImporter;
6
7
use Chamilo\CoreBundle\Entity\Course;
8
use Chamilo\CoreBundle\Entity\Session;
9
use Chamilo\PluginBundle\Entity\H5pImport\H5pImport;
10
use Chamilo\PluginBundle\Entity\H5pImport\H5pImportLibrary;
11
use Database;
12
use H5PCore;
13
use Symfony\Component\Filesystem\Filesystem;
14
15
class H5pPackageTools
16
{
17
    /**
18
     * Help read JSON from the archive.
19
     *
20
     * @return mixed JSON content if valid or FALSE for invalid
21
     */
22
    public static function getJson(string $file, bool $assoc = false)
23
    {
24
        $fs = new Filesystem();
25
        $json = false;
26
27
        if ($fs->exists($file)) {
28
            $contents = file_get_contents($file);
29
30
            // Decode the data
31
            $json = json_decode($contents, $assoc);
32
            if (null === $json) {
33
                // JSON cannot be decoded or the recursion limit has been reached.
34
                return false;
35
            }
36
        }
37
38
        return $json;
39
    }
40
41
    /**
42
     * Checks the integrity of an H5P package by verifying the existence of libraries
43
     * and moves them to the "libraries" directory.
44
     *
45
     * @param object $h5pJson      the H5P JSON object
46
     * @param string $extractedDir the path to the extracted directory
47
     *
48
     * @return bool true if the package integrity is valid, false otherwise
49
     */
50
    public static function checkPackageIntegrity(object $h5pJson, string $extractedDir): bool
51
    {
52
        $filesystem = new Filesystem();
53
        $h5pDir = dirname($extractedDir, 2);
54
        $sharedLibrariesDir = $h5pDir.'/libraries';
55
56
        // Move 'content' directory one level back (H5P specification)
57
        $filesystem->mirror($extractedDir.'/content', $extractedDir, null, ['override' => true]);
58
        $filesystem->remove($extractedDir.'/content');
59
        // Get the list of preloaded dependencies
60
        $preloadedDependencies = $h5pJson->preloadedDependencies;
61
62
        // Check the existence of each library in the extracted directory
63
        foreach ($preloadedDependencies as $dependency) {
64
            $libraryName = $dependency->machineName;
65
            $majorVersion = $dependency->majorVersion;
66
            $minorVersion = $dependency->minorVersion;
67
68
            $libraryFolderName = api_replace_dangerous_char($libraryName.'-'.$majorVersion.'.'.$minorVersion);
69
            $libraryPath = $extractedDir.'/'.$libraryFolderName;
70
71
            // Check if the library folder exists
72
            if (!$filesystem->exists($libraryPath)) {
73
                return false;
74
            }
75
76
            // Move the entire folder to the "libraries" directory
77
            $targetPath = $sharedLibrariesDir.'/'.$libraryFolderName;
78
79
            $filesystem->rename($libraryPath, $targetPath, true);
80
        }
81
82
        return true;
83
    }
84
85
    /**
86
     * Stores the H5P package information in the database.
87
     *
88
     * @param string       $packagePath the path to the H5P package file
89
     * @param object       $h5pJson     the parsed H5P JSON object
90
     * @param Course       $course      the course entity related to the package
91
     * @param null|Session $session     the session entity related to the package
92
     * @param null|array   $values      the advance options in upload form
93
     */
94
    public static function storeH5pPackage(
95
        string $packagePath,
96
        object $h5pJson,
97
        Course $course,
98
        Session $session = null,
99
        array $values = null
100
    ) {
101
        $entityManager = \Database::getManager();
102
        // Go back 2 directories
103
        $h5pDir = dirname($packagePath, 2);
104
        $sharedLibrariesDir = $h5pDir.'/libraries';
105
106
        $mainLibraryName = $h5pJson->mainLibrary;
107
        $relativePath = api_get_path(REL_COURSE_PATH).$course->getDirectory().'/h5p/';
108
109
        $h5pImport = new H5pImport();
110
        $h5pImport->setName($h5pJson->title);
111
        $h5pImport->setPath($packagePath);
112
        if ($values) {
113
            $h5pImport->setDescription($values['description']);
114
        }
115
        $h5pImport->setRelativePath($relativePath);
116
        $h5pImport->setCourse($course);
117
        $h5pImport->setSession($session);
118
        $entityManager->persist($h5pImport);
119
120
        $libraries = $h5pJson->preloadedDependencies;
121
122
        foreach ($libraries as $libraryData) {
123
            $library = $entityManager
124
                ->getRepository(H5pImportLibrary::class)
125
                ->findOneBy(
126
                    [
127
                        'machineName' => $libraryData->machineName,
128
                        'majorVersion' => $libraryData->majorVersion,
129
                        'minorVersion' => $libraryData->minorVersion,
130
                        'course' => $course,
131
                    ]
132
                )
133
            ;
134
135
            if (null === $library) {
136
                $auxFullName = $libraryData->machineName.'-'.$libraryData->majorVersion.'.'.$libraryData->minorVersion;
137
                $libraryOwnJson = self::getJson($sharedLibrariesDir.'/'.$auxFullName.'/library.json');
138
139
                $library = new H5pImportLibrary();
140
                $library->setMachineName($libraryData->machineName);
141
                $library->setTitle($libraryOwnJson->title);
142
                $library->setMajorVersion($libraryData->majorVersion);
143
                $library->setMinorVersion($libraryData->minorVersion);
144
                $library->setPatchVersion($libraryOwnJson->patchVersion);
145
                $library->setRunnable($libraryOwnJson->runnable);
146
                $library->setEmbedTypes($libraryOwnJson->embedTypes);
147
                $library->setPreloadedJs($libraryOwnJson->preloadedJs);
148
                $library->setPreloadedCss($libraryOwnJson->preloadedCss);
149
                $library->setLibraryPath($sharedLibrariesDir.'/'.$auxFullName);
150
                $library->setCourse($course);
151
                $entityManager->persist($library);
152
                $entityManager->flush();
153
            }
154
155
            $h5pImport->addLibraries($library);
156
            if ($mainLibraryName === $libraryData->machineName) {
157
                $h5pImport->setMainLibrary($library);
158
            }
159
            $entityManager->persist($h5pImport);
160
            $entityManager->flush();
161
        }
162
    }
163
164
    /**
165
     * Deletes an H5P package from the database and the disk.
166
     *
167
     * @param H5pImport $h5pImport the H5P import entity representing the package to delete
168
     *
169
     * @return bool true if the package was successfully deleted, false otherwise
170
     */
171
    public static function deleteH5pPackage(H5pImport $h5pImport): bool
172
    {
173
        $packagePath = $h5pImport->getPath();
174
        $entityManager = \Database::getManager();
175
        $entityManager->remove($h5pImport);
176
        $entityManager->flush();
177
178
        $filesystem = new Filesystem();
179
180
        if ($filesystem->exists($packagePath)) {
181
            try {
182
                $filesystem->remove($packagePath);
183
            } catch (\Exception $e) {
184
                return false;
185
            }
186
        }
187
188
        return true;
189
    }
190
191
    /**
192
     * Get core settings for H5P content.
193
     *
194
     * @param H5pImport $h5pImport the H5pImport object
195
     * @param \H5PCore  $h5pCore   the H5PCore object
196
     *
197
     * @return array the core settings for H5P content
198
     */
199
    public static function getCoreSettings(H5pImport $h5pImport, \H5PCore $h5pCore): array
200
    {
201
        $originIsLearnpath = 'learnpath' === api_get_origin();
202
203
        $settings = [
204
            'baseUrl' => api_get_path(WEB_PATH),
205
            'url' => $h5pImport->getRelativePath(),
206
            'postUserStatistics' => true,
207
            'ajax' => [
208
                'setFinished' => api_get_path(WEB_PLUGIN_PATH).'h5pimport/src/ajax.php?action=set_finished&h5pId='.$h5pImport->getIid().'&learnpath='.$originIsLearnpath.'&token='.\H5PCore::createToken('result'),
209
                'contentUserData' => api_get_path(WEB_PLUGIN_PATH).'h5pimport/src/ajax.php?action=content_user_data&h5pId='.$h5pImport->getIid().'&token='.\H5PCore::createToken('content'),
210
            ],
211
            'saveFreq' => false,
212
            'l10n' => [
213
                'H5P' => $h5pCore->getLocalization(),
214
            ],
215
            //            'hubIsEnabled' => variable_get('h5p_hub_is_enabled', TRUE) ? TRUE : FALSE,
216
            'crossorigin' => false,
217
            //            'crossoriginCacheBuster' => variable_get('h5p_crossorigin_cache_buster', NULL),
218
            //            'libraryConfig' => $core->h5pF->getLibraryConfig(),
219
            'pluginCacheBuster' => '?0',
220
            'libraryUrl' => $h5pImport->getMainLibrary()->getLibraryPath().'/js',
221
        ];
222
223
        $loggedUser = api_get_user_info();
224
        if ($loggedUser) {
225
            $settings['user'] = [
226
                'name' => $loggedUser['complete_name'],
227
                'mail' => $loggedUser['email'],
228
            ];
229
        }
230
231
        return $settings;
232
    }
233
234
    /**
235
     * Get the core assets.
236
     *
237
     * @return array[]|bool an array containing CSS and JS assets or false if some core assets missing
238
     */
239
    public static function getCoreAssets()
240
    {
241
        $assets = [
242
            'css' => [],
243
            'js' => [],
244
        ];
245
246
        // Add CSS assets
247
        foreach (\H5PCore::$styles as $style) {
248
            $auxAssetPath = 'vendor/h5p/h5p-core/'.$style;
249
            $assets['css'][] = api_get_path(WEB_PATH).$auxAssetPath;
250
            if (!file_exists(api_get_path(SYS_PATH).$auxAssetPath)) {
251
                return false;
252
            }
253
        }
254
255
        // Add JS assets
256
        foreach (\H5PCore::$scripts as $script) {
257
            $auxAssetPath = 'vendor/h5p/h5p-core/'.$script;
258
            $auxUrl = api_get_path(WEB_PATH).$auxAssetPath;
259
            $assets['js'][] = $auxUrl;
260
            if (!file_exists(api_get_path(SYS_PATH).$auxAssetPath)) {
261
                return false;
262
            }
263
        }
264
265
        return $assets;
266
    }
267
268
    /**
269
     * Return the content body for the H5PIntegration javascript object.
270
     *
271
     * @param mixed $h5pNode
272
     */
273
    public static function getContentSettings($h5pNode, \H5PCore $h5pCore): array
274
    {
275
        $filtered = $h5pCore->filterParameters($h5pNode);
276
        $contentUserData = [
277
            0 => [
278
                'state' => '{}',
279
            ],
280
        ];
281
282
        // ToDo Use $h5pCore->getDisplayOptionsForView() function
283
        $displayOptions = [
284
            'frame' => api_get_course_plugin_setting('h5pimport', 'frame'),
285
            'embed' => api_get_course_plugin_setting('h5pimport', 'embed'),
286
            'copyright' => api_get_course_plugin_setting('h5pimport', 'copyright'),
287
            'icon' => api_get_course_plugin_setting('h5pimport', 'icon'),
288
        ];
289
290
        return [
291
            'library' => \H5PCore::libraryToString($h5pNode['library']),
292
            'jsonContent' => $h5pNode['params'],
293
            'fullScreen' => $h5pNode['library']['fullscreen'],
294
            'exportUrl' => '',
295
            'language' => 'en',
296
            'filtered' => $filtered,
297
            'embedCode' => '<iframe src="'.api_get_course_url().'h5p/embed/'.$h5pNode['mainId'].'" width=":w" height=":h" frameborder="0" allowfullscreen="allowfullscreen" allow="geolocation *; microphone *; camera *; midi *; encrypted-media *" title="'.$h5pNode['title'].'"></iframe>',
298
            'resizeCode' => '',
299
            'mainId' => $h5pNode['mainId'],
300
            'url' => $h5pNode['url'],
301
            'contentUserData' => $contentUserData,
302
            'displayOptions' => $displayOptions,
303
            'metadata' => $h5pNode['metadata'],
304
        ];
305
    }
306
307
    /**
308
     * Convert H5P dependencies to a library list.
309
     *
310
     * @param array $dependencies the H5P dependencies
311
     *
312
     * @return array the library list with machine names as keys and version information as values
313
     */
314
    public static function h5pDependenciesToLibraryList(array $dependencies): array
315
    {
316
        $libraryList = [];
317
318
        foreach ($dependencies as $dependency) {
319
            $libraryList[$dependency['machineName']] = [
320
                'majorVersion' => $dependency['majorVersion'],
321
                'minorVersion' => $dependency['minorVersion'],
322
            ];
323
        }
324
325
        return $libraryList;
326
    }
327
}
328