CourseRestorer   F
last analyzed

Complexity

Total Complexity 559

Size/Duplication

Total Lines 4044
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 559
eloc 2548
dl 0
loc 4044
rs 0.8
c 0
b 0
f 0

42 Methods

Rating   Name   Duplication   Size   Complexity  
B restore_links() 0 50 5
F restore_surveys() 0 176 22
A restore_topic() 0 53 4
A checkGroupId() 0 3 1
B restore_scorm_documents() 0 62 9
F restore_learnpaths() 0 445 71
A checkUserId() 0 18 5
F restore_forums() 0 79 18
B restore_assets() 0 21 9
D restore_gradebook() 0 100 26
A DBUTF8() 0 7 2
A set_add_text_in_items() 0 3 1
C restore_announcements() 0 107 16
A set_file_option() 0 3 1
B get_new_id() 0 32 11
A __construct() 0 15 3
B restore_glossary() 0 49 7
A is_survey_code_available() 0 12 2
A restore_post() 0 42 2
B restore_wiki() 0 76 6
B restore_link_category() 0 61 6
B restore_thematic() 0 94 8
F restore_quizzes() 0 127 27
B restore_learnpath_category() 0 44 10
F restore() 0 117 24
F restore_quiz_question() 0 367 42
A DBUTF8escapestring() 0 7 2
B allow_create_all_directory() 0 25 9
B restore_course_descriptions() 0 39 9
A restore_course_settings() 0 12 1
B restore_forum_category() 0 50 9
A restore_xapi_tool() 0 27 5
B restore_survey_question() 0 73 10
F restore_documents() 0 745 106
C restore_works() 0 93 13
B restore_attendance() 0 54 5
C restore_test_category() 0 80 16
A set_tool_copy_settings() 0 3 1
A fixEditorHtmlContent() 0 15 3
A DBUTF8_array() 0 10 3
F restore_events() 0 144 22
B restore_tool_intro() 0 37 7

How to fix   Complexity   

Complex Class

Complex classes like CourseRestorer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CourseRestorer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
namespace Chamilo\CourseBundle\Component\CourseCopy;
6
7
use Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup;
8
use Chamilo\CourseBundle\Component\CourseCopy\Resources\LearnPathCategory;
9
use Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion;
10
use Chamilo\CourseBundle\Entity\CLpCategory;
11
use Chamilo\CourseBundle\Entity\CQuizAnswer;
12
use CourseManager;
13
use Database;
14
use DocumentManager;
15
use Question;
16
use stdClass;
17
use SurveyManager;
18
use TestCategory;
19
20
/**
21
 * Class CourseRestorer.
22
 *
23
 * Class to restore items from a course object to a Chamilo-course
24
 *
25
 * @author Bart Mollet <[email protected]>
26
 * @author Julio Montoya <[email protected]> Several fixes/improvements
27
 */
28
class CourseRestorer
29
{
30
    /**
31
     * The course-object.
32
     */
33
    public $course;
34
    public $destination_course_info;
35
36
    /**
37
     * What to do with files with same name (FILE_SKIP, FILE_RENAME or
38
     * FILE_OVERWRITE).
39
     */
40
    public $file_option;
41
    public $set_tools_invisible_by_default;
42
    public $skip_content;
43
    // Restoration is done in the order listed for $tools_to_restore
44
    public $tools_to_restore = [
45
        'documents', // first restore documents
46
        'announcements',
47
        'attendance',
48
        'course_descriptions',
49
        'events',
50
        'forum_category',
51
        'forums',
52
       // 'forum_topics',
53
        'glossary',
54
        'quizzes',
55
        'test_category',
56
        'links',
57
        'works',
58
        'xapi_tool',
59
        'h5p_tool',
60
        'surveys',
61
        'learnpath_category',
62
        'learnpaths',
63
        //'scorm_documents', ??
64
        'tool_intro',
65
        'thematic',
66
        'wiki',
67
        'gradebook',
68
        'assets',
69
    ];
70
71
    /** Setting per tool */
72
    public $tool_copy_settings = [];
73
    public $isXapiEnabled = false;
74
    public $isH5pEnabled = false;
75
76
    /**
77
     * If true adds the text "copy" in the title of an item (only for LPs right now).
78
     */
79
    public $add_text_in_items = false;
80
    public $destination_course_id;
81
82
    public $copySessionContent = false;
83
84
    /**
85
     * CourseRestorer constructor.
86
     *
87
     * @param Course $course
88
     */
89
    public function __construct($course)
90
    {
91
        $this->course = $course;
92
        $courseInfo = api_get_course_info($this->course->code);
93
        $this->course_origin_id = null;
94
        if (!empty($courseInfo)) {
95
            $this->course_origin_id = $courseInfo['real_id'];
96
        }
97
        $this->file_option = FILE_RENAME;
98
        $this->set_tools_invisible_by_default = false;
99
        $this->skip_content = [];
100
101
        $forceImport = api_get_configuration_value('allow_import_scorm_package_in_course_builder');
102
        if ($forceImport) {
103
            $this->tools_to_restore[] = 'scorm_documents';
104
        }
105
    }
106
107
    /**
108
     * Set the file-option.
109
     *
110
     * @param int $option (optional) What to do with files with same name
111
     *                    FILE_SKIP, FILE_RENAME or FILE_OVERWRITE
112
     */
113
    public function set_file_option($option = FILE_OVERWRITE)
114
    {
115
        $this->file_option = $option;
116
    }
117
118
    /**
119
     * @param bool $status
120
     */
121
    public function set_add_text_in_items($status)
122
    {
123
        $this->add_text_in_items = $status;
124
    }
125
126
    /**
127
     * @param array $array
128
     */
129
    public function set_tool_copy_settings($array)
130
    {
131
        $this->tool_copy_settings = $array;
132
    }
133
134
    /**
135
     * Restore a course.
136
     *
137
     * @param string $destination_course_code code of the Chamilo-course in
138
     * @param int    $session_id
139
     * @param bool   $update_course_settings  Course settings are going to be restore?
140
     * @param bool   $respect_base_content
141
     *
142
     * @return false|null
143
     */
144
    public function restore(
145
        $destination_course_code = '',
146
        $session_id = 0,
147
        $update_course_settings = false,
148
        $respect_base_content = false
149
    ) {
150
        if ($destination_course_code == '') {
151
            $course_info = api_get_course_info();
152
            $this->destination_course_info = $course_info;
153
            $this->course->destination_path = $course_info['path'];
154
        } else {
155
            $course_info = api_get_course_info($destination_course_code);
156
            $this->destination_course_info = $course_info;
157
            $this->course->destination_path = $course_info['path'];
158
        }
159
        $this->destination_course_id = $course_info['real_id'];
160
        // Getting first teacher (for the forums)
161
        $teacher_list = CourseManager::get_teacher_list_from_course_code($course_info['code']);
162
        $this->first_teacher_id = api_get_user_id();
163
        $this->isXapiEnabled = \XApiPlugin::create()->isEnabled();
164
        $this->isH5pEnabled = false; //\H5pImportPlugin::create()->isEnabled();
165
166
        if (!empty($teacher_list)) {
167
            foreach ($teacher_list as $teacher) {
168
                $this->first_teacher_id = $teacher['user_id'];
169
                break;
170
            }
171
        }
172
173
        if (empty($this->course)) {
174
            return false;
175
        }
176
177
        // Source platform encoding - reading/detection
178
        // The correspondent data field has been added as of version 1.8.6.1
179
        if (empty($this->course->encoding)) {
180
            // The archive has been created by a system which is prior to 1.8.6.1 version.
181
            // In this case we have to detect the encoding.
182
            $sample_text = $this->course->get_sample_text()."\n";
183
            // Let us exclude ASCII lines, probably they are English texts.
184
            $sample_text = explode("\n", $sample_text);
185
            foreach ($sample_text as $key => &$line) {
186
                if (api_is_valid_ascii($line)) {
187
                    unset($sample_text[$key]);
188
                }
189
            }
190
            $sample_text = implode("\n", $sample_text);
191
            $this->course->encoding = api_detect_encoding(
192
                $sample_text,
193
                $course_info['language']
194
            );
195
        }
196
197
        // Encoding conversion of the course, if it is needed.
198
        $this->course->to_system_encoding();
199
200
        foreach ($this->tools_to_restore as $tool) {
201
            if ('xapi_tool' == $tool && !$this->isXapiEnabled) {
202
                continue;
203
            }
204
            if ('h5p_tool' == $tool && !$this->isH5pEnabled) {
205
                continue;
206
            }
207
            $function_build = 'restore_'.$tool;
208
            $this->$function_build(
209
                $session_id,
210
                $respect_base_content,
211
                $destination_course_code
212
            );
213
        }
214
215
        if ($update_course_settings) {
216
            $this->restore_course_settings($destination_course_code);
217
        }
218
219
        // Restore the item properties
220
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
221
        foreach ($this->course->resources as $type => $resources) {
222
            if (is_array($resources)) {
223
                foreach ($resources as $id => $resource) {
224
                    if (isset($resource->item_properties)) {
225
                        foreach ($resource->item_properties as $property) {
226
                            // First check if there isn't already a record for this resource
227
                            $sql = "SELECT * FROM $table
228
                                    WHERE
229
                                        c_id = ".$this->destination_course_id." AND
230
                                        tool = '".$property['tool']."' AND
231
                                        ref = '".$resource->destination_id."'";
232
233
                            $params = [];
234
                            if (!empty($session_id)) {
235
                                $params['session_id'] = (int) $session_id;
236
                            }
237
238
                            $res = Database::query($sql);
239
                            if (Database::num_rows($res) == 0) {
240
                                /* The to_group_id and to_user_id are set to default
241
                                values as users/groups possibly not exist in
242
                                the target course*/
243
244
                                $params['c_id'] = $this->destination_course_id;
245
                                $params['tool'] = self::DBUTF8($property['tool']);
246
                                $params['insert_user_id'] = $this->checkUserId($property['insert_user_id']) ?: null;
247
                                $params['insert_date'] = self::DBUTF8($property['insert_date']);
248
                                $params['lastedit_date'] = self::DBUTF8($property['lastedit_date']);
249
                                $params['ref'] = $resource->destination_id;
250
                                $params['lastedit_type'] = self::DBUTF8($property['lastedit_type']);
251
                                $params['lastedit_user_id'] = $this->checkUserId($property['lastedit_user_id']);
252
                                $params['visibility'] = self::DBUTF8($property['visibility']);
253
                                $params['start_visible'] = self::DBUTF8($property['start_visible']);
254
                                $params['end_visible'] = self::DBUTF8($property['end_visible']);
255
                                $params['to_user_id'] = $this->checkUserId($property['to_user_id']) ?: null;
256
257
                                $id = Database::insert($table, $params);
258
                                if ($id) {
259
                                    $sql = "UPDATE $table SET id = iid WHERE iid = $id";
260
                                    Database::query($sql);
261
                                }
262
                            }
263
                        }
264
                    }
265
                }
266
            }
267
        }
268
    }
269
270
    /**
271
     * Restore only harmless course settings:
272
     * course_language, visibility, department_name,department_url,
273
     * subscribe, unsubscribe ,category_code.
274
     *
275
     * @param string $destination_course_code
276
     */
277
    public function restore_course_settings($destination_course_code)
278
    {
279
        $origin_course_info = api_get_course_info($destination_course_code);
280
        $course_info = $this->course->info;
281
        $params['course_language'] = $course_info['language'];
282
        $params['visibility'] = $course_info['visibility'];
283
        $params['department_name'] = $course_info['department_name'];
284
        $params['department_url'] = $course_info['department_url'];
285
        $params['category_code'] = $course_info['categoryCode'];
286
        $params['subscribe'] = $course_info['subscribe_allowed'];
287
        $params['unsubscribe'] = $course_info['unsubscribe'];
288
        CourseManager::update_attributes($origin_course_info['real_id'], $params);
289
    }
290
291
    /**
292
     * Restore documents.
293
     *
294
     * @param int    $session_id
295
     * @param bool   $respect_base_content
296
     * @param string $destination_course_code
297
     */
298
    public function restore_documents(
299
        $session_id = 0,
300
        $respect_base_content = false,
301
        $destination_course_code = ''
302
    ) {
303
        $course_info = api_get_course_info($destination_course_code);
304
305
        if (!$this->course->has_resources(RESOURCE_DOCUMENT)) {
306
            return;
307
        }
308
309
        $webEditorCss = api_get_path(WEB_CSS_PATH).'editor.css';
310
        $table = Database::get_course_table(TABLE_DOCUMENT);
311
        $resources = $this->course->resources;
312
        $path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/';
313
        $originalFolderNameList = [];
314
        foreach ($resources[RESOURCE_DOCUMENT] as $id => $document) {
315
            $my_session_id = empty($document->item_properties[0]['session_id']) ? 0 : $session_id;
316
317
            if (false === $respect_base_content && $session_id) {
318
                if (empty($my_session_id)) {
319
                    $my_session_id = $session_id;
320
                }
321
            }
322
323
            if ($document->file_type == FOLDER) {
324
                $visibility = isset($document->item_properties[0]['visibility']) ? $document->item_properties[0]['visibility'] : '';
325
                $new = substr($document->path, 8);
326
                $folderList = explode('/', $new);
327
                $tempFolder = '';
328
329
                // Check if the parent path exists.
330
                foreach ($folderList as $folder) {
331
                    $folderToCreate = $tempFolder.$folder;
332
                    $sysFolderPath = $path.'document'.$folderToCreate;
333
                    $tempFolder .= $folder.'/';
334
335
                    if (empty($folderToCreate)) {
336
                        continue;
337
                    }
338
                    $title = $document->title;
339
                    $originalFolderNameList[basename($document->path)] = $document->title;
340
                    if (empty($title)) {
341
                        $title = basename($sysFolderPath);
342
                    }
343
                    //error_log($title); error_log($sysFolderPath);
344
                    // File doesn't exist in file system.
345
                    if (!is_dir($sysFolderPath)) {
346
                        /*error_log('Creating directory');
347
                        error_log("Creating $folderToCreate");*/
348
                        // Creating directory
349
                        create_unexisting_directory(
350
                            $course_info,
351
                            api_get_user_id(),
352
                            $my_session_id,
353
                            0,
354
                            0,
355
                            $path.'document',
356
                            $folderToCreate,
357
                            $title,
358
                            $visibility
359
                        );
360
                        continue;
361
                    }
362
363
                    // File exist in file system.
364
                    $documentData = DocumentManager::get_document_id(
365
                        $course_info,
366
                        $folderToCreate,
367
                        $session_id
368
                    );
369
370
                    //error_log("session_id $session_id");
371
                    if (empty($documentData)) {
372
                        if (!is_dir($sysFolderPath)) {
373
                            //error_log('$documentData empty');
374
                            //error_log('$folderToCreate '.$folderToCreate);
375
                            /* This means the folder exists in the
376
                            filesystem but not in the DB, trying to fix it */
377
                            add_document(
378
                                $course_info,
379
                                $folderToCreate,
380
                                'folder',
381
                                0,
382
                                $title,
383
                                null,
384
                                null,
385
                                false,
386
                                null,
387
                                $session_id,
388
                                0,
389
                                false
390
                            );
391
                        }
392
                    } else {
393
                        $insertUserId = isset($document->item_properties[0]['insert_user_id']) ? $document->item_properties[0]['insert_user_id'] : api_get_user_id();
394
                        $insertUserId = $this->checkUserId($insertUserId);
395
                        // Check if user exists in platform
396
                        $toUserId = isset($document->item_properties[0]['to_user_id']) ? $document->item_properties[0]['to_user_id'] : null;
397
                        $toUserId = $this->checkUserId($toUserId, true);
398
                        $groupId = isset($document->item_properties[0]['to_group_id']) ? $document->item_properties[0]['to_group_id'] : null;
399
                        $groupInfo = $this->checkGroupId($groupId);
400
                        //error_log(" if folder exists then just refresh it");
401
                        // if folder exists then just refresh it
402
                        api_item_property_update(
403
                            $course_info,
404
                            TOOL_DOCUMENT,
405
                            $documentData,
406
                            'FolderUpdated',
407
                            $insertUserId,
408
                            $groupInfo,
409
                            $toUserId,
410
                            null,
411
                            null,
412
                            $my_session_id
413
                        );
414
                    }
415
                }
416
            } elseif ($document->file_type == DOCUMENT) {
417
                // Checking if folder exists in the database otherwise we created it
418
                $dir_to_create = dirname($document->path);
419
                $originalFolderNameList[basename($document->path)] = $document->title;
420
                if (!empty($dir_to_create) && $dir_to_create != 'document' && $dir_to_create != '/') {
421
                    // it creates folder images if it doesn't exist , used for hotspot pictures.
422
                    if (false !== strpos($document->path, '/images/') && !is_dir(dirname($path.$document->path))) {
423
                        $perm = api_get_permissions_for_new_directories();
424
                        mkdir(dirname($path.$document->path), $perm, true);
425
                    }
426
                    if (is_dir($path.dirname($document->path))) {
427
                        $sql = "SELECT id FROM $table
428
                                WHERE
429
                                    c_id = ".$this->destination_course_id." AND
430
                                    path = '/".self::DBUTF8escapestring(substr(dirname($document->path), 9))."'";
431
                        $res = Database::query($sql);
432
433
                        if (Database::num_rows($res) == 0) {
434
                            $new = '/'.substr(dirname($document->path), 9);
435
                            // It adds the folder name as title
436
                            $title = str_replace('/', '', $new);
437
438
                            // This code fixes the possibility for a file without a directory entry to be
439
                            $document_id = add_document(
440
                                $course_info,
441
                                $new,
442
                                'folder',
443
                                0,
444
                                $title,
445
                                null,
446
                                null,
447
                                false,
448
                                0,
449
                                0,
450
                                0,
451
                                false
452
                            );
453
454
                            $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
455
                            $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
456
                            $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
457
                            $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
458
                            $groupInfo = $this->checkGroupId($toGroupId);
459
                            $insertUserId = $this->checkUserId($insertUserId);
460
                            $toUserId = $this->checkUserId($toUserId, true);
461
462
                            api_item_property_update(
463
                                $course_info,
464
                                TOOL_DOCUMENT,
465
                                $document_id,
466
                                'FolderCreated',
467
                                $insertUserId,
468
                                $groupInfo,
469
                                $toUserId,
470
                                null,
471
                                null,
472
                                $my_session_id
473
                            );
474
                        }
475
                    }
476
                }
477
478
                //error_log(print_r($originalFolderNameList, 1));
479
                if (file_exists($path.$document->path)) {
480
                    switch ($this->file_option) {
481
                        case FILE_OVERWRITE:
482
                            $origin_path = $this->course->backup_path.'/'.$document->path;
483
                            if (file_exists($origin_path)) {
484
                                copy($origin_path, $path.$document->path);
485
                                $this->fixEditorHtmlContent($path.$document->path, $webEditorCss);
486
                                $sql = "SELECT id FROM $table
487
                                        WHERE
488
                                            c_id = ".$this->destination_course_id." AND
489
                                            path = '/".self::DBUTF8escapestring(substr($document->path, 9))."'";
490
491
                                $res = Database::query($sql);
492
                                $count = Database::num_rows($res);
493
494
                                if ($count == 0) {
495
                                    $params = [
496
                                        'path' => "/".self::DBUTF8(substr($document->path, 9)),
497
                                        'c_id' => $this->destination_course_id,
498
                                        'comment' => self::DBUTF8($document->comment),
499
                                        'title' => self::DBUTF8($document->title),
500
                                        'filetype' => self::DBUTF8($document->file_type),
501
                                        'size' => self::DBUTF8($document->size),
502
                                        'session_id' => $my_session_id,
503
                                        'readonly' => 0,
504
                                    ];
505
506
                                    $document_id = Database::insert($table, $params);
507
508
                                    if ($document_id) {
509
                                        $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
510
                                        Database::query($sql);
511
                                    }
512
                                    $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
513
514
                                    $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
515
                                    $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
516
                                    $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
517
                                    $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
518
519
                                    $insertUserId = $this->checkUserId($insertUserId);
520
                                    $toUserId = $this->checkUserId($toUserId, true);
521
                                    $groupInfo = $this->checkGroupId($toGroupId);
522
523
                                    api_item_property_update(
524
                                        $course_info,
525
                                        TOOL_DOCUMENT,
526
                                        $document_id,
527
                                        'DocumentAdded',
528
                                        $insertUserId,
529
                                        $groupInfo,
530
                                        $toUserId,
531
                                        null,
532
                                        null,
533
                                        $my_session_id
534
                                    );
535
                                } else {
536
                                    $obj = Database::fetch_object($res);
537
                                    $document_id = $obj->id;
538
                                    $params = [
539
                                        'path' => "/".self::DBUTF8(substr($document->path, 9)),
540
                                        'c_id' => $this->destination_course_id,
541
                                        'comment' => self::DBUTF8($document->comment),
542
                                        'title' => self::DBUTF8($document->title),
543
                                        'filetype' => self::DBUTF8($document->file_type),
544
                                        'size' => self::DBUTF8($document->size),
545
                                        'session_id' => $my_session_id,
546
                                    ];
547
548
                                    Database::update(
549
                                        $table,
550
                                        $params,
551
                                        [
552
                                            'c_id = ? AND path = ?' => [
553
                                                $this->destination_course_id,
554
                                                "/".self::DBUTF8escapestring(substr($document->path, 9)),
555
                                            ],
556
                                        ]
557
                                    );
558
559
                                    $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $obj->id;
560
561
                                    $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
562
                                    $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
563
                                    $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
564
                                    $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
565
566
                                    $insertUserId = $this->checkUserId($insertUserId);
567
                                    $toUserId = $this->checkUserId($toUserId, true);
568
                                    $groupInfo = $this->checkGroupId($toGroupId);
569
570
                                    api_item_property_update(
571
                                        $course_info,
572
                                        TOOL_DOCUMENT,
573
                                        $obj->id,
574
                                        'default',
575
                                        $insertUserId,
576
                                        $groupInfo,
577
                                        $toUserId,
578
                                        null,
579
                                        null,
580
                                        $my_session_id
581
                                    );
582
                                }
583
584
                                // Replace old course code with the new destination code
585
                                $file_info = pathinfo($path.$document->path);
586
587
                                if (isset($file_info['extension']) && in_array($file_info['extension'], ['html', 'htm'])) {
588
                                    $content = file_get_contents($path.$document->path);
589
                                    if (UTF8_CONVERT) {
590
                                        $content = utf8_encode($content);
591
                                    }
592
                                    $content = DocumentManager::replaceUrlWithNewCourseCode(
593
                                        $content,
594
                                        $this->course->code,
595
                                        $this->course->destination_path,
596
                                        $this->course->backup_path,
597
                                        $this->course->info['path']
598
                                    );
599
                                    file_put_contents($path.$document->path, $content);
600
                                }
601
602
                                $params = [
603
                                    'comment' => self::DBUTF8($document->comment),
604
                                    'title' => self::DBUTF8($document->title),
605
                                    'size' => self::DBUTF8($document->size),
606
                                ];
607
                                Database::update(
608
                                    $table,
609
                                    $params,
610
                                    [
611
                                        'c_id = ? AND id = ?' => [
612
                                            $this->destination_course_id,
613
                                            $document_id,
614
                                        ],
615
                                    ]
616
                                );
617
                            }
618
                            break;
619
                        case FILE_SKIP:
620
                            $sql = "SELECT id FROM $table
621
                                    WHERE
622
                                        c_id = ".$this->destination_course_id." AND
623
                                        path='/".self::DBUTF8escapestring(substr($document->path, 9))."'";
624
                            $res = Database::query($sql);
625
                            $obj = Database::fetch_object($res);
626
                            $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $obj->id;
627
                            break;
628
                        case FILE_RENAME:
629
                            //error_log("Rename: ".$path.$document->path);
630
                            $i = 1;
631
                            $ext = explode('.', basename($document->path));
632
                            if (count($ext) > 1) {
633
                                $ext = array_pop($ext);
634
                                $file_name_no_ext = substr($document->path, 0, -(strlen($ext) + 1));
635
                                $ext = '.'.$ext;
636
                            } else {
637
                                $ext = '';
638
                                $file_name_no_ext = $document->path;
639
                            }
640
                            $new_file_name = $file_name_no_ext.'_'.$i.$ext;
641
                            $file_exists = file_exists($path.$new_file_name);
642
                            while ($file_exists) {
643
                                $i++;
644
                                $new_file_name = $file_name_no_ext.'_'.$i.$ext;
645
                                $file_exists = file_exists($path.$new_file_name);
646
                            }
647
648
                            if (!empty($session_id)) {
649
                                $originalPath = $document->path;
650
                                //error_log("document->path: ".$document->path);
651
                                $document_path = explode('/', $document->path, 3);
652
                                $course_path = $path;
653
                                $orig_base_folder = $document_path[1];
654
                                $orig_base_path = $course_path.$document_path[0].'/'.$document_path[1];
655
656
                                if (is_dir($orig_base_path)) {
657
                                    $new_base_foldername = $orig_base_folder;
658
                                    $new_base_path = $orig_base_path;
659
660
                                    if (isset($_SESSION['orig_base_foldername']) &&
661
                                        $_SESSION['orig_base_foldername'] != $new_base_foldername
662
                                    ) {
663
                                        unset($_SESSION['new_base_foldername']);
664
                                        unset($_SESSION['orig_base_foldername']);
665
                                        unset($_SESSION['new_base_path']);
666
                                    }
667
668
                                    $folder_exists = file_exists($new_base_path);
669
                                    if ($folder_exists) {
670
                                        // e.g: carpeta1 in session
671
                                        $_SESSION['orig_base_foldername'] = $new_base_foldername;
672
                                        $x = 0;
673
                                        while ($folder_exists) {
674
                                            $x = $x + 1;
675
                                            $new_base_foldername = $document_path[1].'_'.$x;
676
                                            $new_base_path = $orig_base_path.'_'.$x;
677
                                            if (isset($_SESSION['new_base_foldername']) &&
678
                                                $_SESSION['new_base_foldername'] == $new_base_foldername
679
                                            ) {
680
                                                break;
681
                                            }
682
                                            $folder_exists = file_exists($new_base_path);
683
                                        }
684
                                        $_SESSION['new_base_foldername'] = $new_base_foldername;
685
                                        $_SESSION['new_base_path'] = $new_base_path;
686
                                    }
687
688
                                    if (isset($_SESSION['new_base_foldername']) && isset($_SESSION['new_base_path'])) {
689
                                        $new_base_foldername = $_SESSION['new_base_foldername'];
690
                                        $new_base_path = $_SESSION['new_base_path'];
691
                                    }
692
693
                                    $dest_document_path = $new_base_path.'/'.$document_path[2]; // e.g: "/var/www/wiener/courses/CURSO4/document/carpeta1_1/subcarpeta1/collaborative.png"
694
                                    $basedir_dest_path = dirname($dest_document_path); // e.g: "/var/www/wiener/courses/CURSO4/document/carpeta1_1/subcarpeta1"
695
                                    $base_path_document = $course_path.$document_path[0]; // e.g: "/var/www/wiener/courses/CURSO4/document"
696
                                    $path_title = '/'.$new_base_foldername.'/'.$document_path[2];
697
698
                                    /*error_log("copy_folder_course_session");
699
                                    error_log("original: $orig_base_path");
700
                                    error_log($basedir_dest_path);
701
                                    error_log($document->title);*/
702
703
                                    copy_folder_course_session(
704
                                        $basedir_dest_path,
705
                                        $base_path_document,
706
                                        $session_id,
707
                                        $course_info,
708
                                        $document,
709
                                        $this->course_origin_id,
710
                                        $originalFolderNameList,
711
                                        $originalPath
712
                                    );
713
714
                                    if (file_exists($course_path.$document->path)) {
715
                                        copy($course_path.$document->path, $dest_document_path);
716
                                    }
717
718
                                    // Replace old course code with the new destination code see BT#1985
719
                                    if (file_exists($dest_document_path)) {
720
                                        $file_info = pathinfo($dest_document_path);
721
                                        if (in_array($file_info['extension'], ['html', 'htm'])) {
722
                                            $content = file_get_contents($dest_document_path);
723
                                            if (UTF8_CONVERT) {
724
                                                $content = utf8_encode($content);
725
                                            }
726
                                            $content = DocumentManager::replaceUrlWithNewCourseCode(
727
                                                $content,
728
                                                $this->course->code,
729
                                                $this->course->destination_path,
730
                                                $this->course->backup_path,
731
                                                $this->course->info['path']
732
                                            );
733
                                            file_put_contents($dest_document_path, $content);
734
                                            $this->fixEditorHtmlContent($dest_document_path, $webEditorCss);
735
                                        }
736
                                    }
737
738
                                    $title = basename($path_title);
739
                                    if (isset($originalFolderNameList[basename($path_title)])) {
740
                                        $title = $originalFolderNameList[basename($path_title)];
741
                                    }
742
743
                                    $params = [
744
                                        'path' => self::DBUTF8($path_title),
745
                                        'c_id' => $this->destination_course_id,
746
                                        'comment' => self::DBUTF8($document->comment),
747
                                        'title' => self::DBUTF8($title),
748
                                        'filetype' => self::DBUTF8($document->file_type),
749
                                        'size' => self::DBUTF8($document->size),
750
                                        'session_id' => $my_session_id,
751
                                    ];
752
753
                                    $document_id = Database::insert($table, $params);
754
755
                                    if ($document_id) {
756
                                        $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
757
                                        Database::query($sql);
758
759
                                        $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
760
761
                                        $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
762
                                        $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
763
                                        $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
764
                                        $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
765
766
                                        $insertUserId = $this->checkUserId($insertUserId);
767
                                        $toUserId = $this->checkUserId($toUserId, true);
768
                                        $groupInfo = $this->checkGroupId($toGroupId);
769
770
                                        api_item_property_update(
771
                                            $course_info,
772
                                            TOOL_DOCUMENT,
773
                                            $document_id,
774
                                            'DocumentAdded',
775
                                            $insertUserId,
776
                                            $groupInfo,
777
                                            $toUserId,
778
                                            null,
779
                                            null,
780
                                            $my_session_id
781
                                        );
782
                                    }
783
                                } else {
784
                                    if (file_exists($path.$document->path)) {
785
                                        copy($path.$document->path, $path.$new_file_name);
786
                                    }
787
                                    // Replace old course code with the new destination code see BT#1985
788
                                    if (file_exists($path.$new_file_name)) {
789
                                        $file_info = pathinfo($path.$new_file_name);
790
                                        if (in_array($file_info['extension'], ['html', 'htm'])) {
791
                                            $content = file_get_contents($path.$new_file_name);
792
                                            if (UTF8_CONVERT) {
793
                                                $content = utf8_encode($content);
794
                                            }
795
                                            $content = DocumentManager::replaceUrlWithNewCourseCode(
796
                                                $content,
797
                                                $this->course->code,
798
                                                $this->course->destination_path,
799
                                                $this->course->backup_path,
800
                                                $this->course->info['path']
801
                                            );
802
                                            file_put_contents($path.$new_file_name, $content);
803
                                            $this->fixEditorHtmlContent($path.$new_file_name, $webEditorCss);
804
                                        }
805
                                    }
806
807
                                    $params = [
808
                                        'path' => "/".self::DBUTF8escapestring(substr($new_file_name, 9)),
809
                                        'c_id' => $this->destination_course_id,
810
                                        'comment' => self::DBUTF8($document->comment),
811
                                        'title' => self::DBUTF8($document->title),
812
                                        'filetype' => self::DBUTF8($document->file_type),
813
                                        'size' => self::DBUTF8($document->size),
814
                                        'session_id' => $my_session_id,
815
                                    ];
816
817
                                    $document_id = Database::insert($table, $params);
818
819
                                    if ($document_id) {
820
                                        $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
821
                                        Database::query($sql);
822
823
                                        $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
824
825
                                        $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
826
                                        $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
827
                                        $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
828
                                        $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
829
830
                                        $insertUserId = $this->checkUserId($insertUserId);
831
                                        $toUserId = $this->checkUserId($toUserId, true);
832
                                        $groupInfo = $this->checkGroupId($toGroupId);
833
834
                                        api_item_property_update(
835
                                            $course_info,
836
                                            TOOL_DOCUMENT,
837
                                            $document_id,
838
                                            'DocumentAdded',
839
                                            $insertUserId,
840
                                            $groupInfo,
841
                                            $toUserId,
842
                                            null,
843
                                            null,
844
                                            $my_session_id
845
                                        );
846
                                    }
847
                                }
848
                            } else {
849
                                copy(
850
                                    $this->course->backup_path.'/'.$document->path,
851
                                    $path.$new_file_name
852
                                );
853
854
                                // Replace old course code with the new destination code see BT#1985
855
                                if (file_exists($path.$new_file_name)) {
856
                                    $file_info = pathinfo($path.$new_file_name);
857
                                    if (in_array($file_info['extension'], ['html', 'htm'])) {
858
                                        $content = file_get_contents($path.$new_file_name);
859
                                        if (UTF8_CONVERT) {
860
                                            $content = utf8_encode($content);
861
                                        }
862
                                        $content = DocumentManager::replaceUrlWithNewCourseCode(
863
                                            $content,
864
                                            $this->course->code,
865
                                            $this->course->destination_path,
866
                                            $this->course->backup_path,
867
                                            $this->course->info['path']
868
                                        );
869
                                        file_put_contents($path.$new_file_name, $content);
870
                                        $this->fixEditorHtmlContent($path.$new_file_name, $webEditorCss);
871
                                    }
872
                                }
873
874
                                $params = [
875
                                    'c_id' => $this->destination_course_id,
876
                                    'path' => "/".self::DBUTF8escapestring(substr($new_file_name, 9)),
877
                                    'comment' => self::DBUTF8($document->comment),
878
                                    'title' => self::DBUTF8($document->title),
879
                                    'filetype' => self::DBUTF8($document->file_type),
880
                                    'size' => self::DBUTF8($document->size),
881
                                    'session_id' => $my_session_id,
882
                                ];
883
884
                                $document_id = Database::insert($table, $params);
885
886
                                if ($document_id) {
887
                                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
888
                                    Database::query($sql);
889
                                    $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
890
891
                                    $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
892
                                    $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
893
                                    $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
894
                                    $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
895
896
                                    $insertUserId = $this->checkUserId($insertUserId);
897
                                    $toUserId = $this->checkUserId($toUserId, true);
898
                                    $groupInfo = $this->checkGroupId($toGroupId);
899
900
                                    api_item_property_update(
901
                                        $course_info,
902
                                        TOOL_DOCUMENT,
903
                                        $document_id,
904
                                        'DocumentAdded',
905
                                        $insertUserId,
906
                                        $groupInfo,
907
                                        $toUserId,
908
                                        null,
909
                                        null,
910
                                        $my_session_id
911
                                    );
912
                                }
913
                            }
914
                            break;
915
                    } // end switch
916
                } else {
917
                    // end if file exists
918
919
                    //make sure the source file actually exists
920
                    if (is_file($this->course->backup_path.'/'.$document->path) &&
921
                        is_readable($this->course->backup_path.'/'.$document->path) &&
922
                        is_dir(dirname($path.$document->path)) &&
923
                        is_writeable(dirname($path.$document->path))
924
                    ) {
925
                        copy(
926
                            $this->course->backup_path.'/'.$document->path,
927
                            $path.$document->path
928
                        );
929
930
                        // Replace old course code with the new destination code see BT#1985
931
                        if (file_exists($path.$document->path)) {
932
                            $file_info = pathinfo($path.$document->path);
933
                            if (isset($file_info['extension']) && in_array($file_info['extension'], ['html', 'htm'])) {
934
                                $content = file_get_contents($path.$document->path);
935
                                if (UTF8_CONVERT) {
936
                                    $content = utf8_encode($content);
937
                                }
938
                                $content = DocumentManager::replaceUrlWithNewCourseCode(
939
                                    $content,
940
                                    $this->course->code,
941
                                    $this->course->destination_path,
942
                                    $this->course->backup_path,
943
                                    $this->course->info['path']
944
                                );
945
                                file_put_contents($path.$document->path, $content);
946
                                $this->fixEditorHtmlContent($path.$document->path, $webEditorCss);
947
                            }
948
                        }
949
950
                        $params = [
951
                            'c_id' => $this->destination_course_id,
952
                            'path' => "/".self::DBUTF8(substr($document->path, 9)),
953
                            'comment' => self::DBUTF8($document->comment),
954
                            'title' => self::DBUTF8($document->title),
955
                            'filetype' => self::DBUTF8($document->file_type),
956
                            'size' => self::DBUTF8($document->size),
957
                            'session_id' => $my_session_id,
958
                            'readonly' => 0,
959
                        ];
960
961
                        $document_id = Database::insert($table, $params);
962
963
                        if ($document_id) {
964
                            $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
965
                            Database::query($sql);
966
967
                            $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
968
969
                            $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
970
                            $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
971
                            $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
972
                            $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
973
974
                            $insertUserId = $this->checkUserId($insertUserId);
975
                            $toUserId = $this->checkUserId($toUserId, true);
976
                            $groupInfo = $this->checkGroupId($toGroupId);
977
978
                            api_item_property_update(
979
                                $course_info,
980
                                TOOL_DOCUMENT,
981
                                $document_id,
982
                                'DocumentAdded',
983
                                $insertUserId,
984
                                $groupInfo,
985
                                $toUserId,
986
                                null,
987
                                null,
988
                                $my_session_id
989
                            );
990
                        }
991
                    } else {
992
                        // There was an error in checking existence and
993
                        // permissions for files to copy. Try to determine
994
                        // the exact issue
995
                        // Issue with origin document?
996
                        if (!is_file($this->course->backup_path.'/'.$document->path)) {
997
                            error_log(
998
                                'Course copy generated an ignorable error while trying to copy '.
999
                                $this->course->backup_path.'/'.$document->path.': origin file not found'
1000
                            );
1001
                        } elseif (!is_readable($this->course->backup_path.'/'.$document->path)) {
1002
                            error_log(
1003
                                'Course copy generated an ignorable error while trying to copy '.
1004
                                $this->course->backup_path.'/'.$document->path.': origin file not readable'
1005
                            );
1006
                        }
1007
                        // Issue with destination directories?
1008
                        if (!is_dir(dirname($path.$document->path))) {
1009
                            error_log(
1010
                                'Course copy generated an ignorable error while trying to copy '.
1011
                                $this->course->backup_path.'/'.$document->path.' to '.
1012
                                dirname($path.$document->path).': destination directory not found'
1013
                            );
1014
                        }
1015
                        if (!is_writeable(dirname($path.$document->path))) {
1016
                            error_log(
1017
                                'Course copy generated an ignorable error while trying to copy '.
1018
                                $this->course->backup_path.'/'.$document->path.' to '.
1019
                                dirname($path.$document->path).': destination directory not writable'
1020
                            );
1021
                        }
1022
                    }
1023
                } // end file doesn't exist
1024
            }
1025
1026
            // add image information for area questions
1027
            if (preg_match('/^quiz-.*$/', $document->title) &&
1028
                preg_match('/^document\/images\/.*$/', $document->path)
1029
            ) {
1030
                $this->course->resources[RESOURCE_DOCUMENT]['image_quiz'][$document->title] = [
1031
                    'path' => $document->path,
1032
                    'title' => $document->title,
1033
                    'source_id' => $document->source_id,
1034
                    'destination_id' => $document->destination_id,
1035
                ];
1036
            }
1037
        } // end for each
1038
1039
        // Delete sessions for the copy the new folder in session
1040
        unset($_SESSION['new_base_foldername']);
1041
        unset($_SESSION['orig_base_foldername']);
1042
        unset($_SESSION['new_base_path']);
1043
    }
1044
1045
    /**
1046
     * Restore scorm documents
1047
     * TODO @TODO check that the restore function with renaming doesn't break the scorm structure!
1048
     * see #7029.
1049
     */
1050
    public function restore_scorm_documents()
1051
    {
1052
        $perm = api_get_permissions_for_new_directories();
1053
        if ($this->course->has_resources(RESOURCE_SCORM)) {
1054
            $resources = $this->course->resources;
1055
            foreach ($resources[RESOURCE_SCORM] as $document) {
1056
                $path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/';
1057
                @mkdir(dirname($path.$document->path), $perm, true);
1058
                if (file_exists($path.$document->path)) {
1059
                    switch ($this->file_option) {
1060
                        case FILE_OVERWRITE:
1061
                            rmdirr($path.$document->path);
1062
                            copyDirTo(
1063
                                $this->course->backup_path.'/'.$document->path,
1064
                                $path.$document->path,
1065
                                false
1066
                            );
1067
                            break;
1068
                        case FILE_SKIP:
1069
                            break;
1070
                        case FILE_RENAME:
1071
                            $i = 1;
1072
                            $ext = explode('.', basename($document->path));
1073
                            if (count($ext) > 1) {
1074
                                $ext = array_pop($ext);
1075
                                $file_name_no_ext = substr($document->path, 0, -(strlen($ext) + 1));
1076
                                $ext = '.'.$ext;
1077
                            } else {
1078
                                $ext = '';
1079
                                $file_name_no_ext = $document->path;
1080
                            }
1081
1082
                            $new_file_name = $file_name_no_ext.'_'.$i.$ext;
1083
                            $file_exists = file_exists($path.$new_file_name);
1084
1085
                            while ($file_exists) {
1086
                                $i++;
1087
                                $new_file_name = $file_name_no_ext.'_'.$i.$ext;
1088
                                $file_exists = file_exists($path.$new_file_name);
1089
                            }
1090
1091
                            rename(
1092
                                $this->course->backup_path.'/'.$document->path,
1093
                                $this->course->backup_path.'/'.$new_file_name
1094
                            );
1095
                            copyDirTo(
1096
                                $this->course->backup_path.'/'.$new_file_name,
1097
                                $path.dirname($new_file_name),
1098
                                false
1099
                            );
1100
                            rename(
1101
                                $this->course->backup_path.'/'.$new_file_name,
1102
                                $this->course->backup_path.'/'.$document->path
1103
                            );
1104
                            break;
1105
                    } // end switch
1106
                } else {
1107
                    // end if file exists
1108
                    copyDirTo(
1109
                        $this->course->backup_path.'/'.$document->path,
1110
                        $path.$document->path,
1111
                        false
1112
                    );
1113
                }
1114
            } // end for each
1115
        }
1116
    }
1117
1118
    /**
1119
     * Restore forums.
1120
     *
1121
     * @param int $sessionId
1122
     */
1123
    public function restore_forums($sessionId = 0)
1124
    {
1125
        if ($this->course->has_resources(RESOURCE_FORUM)) {
1126
            $sessionId = (int) $sessionId;
1127
            $table_forum = Database::get_course_table(TABLE_FORUM);
1128
            $resources = $this->course->resources;
1129
            foreach ($resources[RESOURCE_FORUM] as $id => $forum) {
1130
                $params = (array) $forum->obj;
1131
                $cat_id = '';
1132
                if (isset($this->course->resources[RESOURCE_FORUMCATEGORY]) &&
1133
                    isset($this->course->resources[RESOURCE_FORUMCATEGORY][$params['forum_category']])) {
1134
                    if ($this->course->resources[RESOURCE_FORUMCATEGORY][$params['forum_category']]->destination_id == -1) {
1135
                        $cat_id = $this->restore_forum_category($params['forum_category'], $sessionId);
1136
                    } else {
1137
                        $cat_id = $this->course->resources[RESOURCE_FORUMCATEGORY][$params['forum_category']]->destination_id;
1138
                    }
1139
                }
1140
1141
                $params = self::DBUTF8_array($params);
1142
                $params['c_id'] = $this->destination_course_id;
1143
                $params['forum_category'] = $cat_id;
1144
                $params['session_id'] = $sessionId;
1145
                $params['start_time'] = isset($params['start_time']) && $params['start_time'] === '0000-00-00 00:00:00' ? null : $params['start_time'];
1146
                $params['end_time'] = isset($params['end_time']) && $params['end_time'] === '0000-00-00 00:00:00' ? null : $params['end_time'];
1147
                $params['forum_id'] = 0;
1148
                unset($params['iid']);
1149
1150
                $params['forum_comment'] = DocumentManager::replaceUrlWithNewCourseCode(
1151
                    $params['forum_comment'],
1152
                    $this->course->code,
1153
                    $this->course->destination_path,
1154
                    $this->course->backup_path,
1155
                    $this->course->info['path']
1156
                );
1157
1158
                if (!empty($params['forum_image'])) {
1159
                    $original_forum_image = $this->course->path.'upload/forum/images/'.$params['forum_image'];
1160
                    if (file_exists($original_forum_image)) {
1161
                        $new_forum_image = api_get_path(SYS_COURSE_PATH).
1162
                            $this->destination_course_info['path'].'/upload/forum/images/'.$params['forum_image'];
1163
                        @copy($original_forum_image, $new_forum_image);
1164
                    }
1165
                }
1166
1167
                $new_id = Database::insert($table_forum, $params);
1168
1169
                if ($new_id) {
1170
                    $sql = "UPDATE $table_forum SET forum_id = iid WHERE iid = $new_id";
1171
                    Database::query($sql);
1172
1173
                    api_item_property_update(
1174
                        $this->destination_course_info,
1175
                        TOOL_FORUM,
1176
                        $new_id,
1177
                        'ForumUpdated',
1178
                        api_get_user_id(),
1179
                        null,
1180
                        null,
1181
                        null,
1182
                        null,
1183
                        $sessionId
1184
                    );
1185
1186
                    $this->course->resources[RESOURCE_FORUM][$id]->destination_id = $new_id;
1187
                    $forum_topics = 0;
1188
                    if (isset($this->course->resources[RESOURCE_FORUMTOPIC]) &&
1189
                        is_array($this->course->resources[RESOURCE_FORUMTOPIC])
1190
                    ) {
1191
                        foreach ($this->course->resources[RESOURCE_FORUMTOPIC] as $topic_id => $topic) {
1192
                            if ($topic->obj->forum_id == $id) {
1193
                                $this->restore_topic($topic_id, $new_id, $sessionId);
1194
                                $forum_topics++;
1195
                            }
1196
                        }
1197
                    }
1198
                    if ($forum_topics > 0) {
1199
                        $sql = "UPDATE ".$table_forum." SET forum_threads = ".$forum_topics."
1200
                                WHERE c_id = {$this->destination_course_id} AND forum_id = ".(int) $new_id;
1201
                        Database::query($sql);
1202
                    }
1203
                }
1204
            }
1205
        }
1206
    }
1207
1208
    /**
1209
     * Restore forum-categories.
1210
     */
1211
    public function restore_forum_category($my_id = null, $sessionId = 0)
1212
    {
1213
        $forum_cat_table = Database::get_course_table(TABLE_FORUM_CATEGORY);
1214
        $resources = $this->course->resources;
1215
        $sessionId = (int) $sessionId;
1216
        if (!empty($resources[RESOURCE_FORUMCATEGORY])) {
1217
            foreach ($resources[RESOURCE_FORUMCATEGORY] as $id => $forum_cat) {
1218
                if (!empty($my_id)) {
1219
                    if ($my_id != $id) {
1220
                        continue;
1221
                    }
1222
                }
1223
                if ($forum_cat && !$forum_cat->is_restored()) {
1224
                    $params = (array) $forum_cat->obj;
1225
                    $params['c_id'] = $this->destination_course_id;
1226
                    $params['cat_comment'] = DocumentManager::replaceUrlWithNewCourseCode(
1227
                        $params['cat_comment'],
1228
                        $this->course->code,
1229
                        $this->course->destination_path,
1230
                        $this->course->backup_path,
1231
                        $this->course->info['path']
1232
                    );
1233
                    $params['session_id'] = $sessionId;
1234
                    $params['cat_id'] = 0;
1235
                    unset($params['iid']);
1236
1237
                    $params = self::DBUTF8_array($params);
1238
                    $new_id = Database::insert($forum_cat_table, $params);
1239
1240
                    if ($new_id) {
1241
                        $sql = "UPDATE $forum_cat_table SET cat_id = iid WHERE iid = $new_id";
1242
                        Database::query($sql);
1243
1244
                        api_item_property_update(
1245
                            $this->destination_course_info,
1246
                            TOOL_FORUM_CATEGORY,
1247
                            $new_id,
1248
                            'ForumCategoryUpdated',
1249
                            api_get_user_id(),
1250
                            null,
1251
                            null,
1252
                            null,
1253
                            null,
1254
                            $sessionId
1255
                        );
1256
                        $this->course->resources[RESOURCE_FORUMCATEGORY][$id]->destination_id = $new_id;
1257
                    }
1258
1259
                    if (!empty($my_id)) {
1260
                        return $new_id;
1261
                    }
1262
                }
1263
            }
1264
        }
1265
    }
1266
1267
    /**
1268
     * Restore a forum-topic.
1269
     *
1270
     * @param false|string $forum_id
1271
     *
1272
     * @return int
1273
     */
1274
    public function restore_topic($thread_id, $forum_id, $sessionId = 0)
1275
    {
1276
        $table = Database::get_course_table(TABLE_FORUM_THREAD);
1277
        $topic = $this->course->resources[RESOURCE_FORUMTOPIC][$thread_id];
1278
1279
        $sessionId = (int) $sessionId;
1280
        $params = (array) $topic->obj;
1281
1282
        $params = self::DBUTF8_array($params);
1283
        $params['c_id'] = $this->destination_course_id;
1284
        $params['forum_id'] = $forum_id;
1285
        $params['thread_poster_id'] = $this->first_teacher_id;
1286
        $params['thread_date'] = api_get_utc_datetime();
1287
        $params['thread_close_date'] = null;
1288
        $params['thread_last_post'] = 0;
1289
        $params['thread_replies'] = 0;
1290
        $params['thread_views'] = 0;
1291
        $params['session_id'] = $sessionId;
1292
        $params['thread_id'] = 0;
1293
1294
        unset($params['iid']);
1295
1296
        $new_id = Database::insert($table, $params);
1297
1298
        if ($new_id) {
1299
            $sql = "UPDATE $table SET thread_id = iid WHERE iid = $new_id";
1300
            Database::query($sql);
1301
1302
            api_item_property_update(
1303
                $this->destination_course_info,
1304
                TOOL_FORUM_THREAD,
1305
                $new_id,
1306
                'ThreadAdded',
1307
                api_get_user_id(),
1308
                0,
1309
                0,
1310
                null,
1311
                null,
1312
                $sessionId
1313
            );
1314
1315
            $this->course->resources[RESOURCE_FORUMTOPIC][$thread_id]->destination_id = $new_id;
1316
            $topic_replies = -1;
1317
1318
            foreach ($this->course->resources[RESOURCE_FORUMPOST] as $post_id => $post) {
1319
                if ($post->obj->thread_id == $thread_id) {
1320
                    $topic_replies++;
1321
                    $this->restore_post($post_id, $new_id, $forum_id, $sessionId);
1322
                }
1323
            }
1324
        }
1325
1326
        return $new_id;
1327
    }
1328
1329
    /**
1330
     * Restore a forum-post.
1331
     *
1332
     * @TODO Restore tree-structure of posts. For example: attachments to posts.
1333
     *
1334
     * @param false|string $topic_id
1335
     *
1336
     * @return int
1337
     */
1338
    public function restore_post($id, $topic_id, $forum_id, $sessionId = 0)
1339
    {
1340
        $table_post = Database::get_course_table(TABLE_FORUM_POST);
1341
        $post = $this->course->resources[RESOURCE_FORUMPOST][$id];
1342
        $params = (array) $post->obj;
1343
        $params['c_id'] = $this->destination_course_id;
1344
        $params['forum_id'] = $forum_id;
1345
        $params['thread_id'] = $topic_id;
1346
        $params['poster_id'] = $this->first_teacher_id;
1347
        $params['post_date'] = api_get_utc_datetime();
1348
        $params['post_id'] = 0;
1349
        unset($params['iid']);
1350
1351
        $params['post_text'] = DocumentManager::replaceUrlWithNewCourseCode(
1352
            $params['post_text'],
1353
            $this->course->code,
1354
            $this->course->destination_path,
1355
            $this->course->backup_path,
1356
            $this->course->info['path']
1357
        );
1358
        $new_id = Database::insert($table_post, $params);
1359
1360
        if ($new_id) {
1361
            $sql = "UPDATE $table_post SET post_id = iid WHERE iid = $new_id";
1362
            Database::query($sql);
1363
1364
            api_item_property_update(
1365
                $this->destination_course_info,
1366
                TOOL_FORUM_POST,
1367
                $new_id,
1368
                'PostAdded',
1369
                api_get_user_id(),
1370
                0,
1371
                0,
1372
                null,
1373
                null,
1374
                $sessionId
1375
            );
1376
            $this->course->resources[RESOURCE_FORUMPOST][$id]->destination_id = $new_id;
1377
        }
1378
1379
        return $new_id;
1380
    }
1381
1382
    /**
1383
     * Restore links.
1384
     */
1385
    public function restore_links($session_id = 0)
1386
    {
1387
        if ($this->course->has_resources(RESOURCE_LINK)) {
1388
            $link_table = Database::get_course_table(TABLE_LINK);
1389
            $resources = $this->course->resources;
1390
1391
            foreach ($resources[RESOURCE_LINK] as $oldLinkId => $link) {
1392
                $cat_id = (int) $this->restore_link_category($link->category_id, $session_id);
1393
                $sql = "SELECT MAX(display_order)
1394
                        FROM $link_table
1395
                        WHERE
1396
                            c_id = ".$this->destination_course_id." AND
1397
                            category_id='".$cat_id."'";
1398
                $result = Database::query($sql);
1399
                [$max_order] = Database::fetch_array($result);
1400
1401
                $params = [];
1402
                $params['session_id'] = (int) $session_id;
1403
                $params['c_id'] = $this->destination_course_id;
1404
                $params['url'] = self::DBUTF8($link->url);
1405
                $params['title'] = self::DBUTF8($link->title);
1406
                $params['description'] = self::DBUTF8($link->description);
1407
                $params['category_id'] = $cat_id;
1408
                $params['on_homepage'] = $link->on_homepage;
1409
                $params['display_order'] = $max_order + 1;
1410
                $params['target'] = $link->target;
1411
1412
                $id = Database::insert($link_table, $params);
1413
1414
                if ($id) {
1415
                    $sql = "UPDATE $link_table SET id = iid WHERE iid = $id";
1416
                    Database::query($sql);
1417
1418
                    api_item_property_update(
1419
                        $this->destination_course_info,
1420
                        TOOL_LINK,
1421
                        $id,
1422
                        'LinkAdded',
1423
                        api_get_user_id(),
1424
                        null,
1425
                        null,
1426
                        null,
1427
                        null,
1428
                        $session_id
1429
                    );
1430
1431
                    if (!isset($this->course->resources[RESOURCE_LINK][$oldLinkId])) {
1432
                        $this->course->resources[RESOURCE_LINK][$oldLinkId] = new stdClass();
1433
                    }
1434
                    $this->course->resources[RESOURCE_LINK][$oldLinkId]->destination_id = $id;
1435
                }
1436
            }
1437
        }
1438
    }
1439
1440
    /**
1441
     * Restore a link-category.
1442
     *
1443
     * @param int
1444
     * @param int
1445
     *
1446
     * @return bool
1447
     */
1448
    public function restore_link_category($id, $sessionId = 0)
1449
    {
1450
        $params = [];
1451
        $sessionId = (int) $sessionId;
1452
        if (!empty($sessionId)) {
1453
            $params['session_id'] = $sessionId;
1454
        }
1455
1456
        if ($id == 0) {
1457
            return 0;
1458
        }
1459
        $link_cat_table = Database::get_course_table(TABLE_LINK_CATEGORY);
1460
        $resources = $this->course->resources;
1461
        $link_cat = $resources[RESOURCE_LINKCATEGORY][$id];
1462
        if (is_object($link_cat) && !$link_cat->is_restored()) {
1463
            $sql = "SELECT MAX(display_order) FROM  $link_cat_table
1464
                    WHERE c_id = ".$this->destination_course_id;
1465
            $result = Database::query($sql);
1466
            [$orderMax] = Database::fetch_array($result, 'NUM');
1467
            $display_order = $orderMax + 1;
1468
1469
            $params['c_id'] = $this->destination_course_id;
1470
            $params['category_title'] = self::DBUTF8($link_cat->title);
1471
            $params['description'] = self::DBUTF8($link_cat->description);
1472
            $params['display_order'] = $display_order;
1473
            $new_id = Database::insert($link_cat_table, $params);
1474
1475
            if ($new_id) {
1476
                $sql = "UPDATE $link_cat_table
1477
                        SET id = iid
1478
                        WHERE iid = $new_id";
1479
                Database::query($sql);
1480
1481
                $courseInfo = api_get_course_info_by_id($this->destination_course_id);
1482
                api_item_property_update(
1483
                    $courseInfo,
1484
                    TOOL_LINK_CATEGORY,
1485
                    $new_id,
1486
                    'LinkCategoryAdded',
1487
                    api_get_user_id(),
1488
                    null,
1489
                    null,
1490
                    null,
1491
                    null,
1492
                    $sessionId
1493
                );
1494
                api_set_default_visibility(
1495
                    $new_id,
1496
                    TOOL_LINK_CATEGORY,
1497
                    0,
1498
                    $courseInfo,
1499
                    $sessionId
1500
                );
1501
            }
1502
1503
            $this->course->resources[RESOURCE_LINKCATEGORY][$id]->destination_id = $new_id;
1504
1505
            return $new_id;
1506
        }
1507
1508
        return $this->course->resources[RESOURCE_LINKCATEGORY][$id]->destination_id;
1509
    }
1510
1511
    /**
1512
     * Restore tool intro.
1513
     *
1514
     * @param int
1515
     */
1516
    public function restore_tool_intro($sessionId = 0)
1517
    {
1518
        if ($this->course->has_resources(RESOURCE_TOOL_INTRO)) {
1519
            $sessionId = (int) $sessionId;
1520
            $tool_intro_table = Database::get_course_table(TABLE_TOOL_INTRO);
1521
            $resources = $this->course->resources;
1522
            foreach ($resources[RESOURCE_TOOL_INTRO] as $id => $tool_intro) {
1523
                if (!$this->copySessionContent) {
1524
                    $sql = "DELETE FROM $tool_intro_table
1525
                        WHERE
1526
                            c_id = ".$this->destination_course_id." AND
1527
                            id='".self::DBUTF8escapestring($tool_intro->id)."'";
1528
                    Database::query($sql);
1529
                }
1530
1531
                $tool_intro->intro_text = DocumentManager::replaceUrlWithNewCourseCode(
1532
                    $tool_intro->intro_text,
1533
                    $this->course->code,
1534
                    $this->course->destination_path,
1535
                    $this->course->backup_path,
1536
                    $this->course->info['path']
1537
                );
1538
1539
                $params = [
1540
                    'c_id' => $this->destination_course_id,
1541
                    'id' => ($tool_intro->id === false ? '' : self::DBUTF8($tool_intro->id)),
1542
                    'intro_text' => self::DBUTF8($tool_intro->intro_text),
1543
                    'session_id' => $sessionId,
1544
                ];
1545
1546
                $id = Database::insert($tool_intro_table, $params);
1547
                if ($id) {
1548
                    if (!isset($this->course->resources[RESOURCE_TOOL_INTRO][$id])) {
1549
                        $this->course->resources[RESOURCE_TOOL_INTRO][$id] = new stdClass();
1550
                    }
1551
1552
                    $this->course->resources[RESOURCE_TOOL_INTRO][$id]->destination_id = $id;
1553
                }
1554
            }
1555
        }
1556
    }
1557
1558
    /**
1559
     * Restore events.
1560
     *
1561
     * @param int
1562
     */
1563
    public function restore_events($sessionId = 0)
1564
    {
1565
        if ($this->course->has_resources(RESOURCE_EVENT)) {
1566
            $sessionId = (int) $sessionId;
1567
            $table = Database::get_course_table(TABLE_AGENDA);
1568
            $resources = $this->course->resources;
1569
            foreach ($resources[RESOURCE_EVENT] as $id => $event) {
1570
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
1571
                $event->content = DocumentManager::replaceUrlWithNewCourseCode(
1572
                    $event->content,
1573
                    $this->course->code,
1574
                    $this->course->destination_path,
1575
                    $this->course->backup_path,
1576
                    $this->course->info['path']
1577
                );
1578
1579
                $params = [
1580
                    'c_id' => $this->destination_course_id,
1581
                    'title' => self::DBUTF8($event->title),
1582
                    'content' => ($event->content === false ? '' : self::DBUTF8($event->content)),
1583
                    'all_day' => $event->all_day,
1584
                    'start_date' => $event->start_date,
1585
                    'end_date' => $event->end_date,
1586
                    'session_id' => $sessionId,
1587
                ];
1588
                $new_event_id = Database::insert($table, $params);
1589
1590
                if ($new_event_id) {
1591
                    $sql = "UPDATE $table SET id = iid WHERE iid = $new_event_id";
1592
                    Database::query($sql);
1593
1594
                    // Choose default visibility
1595
                    $toolVisibility = api_get_setting('tool_visible_by_default_at_creation');
1596
                    $defaultLpVisibility = 'invisible';
1597
                    if (isset($toolVisibility['learning_path']) && $toolVisibility['learning_path'] == 'true') {
1598
                        $defaultLpVisibility = 'visible';
1599
                    }
1600
1601
                    api_item_property_update(
1602
                        $this->destination_course_info,
1603
                        TOOL_CALENDAR_EVENT,
1604
                        $new_event_id,
1605
                        'AgendaAdded',
1606
                        api_get_user_id(),
1607
                        0,
1608
                        0,
1609
                        0,
1610
                        0,
1611
                        $sessionId
1612
                    );
1613
1614
                    // Set the new Agenda to visible
1615
                    api_item_property_update(
1616
                        $this->destination_course_info,
1617
                        TOOL_CALENDAR_EVENT,
1618
                        $new_event_id,
1619
                        $defaultLpVisibility,
1620
                        api_get_user_id(),
1621
                        0,
1622
                        0,
1623
                        0,
1624
                        0,
1625
                        $sessionId
1626
                    );
1627
1628
                    if (!isset($this->course->resources[RESOURCE_EVENT][$id])) {
1629
                        $this->course->resources[RESOURCE_EVENT][$id] = new stdClass();
1630
                    }
1631
                    $this->course->resources[RESOURCE_EVENT][$id]->destination_id = $new_event_id;
1632
                }
1633
1634
                // Copy event attachment
1635
                $origin_path = $this->course->backup_path.'/upload/calendar/';
1636
                $destination_path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/upload/calendar/';
1637
1638
                if (!empty($this->course->orig)) {
1639
                    $table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
1640
                    $sql = 'SELECT path, comment, size, filename
1641
                            FROM '.$table_attachment.'
1642
                            WHERE c_id = '.$this->destination_course_id.' AND agenda_id = '.$id;
1643
                    $attachment_event = Database::query($sql);
1644
                    $attachment_event = Database::fetch_object($attachment_event);
1645
1646
                    if (file_exists($origin_path.$attachment_event->path) &&
1647
                        !is_dir($origin_path.$attachment_event->path)
1648
                    ) {
1649
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1650
                        $copy_result = copy(
1651
                            $origin_path.$attachment_event->path,
1652
                            $destination_path.$new_filename
1653
                        );
1654
                        //$copy_result = true;
1655
                        if ($copy_result) {
1656
                            $table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
1657
1658
                            $params = [
1659
                                'c_id' => $this->destination_course_id,
1660
                                'path' => self::DBUTF8($new_filename),
1661
                                'comment' => self::DBUTF8($attachment_event->comment),
1662
                                'size' => isset($attachment_event->size) ? $attachment_event->size : '',
1663
                                'filename' => isset($attachment_event->filename) ? $attachment_event->filename : '',
1664
                                'agenda_id' => $new_event_id,
1665
                            ];
1666
                            $id = Database::insert($table_attachment, $params);
1667
                            if ($id) {
1668
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $id";
1669
                                Database::query($sql);
1670
                            }
1671
                        }
1672
                    }
1673
                } else {
1674
                    // get the info of the file
1675
                    if (!empty($event->attachment_path) &&
1676
                        is_file($origin_path.$event->attachment_path) &&
1677
                        is_readable($origin_path.$event->attachment_path)
1678
                    ) {
1679
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1680
                        $copy_result = copy(
1681
                            $origin_path.$event->attachment_path,
1682
                            $destination_path.$new_filename
1683
                        );
1684
                        if ($copy_result) {
1685
                            $table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
1686
1687
                            $params = [
1688
                                'c_id' => $this->destination_course_id,
1689
                                'path' => self::DBUTF8($new_filename),
1690
                                'comment' => self::DBUTF8($event->attachment_comment),
1691
                                'size' => isset($event->attachment_size) ? $event->attachment_size : '',
1692
                                'filename' => isset($event->attachment_filename) ? $event->attachment_filename : '',
1693
                                'agenda_id' => $new_event_id,
1694
                            ];
1695
                            $id = Database::insert($table_attachment, $params);
1696
1697
                            if ($id) {
1698
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $id";
1699
                                Database::query($sql);
1700
1701
                                api_item_property_update(
1702
                                    $this->destination_course_info,
1703
                                    'calendar_event_attachment',
1704
                                    $id,
1705
                                    'AgendaAttachmentAdded',
1706
                                    api_get_user_id()
1707
                                );
1708
                            }
1709
                        }
1710
                    }
1711
                }
1712
            }
1713
        }
1714
    }
1715
1716
    /**
1717
     * Restore course-description.
1718
     *
1719
     * @param int
1720
     */
1721
    public function restore_course_descriptions($session_id = 0)
1722
    {
1723
        if ($this->course->has_resources(RESOURCE_COURSEDESCRIPTION)) {
1724
            $table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
1725
            $resources = $this->course->resources;
1726
            foreach ($resources[RESOURCE_COURSEDESCRIPTION] as $id => $cd) {
1727
                $courseDescription = (array) $cd;
1728
1729
                $content = isset($courseDescription['content']) ? $courseDescription['content'] : '';
1730
                $descriptionType = isset($courseDescription['description_type']) ? $courseDescription['description_type'] : '';
1731
                $title = isset($courseDescription['title']) ? $courseDescription['title'] : '';
1732
1733
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
1734
                $description_content = DocumentManager::replaceUrlWithNewCourseCode(
1735
                    $content,
1736
                    $this->course->code,
1737
                    $this->course->destination_path,
1738
                    $this->course->backup_path,
1739
                    $this->course->info['path']
1740
                );
1741
1742
                $params = [];
1743
                $session_id = (int) $session_id;
1744
                $params['session_id'] = $session_id;
1745
                $params['c_id'] = $this->destination_course_id;
1746
                $params['description_type'] = self::DBUTF8($descriptionType);
1747
                $params['title'] = self::DBUTF8($title);
1748
                $params['content'] = ($description_content === false ? '' : self::DBUTF8($description_content));
1749
                $params['progress'] = 0;
1750
1751
                $id = Database::insert($table, $params);
1752
                if ($id) {
1753
                    $sql = "UPDATE $table SET id = iid WHERE iid = $id";
1754
                    Database::query($sql);
1755
1756
                    if (!isset($this->course->resources[RESOURCE_COURSEDESCRIPTION][$id])) {
1757
                        $this->course->resources[RESOURCE_COURSEDESCRIPTION][$id] = new stdClass();
1758
                    }
1759
                    $this->course->resources[RESOURCE_COURSEDESCRIPTION][$id]->destination_id = $id;
1760
                }
1761
            }
1762
        }
1763
    }
1764
1765
    /**
1766
     * Restore announcements.
1767
     *
1768
     * @param int
1769
     */
1770
    public function restore_announcements($sessionId = 0)
1771
    {
1772
        if ($this->course->has_resources(RESOURCE_ANNOUNCEMENT)) {
1773
            $sessionId = (int) $sessionId;
1774
            $table = Database::get_course_table(TABLE_ANNOUNCEMENT);
1775
            $resources = $this->course->resources;
1776
            foreach ($resources[RESOURCE_ANNOUNCEMENT] as $id => $announcement) {
1777
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
1778
                $announcement->content = DocumentManager::replaceUrlWithNewCourseCode(
1779
                    $announcement->content,
1780
                    $this->course->code,
1781
                    $this->course->destination_path,
1782
                    $this->course->backup_path,
1783
                    $this->course->info['path']
1784
                );
1785
1786
                $params = [
1787
                    'c_id' => $this->destination_course_id,
1788
                    'title' => self::DBUTF8($announcement->title),
1789
                    'content' => ($announcement->content === false ? '' : self::DBUTF8($announcement->content)),
1790
                    'end_date' => $announcement->date,
1791
                    'display_order' => $announcement->display_order,
1792
                    'email_sent' => $announcement->email_sent,
1793
                    'session_id' => $sessionId,
1794
                ];
1795
1796
                $new_announcement_id = Database::insert($table, $params);
1797
1798
                if ($new_announcement_id) {
1799
                    $sql = "UPDATE $table SET id = iid WHERE iid = $new_announcement_id";
1800
                    Database::query($sql);
1801
1802
                    if (!isset($this->course->resources[RESOURCE_ANNOUNCEMENT][$id])) {
1803
                        $this->course->resources[RESOURCE_ANNOUNCEMENT][$id] = new stdClass();
1804
                    }
1805
                    $this->course->resources[RESOURCE_ANNOUNCEMENT][$id]->destination_id = $new_announcement_id;
1806
                }
1807
1808
                $origin_path = $this->course->backup_path.'/upload/announcements/';
1809
                $destination_path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/upload/announcements/';
1810
1811
                // Copy announcement attachment file
1812
                if (!empty($this->course->orig)) {
1813
                    $table_attachment = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
1814
                    $sql = 'SELECT path, comment, size, filename
1815
                            FROM '.$table_attachment.'
1816
                            WHERE
1817
                                c_id = '.$this->destination_course_id.' AND
1818
                                announcement_id = '.$id;
1819
                    $attachment_event = Database::query($sql);
1820
                    $attachment_event = Database::fetch_object($attachment_event);
1821
1822
                    if (file_exists($origin_path.$attachment_event->path) &&
1823
                        !is_dir($origin_path.$attachment_event->path)
1824
                    ) {
1825
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1826
                        $copy_result = copy(
1827
                            $origin_path.$attachment_event->path,
1828
                            $destination_path.$new_filename
1829
                        );
1830
1831
                        if ($copy_result) {
1832
                            $table_attachment = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
1833
1834
                            $params = [
1835
                                'c_id' => $this->destination_course_id,
1836
                                'path' => self::DBUTF8($new_filename),
1837
                                'comment' => self::DBUTF8($attachment_event->comment),
1838
                                'size' => $attachment_event->size,
1839
                                'filename' => $attachment_event->filename,
1840
                                'announcement_id' => $new_announcement_id,
1841
                            ];
1842
1843
                            $attachmentId = Database::insert($table_attachment, $params);
1844
1845
                            if ($attachmentId) {
1846
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $attachmentId";
1847
                                Database::query($sql);
1848
                            }
1849
                        }
1850
                    }
1851
                } else {
1852
                    // get the info of the file
1853
                    if (!empty($announcement->attachment_path) &&
1854
                        is_file($origin_path.$announcement->attachment_path) &&
1855
                        is_readable($origin_path.$announcement->attachment_path)
1856
                    ) {
1857
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1858
                        $copy_result = copy($origin_path.$announcement->attachment_path, $destination_path.$new_filename);
1859
1860
                        if ($copy_result) {
1861
                            $table_attachment = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
1862
1863
                            $params = [
1864
                                'c_id' => $this->destination_course_id,
1865
                                'path' => self::DBUTF8($new_filename),
1866
                                'comment' => self::DBUTF8($announcement->attachment_comment),
1867
                                'size' => $announcement->attachment_size,
1868
                                'filename' => $announcement->attachment_filename,
1869
                                'announcement_id' => $new_announcement_id,
1870
                            ];
1871
1872
                            $attachmentId = Database::insert($table_attachment, $params);
1873
1874
                            if ($attachmentId) {
1875
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $attachmentId";
1876
                                Database::query($sql);
1877
                            }
1878
                        }
1879
                    }
1880
                }
1881
            }
1882
        }
1883
    }
1884
1885
    /**
1886
     * Restore Quiz.
1887
     *
1888
     * @param int  $session_id
1889
     * @param bool $respect_base_content
1890
     */
1891
    public function restore_quizzes(
1892
        $session_id = 0,
1893
        $respect_base_content = false
1894
    ) {
1895
        if ($this->course->has_resources(RESOURCE_QUIZ)) {
1896
            $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
1897
            $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
1898
            $table_doc = Database::get_course_table(TABLE_DOCUMENT);
1899
            $resources = $this->course->resources;
1900
            // Check if the "id" column still exists
1901
            $idColumn = true;
1902
            $columns = Database::listTableColumns($table_qui);
1903
            if (!in_array('id', array_keys($columns))) {
1904
                $idColumn = false;
1905
            }
1906
1907
            foreach ($resources[RESOURCE_QUIZ] as $id => $quiz) {
1908
                if (isset($quiz->obj)) {
1909
                    // For new imports
1910
                    $quiz = $quiz->obj;
1911
                } else {
1912
                    // For backward compatibility
1913
                    $quiz->obj = $quiz;
1914
                }
1915
1916
                $doc = '';
1917
                if (!empty($quiz->sound)) {
1918
                    if (isset($this->course->resources[RESOURCE_DOCUMENT][$quiz->sound]) &&
1919
                        $this->course->resources[RESOURCE_DOCUMENT][$quiz->sound]->is_restored()) {
1920
                        $sql = "SELECT path FROM $table_doc
1921
                                WHERE
1922
                                    c_id = ".$this->destination_course_id." AND
1923
                                    id = ".$resources[RESOURCE_DOCUMENT][$quiz->sound]->destination_id;
1924
                        $doc = Database::query($sql);
1925
                        $doc = Database::fetch_object($doc);
1926
                        $doc = str_replace('/audio/', '', $doc->path);
1927
                    }
1928
                }
1929
1930
                if ($id != -1) {
1931
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
1932
                    $quiz->description = DocumentManager::replaceUrlWithNewCourseCode(
1933
                        $quiz->description,
1934
                        $this->course->code,
1935
                        $this->course->destination_path,
1936
                        $this->course->backup_path,
1937
                        $this->course->info['path']
1938
                    );
1939
1940
                    $quiz->start_time = $quiz->start_time == '0000-00-00 00:00:00' ? null : $quiz->start_time;
1941
                    $quiz->end_time = $quiz->end_time == '0000-00-00 00:00:00' ? null : $quiz->end_time;
1942
1943
                    global $_custom;
1944
                    if (isset($_custom['exercises_clean_dates_when_restoring']) &&
1945
                        $_custom['exercises_clean_dates_when_restoring']
1946
                    ) {
1947
                        $quiz->start_time = null;
1948
                        $quiz->end_time = null;
1949
                    }
1950
1951
                    $params = [
1952
                        'c_id' => $this->destination_course_id,
1953
                        'title' => self::DBUTF8($quiz->title),
1954
                        'description' => ($quiz->description === false ? '' : self::DBUTF8($quiz->description)),
1955
                        'type' => isset($quiz->quiz_type) ? (int) $quiz->quiz_type : $quiz->type,
1956
                        'random' => (int) $quiz->random,
1957
                        'active' => $quiz->active,
1958
                        'sound' => self::DBUTF8($doc),
1959
                        'max_attempt' => (int) $quiz->max_attempt,
1960
                        'results_disabled' => (int) $quiz->results_disabled,
1961
                        'access_condition' => $quiz->access_condition,
1962
                        'pass_percentage' => $quiz->pass_percentage,
1963
                        'feedback_type' => (int) $quiz->feedback_type,
1964
                        'random_answers' => (int) $quiz->random_answers,
1965
                        'random_by_category' => (int) $quiz->random_by_category,
1966
                        'review_answers' => (int) $quiz->review_answers,
1967
                        'propagate_neg' => (int) $quiz->propagate_neg,
1968
                        'text_when_finished' => (string) $quiz->text_when_finished,
1969
                        'expired_time' => (int) $quiz->expired_time,
1970
                        'start_time' => $quiz->start_time,
1971
                        'end_time' => $quiz->end_time,
1972
                        'display_category_name' => 0,
1973
                        'save_correct_answers' => isset($quiz->save_correct_answers) ? $quiz->save_correct_answers : 0,
1974
                        'hide_question_title' => isset($quiz->hide_question_title) ? $quiz->hide_question_title : 0,
1975
                    ];
1976
1977
                    $allow = api_get_configuration_value('allow_notification_setting_per_exercise');
1978
                    if ($allow) {
1979
                        $params['notifications'] = isset($quiz->notifications) ? $quiz->notifications : '';
1980
                    }
1981
1982
                    if ($respect_base_content) {
1983
                        $my_session_id = $quiz->session_id;
1984
                        if (!empty($quiz->session_id)) {
1985
                            $my_session_id = $session_id;
1986
                        }
1987
                        $params['session_id'] = $my_session_id;
1988
                    } else {
1989
                        if (!empty($session_id)) {
1990
                            $session_id = (int) $session_id;
1991
                            $params['session_id'] = $session_id;
1992
                        }
1993
                    }
1994
                    $new_id = Database::insert($table_qui, $params);
1995
1996
                    if ($new_id && $idColumn) {
1997
                        $sql = "UPDATE $table_qui SET id = iid WHERE iid = $new_id";
1998
                        Database::query($sql);
1999
                    }
2000
                } else {
2001
                    // $id = -1 identifies the fictional test for collecting
2002
                    // orphan questions. We do not store it in the database.
2003
                    $new_id = -1;
2004
                }
2005
2006
                $this->course->resources[RESOURCE_QUIZ][$id]->destination_id = $new_id;
2007
                $order = 0;
2008
                if (!empty($quiz->question_ids)) {
2009
                    foreach ($quiz->question_ids as $index => $question_id) {
2010
                        $qid = $this->restore_quiz_question($question_id, $idColumn);
2011
                        $question_order = $quiz->question_orders[$index] ? $quiz->question_orders[$index] : ++$order;
2012
                        $sql = "INSERT IGNORE INTO $table_rel SET
2013
                                c_id = ".$this->destination_course_id.",
2014
                                question_id = $qid ,
2015
                                exercice_id = $new_id ,
2016
                                question_order = ".$question_order;
2017
                        Database::query($sql);
2018
                    }
2019
                }
2020
            }
2021
        }
2022
    }
2023
2024
    /**
2025
     * Restore quiz-questions.
2026
     *
2027
     * @param int  $id       Question id
2028
     * @param bool $idColumn Whether the 'id' column still exists in this table
2029
     */
2030
    public function restore_quiz_question($id, $idColumn = true)
2031
    {
2032
        $em = Database::getManager();
2033
        $resources = $this->course->resources;
2034
        /** @var QuizQuestion $question */
2035
        $question = isset($resources[RESOURCE_QUIZQUESTION][$id]) ? $resources[RESOURCE_QUIZQUESTION][$id] : null;
2036
        $new_id = 0;
2037
2038
        if (is_object($question)) {
2039
            if ($question->is_restored()) {
2040
                return $question->destination_id;
2041
            }
2042
            $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION);
2043
            $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER);
2044
            $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
2045
2046
            // check resources inside html from ckeditor tool and copy correct urls into recipient course
2047
            $question->description = DocumentManager::replaceUrlWithNewCourseCode(
2048
                $question->description,
2049
                $this->course->code,
2050
                $this->course->destination_path,
2051
                $this->course->backup_path,
2052
                $this->course->info['path']
2053
            );
2054
2055
            $imageNewId = '';
2056
            if (preg_match('/^quiz-.*$/', $question->picture) &&
2057
                isset($resources[RESOURCE_DOCUMENT]['image_quiz'][$question->picture])
2058
            ) {
2059
                $imageNewId = $resources[RESOURCE_DOCUMENT]['image_quiz'][$question->picture]['destination_id'];
2060
            } else {
2061
                if (isset($resources[RESOURCE_DOCUMENT][$question->picture])) {
2062
                    $documentsToRestore = $resources[RESOURCE_DOCUMENT][$question->picture];
2063
                    $imageNewId = $documentsToRestore->destination_id;
2064
                }
2065
            }
2066
            $question->question = DocumentManager::replaceUrlWithNewCourseCode(
2067
                $question->question,
2068
                $this->course->code,
2069
                $this->course->destination_path,
2070
                $this->course->backup_path,
2071
                $this->course->info['path']
2072
            );
2073
            $params = [
2074
                'c_id' => $this->destination_course_id,
2075
                'question' => self::DBUTF8($question->question),
2076
                'description' => ($question->description === false ? '' : self::DBUTF8($question->description)),
2077
                'ponderation' => self::DBUTF8($question->ponderation),
2078
                'position' => self::DBUTF8($question->position),
2079
                'type' => self::DBUTF8($question->quiz_type),
2080
                'picture' => self::DBUTF8($imageNewId),
2081
                'level' => self::DBUTF8($question->level),
2082
                'extra' => self::DBUTF8($question->extra),
2083
            ];
2084
2085
            $new_id = Database::insert($table_que, $params);
2086
2087
            if ($new_id) {
2088
                // If the ID column is still present, update it, otherwise just
2089
                // continue
2090
                if ($idColumn) {
2091
                    $sql = "UPDATE $table_que SET id = iid WHERE iid = $new_id";
2092
                    Database::query($sql);
2093
                }
2094
            } else {
2095
                // If no IID was generated, stop right there and return 0
2096
                return 0;
2097
            }
2098
2099
            $correctAnswers = [];
2100
            $allAnswers = [];
2101
            $onlyAnswers = [];
2102
2103
            if (in_array($question->quiz_type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
2104
                $tempAnswerList = $question->answers;
2105
                foreach ($tempAnswerList as &$value) {
2106
                    $value['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
2107
                        $value['answer'],
2108
                        $this->course->code,
2109
                        $this->course->destination_path,
2110
                        $this->course->backup_path,
2111
                        $this->course->info['path']
2112
                    );
2113
                }
2114
                $allAnswers = array_column($tempAnswerList, 'answer', 'id');
2115
            }
2116
2117
            if (in_array($question->quiz_type, [MATCHING, MATCHING_DRAGGABLE])) {
2118
                $temp = [];
2119
                foreach ($question->answers as $index => $answer) {
2120
                    $temp[$answer['position']] = $answer;
2121
                }
2122
2123
                foreach ($temp as $index => $answer) {
2124
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
2125
                    $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
2126
                        $answer['answer'],
2127
                        $this->course->code,
2128
                        $this->course->destination_path,
2129
                        $this->course->backup_path,
2130
                        $this->course->info['path']
2131
                    );
2132
2133
                    $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
2134
                        $answer['comment'],
2135
                        $this->course->code,
2136
                        $this->course->destination_path,
2137
                        $this->course->backup_path,
2138
                        $this->course->info['path']
2139
                    );
2140
2141
                    $quizAnswer = new CQuizAnswer();
2142
                    $quizAnswer
2143
                        ->setCId($this->destination_course_id)
2144
                        ->setQuestionId($new_id)
2145
                        ->setAnswer(self::DBUTF8($answer['answer']))
2146
                        ->setCorrect($answer['correct'])
2147
                        ->setComment($answer['comment'] === false ? '' : self::DBUTF8($answer['comment']))
2148
                        ->setPonderation($answer['ponderation'])
2149
                        ->setPosition($answer['position'])
2150
                        ->setHotspotCoordinates($answer['hotspot_coordinates'])
2151
                        ->setHotspotType($answer['hotspot_type'])
2152
                        ->setIdAuto(0);
2153
2154
                    $em->persist($quizAnswer);
2155
                    $em->flush();
2156
2157
                    $answerId = $quizAnswer->getId();
2158
2159
                    if ($answerId) {
2160
                        $quizAnswer
2161
                            ->setId($answerId)
2162
                            ->setIdAuto($answerId);
2163
                        $em->merge($quizAnswer);
2164
                        $em->flush();
2165
2166
                        $correctAnswers[$answerId] = $answer['correct'];
2167
                        $onlyAnswers[$answerId] = $answer['answer'];
2168
                    }
2169
                }
2170
            } else {
2171
                foreach ($question->answers as $index => $answer) {
2172
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
2173
                    $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
2174
                        $answer['answer'],
2175
                        $this->course->code,
2176
                        $this->course->destination_path,
2177
                        $this->course->backup_path,
2178
                        $this->course->info['path']
2179
                    );
2180
2181
                    $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
2182
                        $answer['comment'],
2183
                        $this->course->code,
2184
                        $this->course->destination_path,
2185
                        $this->course->backup_path,
2186
                        $this->course->info['path']
2187
                    );
2188
2189
                    $params = [
2190
                        'c_id' => $this->destination_course_id,
2191
                        'question_id' => $new_id,
2192
                        'answer' => self::DBUTF8($answer['answer']),
2193
                        'correct' => $answer['correct'],
2194
                        'comment' => ($answer['comment'] === false ? '' : self::DBUTF8($answer['comment'])),
2195
                        'ponderation' => $answer['ponderation'],
2196
                        'position' => $answer['position'],
2197
                        'hotspot_coordinates' => $answer['hotspot_coordinates'],
2198
                        'hotspot_type' => $answer['hotspot_type'],
2199
                        'id_auto' => 0,
2200
                        'destination' => '',
2201
                    ];
2202
2203
                    $answerId = Database::insert($table_ans, $params);
2204
2205
                    if ($answerId) {
2206
                        if ($idColumn) {
2207
                            $sql = "UPDATE $table_ans SET id = iid, id_auto = iid WHERE iid = $answerId";
2208
                            Database::query($sql);
2209
                        } else {
2210
                            $sql = "UPDATE $table_ans SET id_auto = iid WHERE iid = $answerId";
2211
                            Database::query($sql);
2212
                        }
2213
                    }
2214
2215
                    $correctAnswers[$answerId] = $answer['correct'];
2216
                    $onlyAnswers[$answerId] = $answer['answer'];
2217
                }
2218
            }
2219
2220
            // Current course id
2221
            $course_id = api_get_course_int_id();
2222
2223
            // Moving quiz_question_options
2224
            if ($question->quiz_type == MULTIPLE_ANSWER_TRUE_FALSE) {
2225
                if (count($question->question_options) < 3) {
2226
                    $options = [1 => 'True', 2 => 'False', 3 => 'DoubtScore'];
2227
                    $correct = [];
2228
                    for ($i = 1; $i <= 3; $i++) {
2229
                        $lastId = Question::saveQuestionOption(
2230
                            $new_id,
2231
                            $options[$i],
2232
                            $this->destination_course_id,
2233
                            $i
2234
                        );
2235
                        $correct[$i] = $lastId;
2236
                    }
2237
2238
                    $correctAnswerValues = Database::select(
2239
                        'DISTINCT(correct)',
2240
                        $table_ans,
2241
                        [
2242
                            'WHERE' => [
2243
                                'question_id = ? AND c_id = ? ' => [
2244
                                    $new_id,
2245
                                    $this->destination_course_id,
2246
                                ],
2247
                            ],
2248
                            'ORDER' => 'correct ASC',
2249
                        ]
2250
                    );
2251
                    $i = 1;
2252
                    foreach ($correctAnswerValues as $correctAnswer) {
2253
                        $params = [];
2254
                        $params['correct'] = $correct[$i];
2255
                        Database::update(
2256
                            $table_ans,
2257
                            $params,
2258
                            [
2259
                                'question_id = ? AND c_id = ? AND correct = ? ' => [
2260
                                    $new_id,
2261
                                    $this->destination_course_id,
2262
                                    $correctAnswer['correct'],
2263
                                ],
2264
                            ],
2265
                            false
2266
                        );
2267
                        $i++;
2268
                    }
2269
                } else {
2270
                    $question_option_list = Question::readQuestionOption($id, $course_id);
2271
2272
                    // Question copied from the current platform
2273
                    if ($question_option_list) {
2274
                        $old_option_ids = [];
2275
                        foreach ($question_option_list as $item) {
2276
                            if (isset($item['iid'])) {
2277
                                $old_id = $item['iid'];
2278
                                unset($item['iid']);
2279
                                unset($item['id']);
2280
                            } else {
2281
                                $old_id = $item['id'];
2282
                                unset($item['id']);
2283
                            }
2284
                            $item['question_id'] = $new_id;
2285
                            $item['c_id'] = $this->destination_course_id;
2286
                            $question_option_id = Database::insert($table_options, $item);
2287
                            if ($question_option_id && $idColumn) {
2288
                                $old_option_ids[$old_id] = $question_option_id;
2289
                                $sql = "UPDATE $table_options SET id = iid WHERE iid = $question_option_id";
2290
                                Database::query($sql);
2291
                            }
2292
                        }
2293
                        if ($old_option_ids) {
2294
                            $new_answers = Database::select(
2295
                                'iid, correct',
2296
                                $table_ans,
2297
                                [
2298
                                    'WHERE' => [
2299
                                        'question_id = ? AND c_id = ? ' => [
2300
                                            $new_id,
2301
                                            $this->destination_course_id,
2302
                                        ],
2303
                                    ],
2304
                                ]
2305
                            );
2306
2307
                            foreach ($new_answers as $answer_item) {
2308
                                $params = [];
2309
                                $params['correct'] = $old_option_ids[$answer_item['correct']];
2310
                                Database::update(
2311
                                    $table_ans,
2312
                                    $params,
2313
                                    [
2314
                                        'iid = ? AND c_id = ? AND question_id = ? ' => [
2315
                                            $answer_item['iid'],
2316
                                            $this->destination_course_id,
2317
                                            $new_id,
2318
                                        ],
2319
                                    ],
2320
                                    false
2321
                                );
2322
                            }
2323
                        }
2324
                    } else {
2325
                        $new_options = [];
2326
                        if (isset($question->question_options)) {
2327
                            foreach ($question->question_options as $obj) {
2328
                                $item = [];
2329
                                $item['question_id'] = $new_id;
2330
                                $item['c_id'] = $this->destination_course_id;
2331
                                $item['name'] = $obj->obj->name;
2332
                                $item['position'] = $obj->obj->position;
2333
                                $question_option_id = Database::insert($table_options, $item);
2334
2335
                                if ($question_option_id) {
2336
                                    $new_options[$obj->obj->id] = $question_option_id;
2337
                                    $sql = "UPDATE $table_options SET id = iid WHERE iid = $question_option_id";
2338
                                    Database::query($sql);
2339
                                }
2340
                            }
2341
2342
                            foreach ($correctAnswers as $answer_id => $correct_answer) {
2343
                                $params = [];
2344
                                $params['correct'] = isset($new_options[$correct_answer]) ? $new_options[$correct_answer] : '';
2345
                                Database::update(
2346
                                    $table_ans,
2347
                                    $params,
2348
                                    [
2349
                                        'iid = ? AND c_id = ? AND question_id = ? ' => [
2350
                                            $answer_id,
2351
                                            $this->destination_course_id,
2352
                                            $new_id,
2353
                                        ],
2354
                                    ],
2355
                                    false
2356
                                );
2357
                            }
2358
                        }
2359
                    }
2360
                }
2361
            }
2362
2363
            // Fix correct answers
2364
            if (in_array($question->quiz_type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
2365
                foreach ($correctAnswers as $answer_id => $correct_answer) {
2366
                    $params = [];
2367
2368
                    if (isset($allAnswers[$correct_answer])) {
2369
                        $correct = '';
2370
                        foreach ($onlyAnswers as $key => $value) {
2371
                            if ($value == $allAnswers[$correct_answer]) {
2372
                                $correct = $key;
2373
                                break;
2374
                            }
2375
                        }
2376
2377
                        $params['correct'] = $correct;
2378
                        Database::update(
2379
                            $table_ans,
2380
                            $params,
2381
                            [
2382
                                'iid = ? AND c_id = ? AND question_id = ? ' => [
2383
                                    $answer_id,
2384
                                    $this->destination_course_id,
2385
                                    $new_id,
2386
                                ],
2387
                            ]
2388
                        );
2389
                    }
2390
                }
2391
            }
2392
2393
            $this->course->resources[RESOURCE_QUIZQUESTION][$id]->destination_id = $new_id;
2394
        }
2395
2396
        return $new_id;
2397
    }
2398
2399
    /**
2400
     * @todo : add session id when used for session
2401
     */
2402
    public function restore_test_category($session_id, $respect_base_content, $destination_course_code)
2403
    {
2404
        // Cannot restore a test category to a session.
2405
        if (!empty($session_id)) {
2406
            return false;
2407
        }
2408
2409
        $destinationCourseId = $this->destination_course_info['real_id'];
2410
        // Let's restore the categories
2411
        $categoryOldVsNewList = []; // used to build the quiz_question_rel_category table
2412
        if ($this->course->has_resources(RESOURCE_TEST_CATEGORY)) {
2413
            $resources = $this->course->resources;
2414
            foreach ($resources[RESOURCE_TEST_CATEGORY] as $id => $courseCopyTestCategory) {
2415
                $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $id;
2416
                // check if this test_category already exist in the destination BDD
2417
                // do not Database::escape_string $title and $description, it will be done later
2418
                $title = $courseCopyTestCategory->title;
2419
                $description = $courseCopyTestCategory->description;
2420
                if (TestCategory::categoryTitleExists($title, $destinationCourseId)) {
2421
                    switch ($this->file_option) {
2422
                        case FILE_SKIP:
2423
                            //Do nothing
2424
                            break;
2425
                        case FILE_RENAME:
2426
                            $new_title = $title.'_';
2427
                            while (TestCategory::categoryTitleExists($new_title, $destinationCourseId)) {
2428
                                $new_title .= '_';
2429
                            }
2430
                            $test_category = new TestCategory();
2431
                            $test_category->name = $new_title;
2432
                            $test_category->description = $description;
2433
                            $new_id = $test_category->save($destinationCourseId);
2434
                            $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $new_id;
2435
                            break;
2436
                        case FILE_OVERWRITE:
2437
                            // get category from source
2438
                            $destinationCategoryId = TestCategory::get_category_id_for_title(
2439
                                $title,
2440
                                $destinationCourseId
2441
                            );
2442
                            if ($destinationCategoryId) {
2443
                                $my_cat = new TestCategory();
2444
                                $my_cat = $my_cat->getCategory($destinationCategoryId, $destinationCourseId);
2445
                                $my_cat->name = $title;
2446
                                $my_cat->description = $description;
2447
                                $my_cat->modifyCategory($destinationCourseId);
2448
                                $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $destinationCategoryId;
2449
                            }
2450
                            break;
2451
                    }
2452
                } else {
2453
                    // create a new test_category
2454
                    $test_category = new TestCategory();
2455
                    $test_category->name = $title;
2456
                    $test_category->description = $description;
2457
                    $new_id = $test_category->save($destinationCourseId);
2458
                    $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $new_id;
2459
                }
2460
                $this->course->resources[RESOURCE_TEST_CATEGORY][$id]->destination_id = $categoryOldVsNewList[$courseCopyTestCategory->source_id];
2461
            }
2462
        }
2463
2464
        // lets check if quizzes-question are restored too,
2465
        // to redo the link between test_category and quizzes question for questions restored
2466
        // we can use the source_id field
2467
        // question source_id => category source_id
2468
        if ($this->course->has_resources(RESOURCE_QUIZQUESTION)) {
2469
            // check the category number of each question restored
2470
            if (!empty($resources[RESOURCE_QUIZQUESTION])) {
2471
                foreach ($resources[RESOURCE_QUIZQUESTION] as $id => $courseCopyQuestion) {
2472
                    $newQuestionId = $resources[RESOURCE_QUIZQUESTION][$id]->destination_id;
2473
                    $questionCategoryId = $courseCopyQuestion->question_category;
2474
                    if ($newQuestionId > 0 &&
2475
                        $questionCategoryId > 0 &&
2476
                        isset($categoryOldVsNewList[$questionCategoryId])
2477
                    ) {
2478
                        TestCategory::addCategoryToQuestion(
2479
                            $categoryOldVsNewList[$questionCategoryId],
2480
                            $newQuestionId,
2481
                            $destinationCourseId
2482
                        );
2483
                    }
2484
                }
2485
            }
2486
        }
2487
    }
2488
2489
    /**
2490
     * Restore surveys.
2491
     *
2492
     * @param int $sessionId Optional. The session id
2493
     */
2494
    public function restore_surveys($sessionId = 0)
2495
    {
2496
        $sessionId = (int) $sessionId;
2497
        if ($this->course->has_resources(RESOURCE_SURVEY)) {
2498
            $table_sur = Database::get_course_table(TABLE_SURVEY);
2499
            $table_que = Database::get_course_table(TABLE_SURVEY_QUESTION);
2500
            $table_ans = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2501
            $resources = $this->course->resources;
2502
            foreach ($resources[RESOURCE_SURVEY] as $id => $survey) {
2503
                $sql = 'SELECT survey_id FROM '.$table_sur.'
2504
                        WHERE
2505
                            c_id = '.$this->destination_course_id.' AND
2506
                            code = "'.self::DBUTF8escapestring($survey->code).'" AND
2507
                            lang = "'.self::DBUTF8escapestring($survey->lang).'" ';
2508
2509
                $result_check = Database::query($sql);
2510
2511
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
2512
                $survey->title = DocumentManager::replaceUrlWithNewCourseCode(
2513
                    $survey->title,
2514
                    $this->course->code,
2515
                    $this->course->destination_path,
2516
                    $this->course->backup_path,
2517
                    $this->course->info['path']
2518
                );
2519
2520
                $survey->subtitle = DocumentManager::replaceUrlWithNewCourseCode(
2521
                    $survey->subtitle,
2522
                    $this->course->code,
2523
                    $this->course->destination_path,
2524
                    $this->course->backup_path,
2525
                    $this->course->info['path']
2526
                );
2527
2528
                $survey->intro = DocumentManager::replaceUrlWithNewCourseCode(
2529
                    $survey->intro,
2530
                    $this->course->code,
2531
                    $this->course->destination_path,
2532
                    $this->course->backup_path,
2533
                    $this->course->info['path']
2534
                );
2535
2536
                $survey->surveythanks = DocumentManager::replaceUrlWithNewCourseCode(
2537
                    $survey->surveythanks,
2538
                    $this->course->code,
2539
                    $this->course->destination_path,
2540
                    $this->course->backup_path,
2541
                    $this->course->info['path']
2542
                );
2543
2544
                $params = [
2545
                    'c_id' => $this->destination_course_id,
2546
                    'code' => self::DBUTF8($survey->code),
2547
                    'title' => ($survey->title === false ? '' : self::DBUTF8($survey->title)),
2548
                    'subtitle' => ($survey->subtitle === false ? '' : self::DBUTF8($survey->subtitle)),
2549
                    'author' => self::DBUTF8($survey->author),
2550
                    'lang' => self::DBUTF8($survey->lang),
2551
                    'avail_from' => self::DBUTF8($survey->avail_from),
2552
                    'avail_till' => self::DBUTF8($survey->avail_till),
2553
                    'is_shared' => self::DBUTF8($survey->is_shared),
2554
                    'template' => self::DBUTF8($survey->template),
2555
                    'intro' => $survey->intro === false ? '' : self::DBUTF8($survey->intro),
2556
                    'surveythanks' => $survey->surveythanks === false ? '' : self::DBUTF8($survey->surveythanks),
2557
                    'creation_date' => self::DBUTF8($survey->creation_date),
2558
                    'invited' => '0',
2559
                    'answered' => '0',
2560
                    'invite_mail' => self::DBUTF8($survey->invite_mail),
2561
                    'reminder_mail' => self::DBUTF8($survey->reminder_mail),
2562
                    'session_id' => $sessionId,
2563
                    'one_question_per_page' => isset($survey->one_question_per_page) ? $survey->one_question_per_page : 0,
2564
                    'shuffle' => isset($survey->suffle) ? $survey->suffle : 0,
2565
                ];
2566
2567
                // An existing survey exists with the same code and the same language
2568
                if (Database::num_rows($result_check) == 1) {
2569
                    switch ($this->file_option) {
2570
                        case FILE_SKIP:
2571
                            //Do nothing
2572
                            break;
2573
                        case FILE_RENAME:
2574
                            $survey_code = $survey->code.'_';
2575
                            $i = 1;
2576
                            $temp_survey_code = $survey_code.$i;
2577
                            while (!$this->is_survey_code_available($temp_survey_code)) {
2578
                                $temp_survey_code = $survey_code.++$i;
2579
                            }
2580
                            $survey_code = $temp_survey_code;
2581
2582
                            $params['code'] = $survey_code;
2583
                            $new_id = Database::insert($table_sur, $params);
2584
                            if ($new_id) {
2585
                                $sql = "UPDATE $table_sur SET survey_id = iid WHERE iid = $new_id";
2586
                                Database::query($sql);
2587
2588
                                $this->course->resources[RESOURCE_SURVEY][$id]->destination_id = $new_id;
2589
                                foreach ($survey->question_ids as $index => $question_id) {
2590
                                    $qid = $this->restore_survey_question($question_id, $new_id);
2591
                                    $sql = "UPDATE $table_que SET survey_id = $new_id
2592
                                            WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2593
                                    Database::query($sql);
2594
                                    $sql = "UPDATE $table_ans SET survey_id = $new_id
2595
                                            WHERE  c_id = ".$this->destination_course_id." AND  question_id = $qid";
2596
                                    Database::query($sql);
2597
                                }
2598
                            }
2599
                            break;
2600
                        case FILE_OVERWRITE:
2601
                            // Delete the existing survey with the same code and language and
2602
                            // import the one of the source course
2603
                            // getting the information of the survey (used for when the survey is shared)
2604
                            $sql = "SELECT * FROM $table_sur
2605
                                    WHERE
2606
                                        c_id = ".$this->destination_course_id." AND
2607
                                        survey_id='".self::DBUTF8escapestring(Database::result($result_check, 0, 0))."'";
2608
                            $result = Database::query($sql);
2609
                            $survey_data = Database::fetch_array($result, 'ASSOC');
2610
2611
                            // if the survey is shared => also delete the shared content
2612
                            if (isset($survey_data['survey_share']) && is_numeric($survey_data['survey_share'])) {
2613
                                SurveyManager::delete_survey(
2614
                                    $survey_data['survey_share'],
2615
                                    true,
2616
                                    $this->destination_course_id
2617
                                );
2618
                            }
2619
                            SurveyManager::delete_survey(
2620
                                $survey_data['survey_id'],
2621
                                false,
2622
                                $this->destination_course_id
2623
                            );
2624
2625
                            // Insert the new source survey
2626
                            $new_id = Database::insert($table_sur, $params);
2627
2628
                            if ($new_id) {
2629
                                $sql = "UPDATE $table_sur SET survey_id = iid WHERE iid = $new_id";
2630
                                Database::query($sql);
2631
2632
                                $this->course->resources[RESOURCE_SURVEY][$id]->destination_id = $new_id;
2633
                                foreach ($survey->question_ids as $index => $question_id) {
2634
                                    $qid = $this->restore_survey_question(
2635
                                        $question_id,
2636
                                        $new_id
2637
                                    );
2638
                                    $sql = "UPDATE $table_que SET survey_id = $new_id
2639
                                            WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2640
                                    Database::query($sql);
2641
                                    $sql = "UPDATE $table_ans SET survey_id = $new_id
2642
                                            WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2643
                                    Database::query($sql);
2644
                                }
2645
                            }
2646
                            break;
2647
                        default:
2648
                            break;
2649
                    }
2650
                } else {
2651
                    // No existing survey with the same language and the same code, we just copy the survey
2652
                    $new_id = Database::insert($table_sur, $params);
2653
2654
                    if ($new_id) {
2655
                        $sql = "UPDATE $table_sur SET survey_id = iid WHERE iid = $new_id";
2656
                        Database::query($sql);
2657
2658
                        $this->course->resources[RESOURCE_SURVEY][$id]->destination_id = $new_id;
2659
                        foreach ($survey->question_ids as $index => $question_id) {
2660
                            $qid = $this->restore_survey_question(
2661
                                $question_id,
2662
                                $new_id
2663
                            );
2664
                            $sql = "UPDATE $table_que SET survey_id = $new_id
2665
                                    WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2666
                            Database::query($sql);
2667
                            $sql = "UPDATE $table_ans SET survey_id = $new_id
2668
                                    WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2669
                            Database::query($sql);
2670
                        }
2671
                    }
2672
                }
2673
            }
2674
        }
2675
    }
2676
2677
    /**
2678
     * Check availability of a survey code.
2679
     *
2680
     * @param string $survey_code
2681
     *
2682
     * @return bool
2683
     */
2684
    public function is_survey_code_available($survey_code)
2685
    {
2686
        $table_sur = Database::get_course_table(TABLE_SURVEY);
2687
        $sql = "SELECT * FROM $table_sur
2688
                WHERE
2689
                    c_id = ".$this->destination_course_id." AND
2690
                    code = '".self::DBUTF8escapestring($survey_code)."'";
2691
        $result = Database::query($sql);
2692
        if (Database::num_rows($result) > 0) {
2693
            return false;
2694
        } else {
2695
            return true;
2696
        }
2697
    }
2698
2699
    /**
2700
     * Restore survey-questions.
2701
     *
2702
     * @param int    $id
2703
     * @param string $survey_id
2704
     */
2705
    public function restore_survey_question($id, $survey_id)
2706
    {
2707
        $resources = $this->course->resources;
2708
        $question = $resources[RESOURCE_SURVEYQUESTION][$id];
2709
        $new_id = 0;
2710
2711
        if (is_object($question)) {
2712
            if ($question->is_restored()) {
2713
                return $question->destination_id;
2714
            }
2715
            $table_que = Database::get_course_table(TABLE_SURVEY_QUESTION);
2716
            $table_ans = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2717
2718
            // check resources inside html from ckeditor tool and copy correct urls into recipient course
2719
            $question->survey_question = DocumentManager::replaceUrlWithNewCourseCode(
2720
                $question->survey_question,
2721
                $this->course->code,
2722
                $this->course->destination_path,
2723
                $this->course->backup_path,
2724
                $this->course->info['path']
2725
            );
2726
2727
            $params = [
2728
                'c_id' => $this->destination_course_id,
2729
                'survey_id' => self::DBUTF8($survey_id),
2730
                'survey_question' => ($question->survey_question === false ? '' : self::DBUTF8($question->survey_question)),
2731
                'survey_question_comment' => self::DBUTF8($question->survey_question_comment),
2732
                'type' => self::DBUTF8($question->survey_question_type),
2733
                'display' => self::DBUTF8($question->display),
2734
                'sort' => self::DBUTF8($question->sort),
2735
                'shared_question_id' => self::DBUTF8($question->shared_question_id),
2736
                'max_value' => self::DBUTF8($question->max_value),
2737
            ];
2738
            if (api_get_configuration_value('allow_required_survey_questions')) {
2739
                if (isset($question->is_required)) {
2740
                    $params['is_required'] = $question->is_required;
2741
                }
2742
            }
2743
2744
            $new_id = Database::insert($table_que, $params);
2745
            if ($new_id) {
2746
                $sql = "UPDATE $table_que SET question_id = iid WHERE iid = $new_id";
2747
                Database::query($sql);
2748
2749
                foreach ($question->answers as $index => $answer) {
2750
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
2751
                    $answer['option_text'] = DocumentManager::replaceUrlWithNewCourseCode(
2752
                        $answer['option_text'],
2753
                        $this->course->code,
2754
                        $this->course->destination_path,
2755
                        $this->course->backup_path,
2756
                        $this->course->info['path']
2757
                    );
2758
2759
                    $params = [
2760
                        'c_id' => $this->destination_course_id,
2761
                        'question_id' => $new_id,
2762
                        'option_text' => ($answer['option_text'] === false ? '' : self::DBUTF8($answer['option_text'])),
2763
                        'sort' => $answer['sort'],
2764
                        'survey_id' => self::DBUTF8($survey_id),
2765
                    ];
2766
                    $answerId = Database::insert($table_ans, $params);
2767
                    if ($answerId) {
2768
                        $sql = "UPDATE $table_ans SET question_option_id = iid
2769
                                WHERE iid = $answerId";
2770
                        Database::query($sql);
2771
                    }
2772
                }
2773
                $this->course->resources[RESOURCE_SURVEYQUESTION][$id]->destination_id = $new_id;
2774
            }
2775
        }
2776
2777
        return $new_id;
2778
    }
2779
2780
    /**
2781
     * @param int  $sessionId
2782
     * @param bool $baseContent
2783
     */
2784
    public function restore_learnpath_category($sessionId = 0, $baseContent = false)
2785
    {
2786
        $reuseExisting = false;
2787
2788
        if (isset($this->tool_copy_settings['learnpath_category']) &&
2789
            isset($this->tool_copy_settings['learnpath_category']['reuse_existing']) &&
2790
            true === $this->tool_copy_settings['learnpath_category']['reuse_existing']
2791
        ) {
2792
            $reuseExisting = true;
2793
        }
2794
2795
        $tblLpCategory = Database::get_course_table(TABLE_LP_CATEGORY);
2796
2797
        if ($this->course->has_resources(RESOURCE_LEARNPATH_CATEGORY)) {
2798
            $resources = $this->course->resources;
2799
            /** @var LearnPathCategory $item */
2800
            foreach ($resources[RESOURCE_LEARNPATH_CATEGORY] as $id => $item) {
2801
                /** @var CLpCategory $lpCategory */
2802
                $lpCategory = $item->object;
2803
2804
                if ($lpCategory) {
2805
                    $existingLpCategory = Database::select(
2806
                        'iid',
2807
                        $tblLpCategory,
2808
                        [
2809
                            'WHERE' => [
2810
                                'c_id = ? AND name = ?' => [$this->destination_course_id, $lpCategory->getName()],
2811
                            ],
2812
                        ],
2813
                        'first'
2814
                    );
2815
2816
                    if ($reuseExisting && !empty($existingLpCategory)) {
2817
                        $categoryId = $existingLpCategory['iid'];
2818
                    } else {
2819
                        $values = [
2820
                            'c_id' => $this->destination_course_id,
2821
                            'name' => $lpCategory->getName(),
2822
                        ];
2823
                        $categoryId = \learnpath::createCategory($values);
2824
                    }
2825
2826
                    if ($categoryId) {
2827
                        $this->course->resources[RESOURCE_LEARNPATH_CATEGORY][$id]->destination_id = $categoryId;
2828
                    }
2829
                }
2830
            }
2831
        }
2832
    }
2833
2834
    /**
2835
     * Restoring learning paths.
2836
     *
2837
     * @param int        $session_id
2838
     * @param bool|false $respect_base_content
2839
     */
2840
    public function restore_learnpaths($session_id = 0, $respect_base_content = false)
2841
    {
2842
        $session_id = (int) $session_id;
2843
        if ($this->course->has_resources(RESOURCE_LEARNPATH)) {
2844
            $table_main = Database::get_course_table(TABLE_LP_MAIN);
2845
            $table_item = Database::get_course_table(TABLE_LP_ITEM);
2846
            $table_tool = Database::get_course_table(TABLE_TOOL_LIST);
2847
2848
            $resources = $this->course->resources;
2849
            $origin_path = $this->course->backup_path.'/upload/learning_path/images/';
2850
            $destination_path = api_get_path(SYS_COURSE_PATH).
2851
                $this->course->destination_path.'/upload/learning_path/images/';
2852
2853
            // Choose default visibility
2854
            $toolVisibility = api_get_setting('tool_visible_by_default_at_creation');
2855
            $defaultLpVisibility = 'invisible';
2856
            if (isset($toolVisibility['learning_path']) && $toolVisibility['learning_path'] == 'true') {
2857
                $defaultLpVisibility = 'visible';
2858
            }
2859
2860
            $lpIds = [];
2861
            foreach ($resources[RESOURCE_LEARNPATH] as $id => $lp) {
2862
                $condition_session = '';
2863
                if (!empty($session_id)) {
2864
                    if ($respect_base_content) {
2865
                        $my_session_id = $lp->session_id;
2866
                        if (!empty($lp->session_id)) {
2867
                            $my_session_id = $session_id;
2868
                        }
2869
                        $condition_session = $my_session_id;
2870
                    } else {
2871
                        $session_id = (int) $session_id;
2872
                        $condition_session = $session_id;
2873
                    }
2874
                }
2875
2876
                // Adding the LP image
2877
                if (!empty($lp->preview_image)) {
2878
                    $new_filename = uniqid('').substr(
2879
                        $lp->preview_image,
2880
                        strlen($lp->preview_image) - 7,
2881
                        strlen($lp->preview_image)
2882
                    );
2883
2884
                    if (file_exists($origin_path.$lp->preview_image) &&
2885
                        !is_dir($origin_path.$lp->preview_image)
2886
                    ) {
2887
                        $copy_result = copy(
2888
                            $origin_path.$lp->preview_image,
2889
                            $destination_path.$new_filename
2890
                        );
2891
                        if ($copy_result) {
2892
                            $lp->preview_image = $new_filename;
2893
                            // Create 64 version from original
2894
                            $temp = new \Image($destination_path.$new_filename);
2895
                            $temp->resize(64);
2896
                            $pathInfo = pathinfo($new_filename);
2897
                            if ($pathInfo) {
2898
                                $filename = $pathInfo['filename'];
2899
                                $extension = $pathInfo['extension'];
2900
                                $temp->send_image($destination_path.'/'.$filename.'.64.'.$extension);
2901
                            }
2902
                        } else {
2903
                            $lp->preview_image = '';
2904
                        }
2905
                    }
2906
                }
2907
2908
                if ($this->add_text_in_items) {
2909
                    $lp->name = $lp->name.' '.get_lang('CopyLabelSuffix');
2910
                }
2911
2912
                if (isset($this->tool_copy_settings['learnpaths'])) {
2913
                    if (isset($this->tool_copy_settings['learnpaths']['reset_dates']) &&
2914
                        $this->tool_copy_settings['learnpaths']['reset_dates']
2915
                    ) {
2916
                        $lp->created_on = api_get_utc_datetime();
2917
                        $lp->modified_on = api_get_utc_datetime();
2918
                        $lp->publicated_on = null;
2919
                    }
2920
                }
2921
2922
                $lp->expired_on = isset($lp->expired_on) && $lp->expired_on === '0000-00-00 00:00:00' ? null : $lp->expired_on;
2923
                $lp->publicated_on = isset($lp->publicated_on) && $lp->publicated_on === '0000-00-00 00:00:00' ? null : $lp->publicated_on;
2924
2925
                if (isset($lp->categoryId)) {
2926
                    $lp->categoryId = (int) $lp->categoryId;
2927
                }
2928
2929
                $categoryId = 0;
2930
                if (!empty($lp->categoryId)) {
2931
                    if (isset($resources[RESOURCE_LEARNPATH_CATEGORY][$lp->categoryId])) {
2932
                        $categoryId = $resources[RESOURCE_LEARNPATH_CATEGORY][$lp->categoryId]->destination_id;
2933
                    }
2934
                }
2935
                $params = [
2936
                    'c_id' => $this->destination_course_id,
2937
                    'lp_type' => $lp->lp_type,
2938
                    'name' => self::DBUTF8($lp->name),
2939
                    'path' => self::DBUTF8($lp->path),
2940
                    'ref' => $lp->ref,
2941
                    'description' => self::DBUTF8($lp->description),
2942
                    'content_local' => self::DBUTF8($lp->content_local),
2943
                    'default_encoding' => self::DBUTF8($lp->default_encoding),
2944
                    'default_view_mod' => self::DBUTF8($lp->default_view_mod),
2945
                    'prevent_reinit' => self::DBUTF8($lp->prevent_reinit),
2946
                    'force_commit' => self::DBUTF8($lp->force_commit),
2947
                    'content_maker' => self::DBUTF8($lp->content_maker),
2948
                    'display_order' => self::DBUTF8($lp->display_order),
2949
                    'js_lib' => self::DBUTF8($lp->js_lib),
2950
                    'content_license' => self::DBUTF8($lp->content_license),
2951
                    'author' => self::DBUTF8($lp->author),
2952
                    'preview_image' => self::DBUTF8($lp->preview_image),
2953
                    'use_max_score' => self::DBUTF8($lp->use_max_score),
2954
                    'autolaunch' => self::DBUTF8(isset($lp->autolaunch) ? $lp->autolaunch : ''),
2955
                    'created_on' => empty($lp->created_on) ? api_get_utc_datetime() : self::DBUTF8($lp->created_on),
2956
                    'modified_on' => empty($lp->modified_on) ? api_get_utc_datetime() : self::DBUTF8($lp->modified_on),
2957
                    'publicated_on' => empty($lp->publicated_on) ? api_get_utc_datetime() : self::DBUTF8($lp->publicated_on),
2958
                    'expired_on' => self::DBUTF8($lp->expired_on),
2959
                    'debug' => self::DBUTF8($lp->debug),
2960
                    'theme' => '',
2961
                    'session_id' => $session_id,
2962
                    'prerequisite' => (int) $lp->prerequisite,
2963
                    'hide_toc_frame' => self::DBUTF8(isset($lp->hideTableOfContents) ? $lp->hideTableOfContents : 0),
2964
                    'subscribe_users' => self::DBUTF8(isset($lp->subscribeUsers) ? $lp->subscribeUsers : 0),
2965
                    'seriousgame_mode' => 0,
2966
                    'category_id' => $categoryId,
2967
                    'max_attempts' => 0,
2968
                ];
2969
2970
                if (api_get_configuration_value('lp_minimum_time')) {
2971
                    if (isset($lp->accumulateWorkTime) && !empty($lp->accumulateWorkTime)) {
2972
                        $params['accumulate_work_time'] = $lp->accumulateWorkTime;
2973
                    }
2974
                }
2975
2976
                if (!empty($condition_session)) {
2977
                    $params['session_id'] = $condition_session;
2978
                }
2979
2980
                $new_lp_id = Database::insert($table_main, $params);
2981
                if ($new_lp_id) {
2982
                    $lpIds[$id] = $new_lp_id;
2983
                    // The following only makes sense if a new LP was
2984
                    // created in the destination course
2985
                    $sql = "UPDATE $table_main SET id = iid WHERE iid = $new_lp_id";
2986
                    Database::query($sql);
2987
2988
                    if ($lp->visibility) {
2989
                        $params = [
2990
                            'c_id' => $this->destination_course_id,
2991
                            'name' => self::DBUTF8($lp->name),
2992
                            'link' => "lp/lp_controller.php?action=view&lp_id=$new_lp_id&id_session=$session_id",
2993
                            'image' => 'scormbuilder.gif',
2994
                            'visibility' => '0',
2995
                            'admin' => '0',
2996
                            'address' => 'squaregrey.gif',
2997
                            'session_id' => $session_id,
2998
                        ];
2999
                        $insertId = Database::insert($table_tool, $params);
3000
                        if ($insertId) {
3001
                            $sql = "UPDATE $table_tool SET id = iid WHERE iid = $insertId";
3002
                            Database::query($sql);
3003
                        }
3004
                    }
3005
3006
                    if (isset($lp->extraFields) && !empty($lp->extraFields)) {
3007
                        $extraFieldValue = new \ExtraFieldValue('lp');
3008
                        foreach ($lp->extraFields as $extraField) {
3009
                            $params = [
3010
                                'item_id' => $new_lp_id,
3011
                                'value' => $extraField['value'],
3012
                                'variable' => $extraField['variable'],
3013
                            ];
3014
                            $extraFieldValue->save($params);
3015
                        }
3016
                    }
3017
3018
                    api_item_property_update(
3019
                        $this->destination_course_info,
3020
                        TOOL_LEARNPATH,
3021
                        $new_lp_id,
3022
                        'LearnpathAdded',
3023
                        api_get_user_id(),
3024
                        0,
3025
                        0,
3026
                        0,
3027
                        0,
3028
                        $session_id
3029
                    );
3030
3031
                    // Set the new LP to visible
3032
                    api_item_property_update(
3033
                        $this->destination_course_info,
3034
                        TOOL_LEARNPATH,
3035
                        $new_lp_id,
3036
                        $defaultLpVisibility,
3037
                        api_get_user_id(),
3038
                        0,
3039
                        0,
3040
                        0,
3041
                        0,
3042
                        $session_id
3043
                    );
3044
3045
                    $new_item_ids = [];
3046
                    $parent_item_ids = [];
3047
                    $previous_item_ids = [];
3048
                    $next_item_ids = [];
3049
                    $old_prerequisite = [];
3050
                    $old_refs = [];
3051
                    $prerequisite_ids = [];
3052
3053
                    foreach ($lp->get_items() as $index => $item) {
3054
                        // we set the ref code here and then we update in a for loop
3055
                        $ref = $item['ref'];
3056
3057
                        // Dealing with path the same way as ref as some data has
3058
                        // been put into path when it's a local resource
3059
                        // Only fix the path for no scos
3060
                        if ($item['item_type'] === 'sco') {
3061
                            $path = $item['path'];
3062
                        } else {
3063
                            $path = $this->get_new_id($item['item_type'], $item['path']);
3064
                        }
3065
3066
                        $item['item_type'] = $item['item_type'] === 'dokeos_chapter' ? 'dir' : $item['item_type'];
3067
3068
                        $masteryScore = $item['mastery_score'];
3069
                        // If item is a chamilo quiz, then use the max score as mastery_score.
3070
                        if ($item['item_type'] === 'quiz') {
3071
                            if (empty($masteryScore)) {
3072
                                $masteryScore = $item['max_score'];
3073
                            }
3074
                        }
3075
3076
                        $prerequisiteMinScore = $item['prerequisite_min_score'] ?? null;
3077
                        $prerequisiteMaxScore = $item['prerequisite_max_score'] ?? null;
3078
3079
                        $params = [
3080
                            'c_id' => $this->destination_course_id,
3081
                            'lp_id' => self::DBUTF8($new_lp_id),
3082
                            'item_type' => self::DBUTF8($item['item_type']),
3083
                            'ref' => self::DBUTF8($ref),
3084
                            'path' => self::DBUTF8($path),
3085
                            'title' => self::DBUTF8($item['title']),
3086
                            'description' => self::DBUTF8($item['description']),
3087
                            'min_score' => self::DBUTF8($item['min_score']),
3088
                            'max_score' => self::DBUTF8($item['max_score']),
3089
                            'mastery_score' => self::DBUTF8($masteryScore),
3090
                            'prerequisite_min_score' => $prerequisiteMinScore,
3091
                            'prerequisite_max_score' => $prerequisiteMaxScore,
3092
                            'parent_item_id' => self::DBUTF8($item['parent_item_id']),
3093
                            'previous_item_id' => self::DBUTF8($item['previous_item_id']),
3094
                            'next_item_id' => self::DBUTF8($item['next_item_id']),
3095
                            'display_order' => self::DBUTF8($item['display_order']),
3096
                            'prerequisite' => self::DBUTF8($item['prerequisite']),
3097
                            'parameters' => self::DBUTF8($item['parameters']),
3098
                            'audio' => self::DBUTF8($item['audio']),
3099
                            'launch_data' => self::DBUTF8($item['launch_data']),
3100
                        ];
3101
3102
                        $new_item_id = Database::insert($table_item, $params);
3103
                        if ($new_item_id) {
3104
                            $sql = "UPDATE $table_item SET id = iid WHERE iid = $new_item_id";
3105
                            Database::query($sql);
3106
3107
                            //save a link between old and new item IDs
3108
                            $new_item_ids[$item['id']] = $new_item_id;
3109
                            //save a reference of items that need a parent_item_id refresh
3110
                            $parent_item_ids[$new_item_id] = $item['parent_item_id'];
3111
                            //save a reference of items that need a previous_item_id refresh
3112
                            $previous_item_ids[$new_item_id] = $item['previous_item_id'];
3113
                            //save a reference of items that need a next_item_id refresh
3114
                            $next_item_ids[$new_item_id] = $item['next_item_id'];
3115
3116
                            if (!empty($item['prerequisite'])) {
3117
                                if ($lp->lp_type == '2') {
3118
                                    // if is an sco
3119
                                    $old_prerequisite[$new_item_id] = $item['prerequisite'];
3120
                                } else {
3121
                                    $old_prerequisite[$new_item_id] = isset($new_item_ids[$item['prerequisite']]) ? $new_item_ids[$item['prerequisite']] : '';
3122
                                }
3123
                            }
3124
3125
                            if (!empty($ref)) {
3126
                                if ($lp->lp_type == '2') {
3127
                                    // if is an sco
3128
                                    $old_refs[$new_item_id] = $ref;
3129
                                } elseif (isset($new_item_ids[$ref])) {
3130
                                    $old_refs[$new_item_id] = $new_item_ids[$ref];
3131
                                }
3132
                            }
3133
                            $prerequisite_ids[$new_item_id] = $item['prerequisite'];
3134
3135
                            // Upload audio.
3136
                            if (!empty($item['audio'])) {
3137
                                $courseInfo = api_get_course_info_by_id($this->destination_course_id);
3138
                                // Create the audio folder if it does not exist yet.
3139
                                $filepath = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/document/';
3140
                                if (!is_dir($filepath.'audio')) {
3141
                                    mkdir(
3142
                                        $filepath.'audio',
3143
                                        api_get_permissions_for_new_directories()
3144
                                    );
3145
                                    $audioId = add_document(
3146
                                        $courseInfo,
3147
                                        '/audio',
3148
                                        'folder',
3149
                                        0,
3150
                                        'audio',
3151
                                        '',
3152
                                        0,
3153
                                        true,
3154
                                        null,
3155
                                        $session_id,
3156
                                        api_get_user_id()
3157
                                    );
3158
                                    api_item_property_update(
3159
                                        $courseInfo,
3160
                                        TOOL_DOCUMENT,
3161
                                        $audioId,
3162
                                        'FolderCreated',
3163
                                        api_get_user_id(),
3164
                                        null,
3165
                                        null,
3166
                                        null,
3167
                                        null,
3168
                                        $session_id
3169
                                    );
3170
                                    api_item_property_update(
3171
                                        $courseInfo,
3172
                                        TOOL_DOCUMENT,
3173
                                        $audioId,
3174
                                        'invisible',
3175
                                        api_get_user_id(),
3176
                                        null,
3177
                                        null,
3178
                                        null,
3179
                                        null,
3180
                                        $session_id
3181
                                    );
3182
                                }
3183
                                $originAudioFile = $this->course->backup_path.'/document'.$item['audio'];
3184
                                $uploadedFile = [
3185
                                    'name' => basename($originAudioFile),
3186
                                    'tmp_name' => $originAudioFile,
3187
                                    'size' => filesize($originAudioFile),
3188
                                    'type' => null,
3189
                                    'from_file' => true,
3190
                                    'copy_file' => true,
3191
                                ];
3192
                                $filePath = handle_uploaded_document(
3193
                                    $courseInfo,
3194
                                    $uploadedFile,
3195
                                    api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/document',
3196
                                    '/audio',
3197
                                    api_get_user_id(),
3198
                                    '',
3199
                                    '',
3200
                                    '',
3201
                                    '',
3202
                                    false
3203
                                );
3204
                            }
3205
                        }
3206
                    }
3207
3208
                    // Updating prerequisites
3209
                    foreach ($old_prerequisite as $key => $my_old_prerequisite) {
3210
                        if ($my_old_prerequisite != '') {
3211
                            $my_old_prerequisite = Database::escape_string($my_old_prerequisite);
3212
                            $sql = "UPDATE $table_item SET prerequisite = '$my_old_prerequisite'
3213
                                    WHERE c_id = ".$this->destination_course_id." AND id = '".$key."'  ";
3214
                            Database::query($sql);
3215
                        }
3216
                    }
3217
3218
                    // Updating refs
3219
                    foreach ($old_refs as $key => $my_old_ref) {
3220
                        if ($my_old_ref != '') {
3221
                            $my_old_ref = Database::escape_string($my_old_ref);
3222
                            $sql = "UPDATE $table_item SET ref = '$my_old_ref'
3223
                                    WHERE c_id = ".$this->destination_course_id." AND id = $key";
3224
                            Database::query($sql);
3225
                        }
3226
                    }
3227
3228
                    foreach ($parent_item_ids as $new_item_id => $parent_item_old_id) {
3229
                        $new_item_id = (int) $new_item_id;
3230
                        $parent_new_id = 0;
3231
                        if ($parent_item_old_id != 0) {
3232
                            $parent_new_id = isset($new_item_ids[$parent_item_old_id]) ? $new_item_ids[$parent_item_old_id] : 0;
3233
                        }
3234
3235
                        $parent_new_id = Database::escape_string($parent_new_id);
3236
                        $sql = "UPDATE $table_item SET parent_item_id = '$parent_new_id'
3237
                                WHERE c_id = ".$this->destination_course_id." AND id = $new_item_id";
3238
                        Database::query($sql);
3239
                    }
3240
3241
                    foreach ($previous_item_ids as $new_item_id => $previous_item_old_id) {
3242
                        $new_item_id = (int) $new_item_id;
3243
                        $previous_new_id = 0;
3244
                        if ($previous_item_old_id != 0) {
3245
                            $previous_new_id = isset($new_item_ids[$previous_item_old_id]) ? $new_item_ids[$previous_item_old_id] : 0;
3246
                        }
3247
                        $previous_new_id = Database::escape_string($previous_new_id);
3248
                        $sql = "UPDATE $table_item SET previous_item_id = '$previous_new_id'
3249
                                WHERE c_id = ".$this->destination_course_id." AND id = '".$new_item_id."'";
3250
                        Database::query($sql);
3251
                    }
3252
3253
                    foreach ($next_item_ids as $new_item_id => $next_item_old_id) {
3254
                        $new_item_id = (int) $new_item_id;
3255
                        $next_new_id = 0;
3256
                        if ($next_item_old_id != 0) {
3257
                            $next_new_id = isset($new_item_ids[$next_item_old_id]) ? $new_item_ids[$next_item_old_id] : 0;
3258
                        }
3259
                        $next_new_id = Database::escape_string($next_new_id);
3260
                        $sql = "UPDATE $table_item SET next_item_id = '$next_new_id'
3261
                                WHERE c_id = ".$this->destination_course_id." AND id = '".$new_item_id."'";
3262
                        Database::query($sql);
3263
                    }
3264
3265
                    foreach ($prerequisite_ids as $new_item_id => $prerequisite_old_id) {
3266
                        $new_item_id = (int) $new_item_id;
3267
                        $prerequisite_new_id = 0;
3268
                        if ($prerequisite_old_id != 0) {
3269
                            $prerequisite_new_id = $new_item_ids[$prerequisite_old_id];
3270
                        }
3271
                        $prerequisite_new_id = Database::escape_string($prerequisite_new_id);
3272
                        $sql = "UPDATE $table_item SET prerequisite = '$prerequisite_new_id'
3273
                                WHERE c_id = ".$this->destination_course_id." AND id = $new_item_id";
3274
                        Database::query($sql);
3275
                    }
3276
                    $this->course->resources[RESOURCE_LEARNPATH][$id]->destination_id = $new_lp_id;
3277
                }
3278
            }
3279
            // It updates the current lp id prerequisites
3280
            if (!empty($lpIds)) {
3281
                foreach ($lpIds as $oldLpId => $newLpId) {
3282
                    $sql = "UPDATE $table_main SET prerequisite = '$newLpId'
3283
                                WHERE c_id = ".$this->destination_course_id." AND prerequisite = '$oldLpId'";
3284
                    Database::query($sql);
3285
                }
3286
            }
3287
        }
3288
    }
3289
3290
    /**
3291
     * Copy all directory and sub directory.
3292
     *
3293
     * @param string $source The path origin
3294
     * @param string $dest   The path destination
3295
     * @param bool Option Overwrite
3296
     *
3297
     * @deprecated
3298
     */
3299
    public function allow_create_all_directory($source, $dest, $overwrite = false)
3300
    {
3301
        if (!is_dir($dest)) {
3302
            mkdir($dest, api_get_permissions_for_new_directories());
3303
        }
3304
        if ($handle = opendir($source)) {
3305
            // if the folder exploration is sucsessful, continue
3306
            while (false !== ($file = readdir($handle))) {
3307
                // as long as storing the next file to $file is successful, continue
3308
                if ($file != '.' && $file != '..') {
3309
                    $path = $source.'/'.$file;
3310
                    if (is_file($path)) {
3311
                        /* if (!is_file($dest . '/' . $file) || $overwrite)
3312
                         if (!@copy($path, $dest . '/' . $file)) {
3313
                             echo '<font color="red">File ('.$path.') '.get_lang('NotHavePermission').'</font>';
3314
                         }*/
3315
                    } elseif (is_dir($path)) {
3316
                        if (!is_dir($dest.'/'.$file)) {
3317
                            mkdir($dest.'/'.$file);
3318
                        }
3319
                        self::allow_create_all_directory($path, $dest.'/'.$file, $overwrite);
3320
                    }
3321
                }
3322
            }
3323
            closedir($handle);
3324
        }
3325
    }
3326
3327
    /**
3328
     * Gets the new ID of one specific tool item from the tool name and the old ID.
3329
     *
3330
     * @param	string	Tool name
3331
     * @param	int	Old ID
3332
     *
3333
     * @return int New ID
3334
     */
3335
    public function get_new_id($tool, $ref)
3336
    {
3337
        // Check if the value exist in the current array.
3338
        if ($tool === 'hotpotatoes') {
3339
            $tool = 'document';
3340
        }
3341
3342
        if ($tool === 'student_publication') {
3343
            $tool = RESOURCE_WORK;
3344
        }
3345
3346
        if ('xapi' === $tool && $this->isXapiEnabled) {
3347
            $tool = RESOURCE_XAPI_TOOL;
3348
        }
3349
3350
        if ('h5p' === $tool && $this->isH5pEnabled) {
3351
            $tool = RESOURCE_H5P_TOOL;
3352
        }
3353
3354
        if (isset($this->course->resources[$tool][$ref]) &&
3355
            isset($this->course->resources[$tool][$ref]->destination_id) &&
3356
            !empty($this->course->resources[$tool][$ref]->destination_id)
3357
        ) {
3358
            return $this->course->resources[$tool][$ref]->destination_id;
3359
        }
3360
3361
        // Check if the course is the same (last hope).
3362
        if ($this->course_origin_id == $this->destination_course_id) {
3363
            return $ref;
3364
        }
3365
3366
        return '';
3367
    }
3368
3369
    /**
3370
     * Restore glossary.
3371
     */
3372
    public function restore_glossary($sessionId = 0)
3373
    {
3374
        $sessionId = (int) $sessionId;
3375
        if ($this->course->has_resources(RESOURCE_GLOSSARY)) {
3376
            $table_glossary = Database::get_course_table(TABLE_GLOSSARY);
3377
            $resources = $this->course->resources;
3378
            foreach ($resources[RESOURCE_GLOSSARY] as $id => $glossary) {
3379
                $params = [];
3380
                if (!empty($sessionId)) {
3381
                    $params['session_id'] = $sessionId;
3382
                }
3383
3384
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3385
                $glossary->description = DocumentManager::replaceUrlWithNewCourseCode(
3386
                    $glossary->description,
3387
                    $this->course->code,
3388
                    $this->course->destination_path,
3389
                    $this->course->backup_path,
3390
                    $this->course->info['path']
3391
                );
3392
3393
                $params['c_id'] = $this->destination_course_id;
3394
                $params['description'] = ($glossary->description === false ? '' : self::DBUTF8($glossary->description));
3395
                $params['display_order'] = $glossary->display_order;
3396
                $params['name'] = self::DBUTF8($glossary->name);
3397
                $params['glossary_id'] = 0;
3398
                $my_id = Database::insert($table_glossary, $params);
3399
                if ($my_id) {
3400
                    $sql = "UPDATE $table_glossary SET glossary_id = iid WHERE iid = $my_id";
3401
                    Database::query($sql);
3402
3403
                    api_item_property_update(
3404
                        $this->destination_course_info,
3405
                        TOOL_GLOSSARY,
3406
                        $my_id,
3407
                        'GlossaryAdded',
3408
                        api_get_user_id(),
3409
                        null,
3410
                        null,
3411
                        null,
3412
                        null,
3413
                        $sessionId
3414
                    );
3415
3416
                    if (!isset($this->course->resources[RESOURCE_GLOSSARY][$id])) {
3417
                        $this->course->resources[RESOURCE_GLOSSARY][$id] = new stdClass();
3418
                    }
3419
3420
                    $this->course->resources[RESOURCE_GLOSSARY][$id]->destination_id = $my_id;
3421
                }
3422
            }
3423
        }
3424
    }
3425
3426
    /**
3427
     * @param int $sessionId
3428
     */
3429
    public function restore_wiki($sessionId = 0)
3430
    {
3431
        if ($this->course->has_resources(RESOURCE_WIKI)) {
3432
            // wiki table of the target course
3433
            $table_wiki = Database::get_course_table(TABLE_WIKI);
3434
            $table_wiki_conf = Database::get_course_table(TABLE_WIKI_CONF);
3435
3436
            // storing all the resources that have to be copied in an array
3437
            $resources = $this->course->resources;
3438
3439
            foreach ($resources[RESOURCE_WIKI] as $id => $wiki) {
3440
                // the sql statement to insert the groups from the old course to the new course
3441
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3442
                $wiki->content = DocumentManager::replaceUrlWithNewCourseCode(
3443
                    $wiki->content,
3444
                    $this->course->code,
3445
                    $this->course->destination_path,
3446
                    $this->course->backup_path,
3447
                    $this->course->info['path']
3448
                );
3449
3450
                $params = [
3451
                    'c_id' => $this->destination_course_id,
3452
                    'page_id' => self::DBUTF8($wiki->page_id),
3453
                    'reflink' => self::DBUTF8($wiki->reflink),
3454
                    'title' => self::DBUTF8($wiki->title),
3455
                    'content' => ($wiki->content === false ? '' : self::DBUTF8($wiki->content)),
3456
                    'user_id' => intval($wiki->user_id),
3457
                    'group_id' => intval($wiki->group_id),
3458
                    'dtime' => self::DBUTF8($wiki->dtime),
3459
                    'progress' => self::DBUTF8($wiki->progress),
3460
                    'version' => intval($wiki->version),
3461
                    'session_id' => !empty($sessionId) ? intval($sessionId) : 0,
3462
                    'addlock' => 0,
3463
                    'editlock' => 0,
3464
                    'visibility' => 0,
3465
                    'addlock_disc' => 0,
3466
                    'visibility_disc' => 0,
3467
                    'ratinglock_disc' => 0,
3468
                    'assignment' => 0,
3469
                    'comment' => '',
3470
                    'is_editing' => 0,
3471
                    'linksto' => 0,
3472
                    'tag' => '',
3473
                    'user_ip' => '',
3474
                ];
3475
3476
                $new_id = Database::insert($table_wiki, $params);
3477
3478
                if ($new_id) {
3479
                    $sql = "UPDATE $table_wiki SET page_id = '$new_id', id = iid
3480
                            WHERE c_id = ".$this->destination_course_id." AND iid = '$new_id'";
3481
                    Database::query($sql);
3482
3483
                    $this->course->resources[RESOURCE_WIKI][$id]->destination_id = $new_id;
3484
3485
                    // we also add an entry in wiki_conf
3486
                    $params = [
3487
                        'c_id' => $this->destination_course_id,
3488
                        'page_id' => $new_id,
3489
                        'task' => '',
3490
                        'feedback1' => '',
3491
                        'feedback2' => '',
3492
                        'feedback3' => '',
3493
                        'fprogress1' => '',
3494
                        'fprogress2' => '',
3495
                        'fprogress3' => '',
3496
                        'max_size' => 0,
3497
                        'max_text' => 0,
3498
                        'max_version' => 0,
3499
                        'startdate_assig' => null,
3500
                        'enddate_assig' => null,
3501
                        'delayedsubmit' => 0,
3502
                    ];
3503
3504
                    Database::insert($table_wiki_conf, $params);
3505
                }
3506
            }
3507
        }
3508
    }
3509
3510
    /**
3511
     * Restore xapi tool.
3512
     *
3513
     * @param int $sessionId
3514
     */
3515
    public function restore_xapi_tool()
3516
    {
3517
        if ($this->course->has_resources(RESOURCE_XAPI_TOOL) && $this->isXapiEnabled) {
3518
            $resources = $this->course->resources;
3519
            foreach ($resources[RESOURCE_XAPI_TOOL] as $id => $xapiTool) {
3520
                $launchPath = str_replace(
3521
                    api_get_path(WEB_COURSE_PATH).$this->course->info['path'].'/',
3522
                    '',
3523
                    dirname($xapiTool->params['launch_url'])
3524
                );
3525
3526
                $originPath = $this->course->backup_path.'/'.$launchPath;
3527
                $destinationPath = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/'.$launchPath;
3528
                $xapiDir = dirname($destinationPath);
3529
                @mkdir($xapiDir, api_get_permissions_for_new_directories(), true);
3530
                if (copyDirTo($originPath, $destinationPath, false)) {
3531
                    $xapiTool->params['launch_url'] = str_replace(
3532
                        '/'.$this->course->info['path'].'/',
3533
                        '/'.$this->course->destination_path.'/',
3534
                        $xapiTool->params['launch_url']
3535
                    );
3536
                    $ref = $xapiTool->params['id'];
3537
                    $xapiTool->params['c_id'] = $this->destination_course_id;
3538
                    unset($xapiTool->params['id']);
3539
3540
                    $lastId = Database::insert('xapi_tool_launch', $xapiTool->params, false);
3541
                    $this->course->resources[RESOURCE_XAPI_TOOL][$ref]->destination_id = $lastId;
3542
                }
3543
            }
3544
        }
3545
    }
3546
3547
    /**
3548
     * Restore Thematics.
3549
     *
3550
     * @param int $sessionId
3551
     */
3552
    public function restore_thematic($sessionId = 0)
3553
    {
3554
        if ($this->course->has_resources(RESOURCE_THEMATIC)) {
3555
            $table_thematic = Database::get_course_table(TABLE_THEMATIC);
3556
            $table_thematic_advance = Database::get_course_table(TABLE_THEMATIC_ADVANCE);
3557
            $table_thematic_plan = Database::get_course_table(TABLE_THEMATIC_PLAN);
3558
3559
            $resources = $this->course->resources;
3560
            foreach ($resources[RESOURCE_THEMATIC] as $id => $thematic) {
3561
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3562
                $thematic->params['content'] = DocumentManager::replaceUrlWithNewCourseCode(
3563
                    $thematic->params['content'],
3564
                    $this->course->code,
3565
                    $this->course->destination_path,
3566
                    $this->course->backup_path,
3567
                    $this->course->info['path']
3568
                );
3569
                $thematic->params['c_id'] = $this->destination_course_id;
3570
                unset($thematic->params['id']);
3571
                unset($thematic->params['iid']);
3572
3573
                $last_id = Database::insert($table_thematic, $thematic->params, false);
3574
3575
                if ($last_id) {
3576
                    $sql = "UPDATE $table_thematic SET id = iid WHERE iid = $last_id";
3577
                    Database::query($sql);
3578
3579
                    api_item_property_update(
3580
                        $this->destination_course_info,
3581
                        'thematic',
3582
                        $last_id,
3583
                        'ThematicAdded',
3584
                        api_get_user_id(),
3585
                        null,
3586
                        null,
3587
                        null,
3588
                        null,
3589
                        $sessionId
3590
                    );
3591
3592
                    foreach ($thematic->thematic_advance_list as $thematic_advance) {
3593
                        unset($thematic_advance['id']);
3594
                        unset($thematic_advance['iid']);
3595
                        $thematic_advance['attendance_id'] = 0;
3596
                        $thematic_advance['thematic_id'] = $last_id;
3597
                        $thematic_advance['c_id'] = $this->destination_course_id;
3598
3599
                        $my_id = Database::insert(
3600
                            $table_thematic_advance,
3601
                            $thematic_advance,
3602
                            false
3603
                        );
3604
3605
                        if ($my_id) {
3606
                            $sql = "UPDATE $table_thematic_advance SET id = iid WHERE iid = $my_id";
3607
                            Database::query($sql);
3608
3609
                            api_item_property_update(
3610
                                $this->destination_course_info,
3611
                                'thematic_advance',
3612
                                $my_id,
3613
                                'ThematicAdvanceAdded',
3614
                                api_get_user_id(),
3615
                                null,
3616
                                null,
3617
                                null,
3618
                                null,
3619
                                $sessionId
3620
                            );
3621
                        }
3622
                    }
3623
3624
                    foreach ($thematic->thematic_plan_list as $thematic_plan) {
3625
                        unset($thematic_plan['id']);
3626
                        unset($thematic_plan['iid']);
3627
                        $thematic_plan['thematic_id'] = $last_id;
3628
                        $thematic_plan['c_id'] = $this->destination_course_id;
3629
                        $my_id = Database::insert($table_thematic_plan, $thematic_plan, false);
3630
3631
                        if ($my_id) {
3632
                            $sql = "UPDATE $table_thematic_plan SET id = iid WHERE iid = $my_id";
3633
                            Database::query($sql);
3634
3635
                            api_item_property_update(
3636
                                $this->destination_course_info,
3637
                                'thematic_plan',
3638
                                $my_id,
3639
                                'ThematicPlanAdded',
3640
                                api_get_user_id(),
3641
                                null,
3642
                                null,
3643
                                null,
3644
                                null,
3645
                                $sessionId
3646
                            );
3647
                        }
3648
                    }
3649
                }
3650
            }
3651
        }
3652
    }
3653
3654
    /**
3655
     * Restore Attendance.
3656
     *
3657
     * @param int $sessionId
3658
     */
3659
    public function restore_attendance($sessionId = 0)
3660
    {
3661
        if ($this->course->has_resources(RESOURCE_ATTENDANCE)) {
3662
            $table_attendance = Database::get_course_table(TABLE_ATTENDANCE);
3663
            $table_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
3664
3665
            $resources = $this->course->resources;
3666
            foreach ($resources[RESOURCE_ATTENDANCE] as $id => $obj) {
3667
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3668
                $obj->params['description'] = DocumentManager::replaceUrlWithNewCourseCode(
3669
                    $obj->params['description'],
3670
                    $this->course->code,
3671
                    $this->course->destination_path,
3672
                    $this->course->backup_path,
3673
                    $this->course->info['path']
3674
                );
3675
3676
                unset($obj->params['id']);
3677
                unset($obj->params['iid']);
3678
                $obj->params['c_id'] = $this->destination_course_id;
3679
                $last_id = Database::insert($table_attendance, $obj->params);
3680
3681
                if (is_numeric($last_id)) {
3682
                    $sql = "UPDATE $table_attendance SET id = iid WHERE iid = $last_id";
3683
                    Database::query($sql);
3684
3685
                    $this->course->resources[RESOURCE_ATTENDANCE][$id]->destination_id = $last_id;
3686
3687
                    api_item_property_update(
3688
                        $this->destination_course_info,
3689
                        TOOL_ATTENDANCE,
3690
                        $last_id,
3691
                        'AttendanceAdded',
3692
                        api_get_user_id(),
3693
                        null,
3694
                        null,
3695
                        null,
3696
                        null,
3697
                        $sessionId
3698
                    );
3699
3700
                    foreach ($obj->attendance_calendar as $attendance_calendar) {
3701
                        unset($attendance_calendar['id']);
3702
                        unset($attendance_calendar['iid']);
3703
3704
                        $attendance_calendar['attendance_id'] = $last_id;
3705
                        $attendance_calendar['c_id'] = $this->destination_course_id;
3706
                        $attendanceCalendarId = Database::insert(
3707
                            $table_attendance_calendar,
3708
                            $attendance_calendar
3709
                        );
3710
3711
                        $sql = "UPDATE $table_attendance_calendar SET id = iid WHERE iid = $attendanceCalendarId";
3712
                        Database::query($sql);
3713
                    }
3714
                }
3715
            }
3716
        }
3717
    }
3718
3719
    /**
3720
     * Restore Works.
3721
     *
3722
     * @param int $sessionId
3723
     */
3724
    public function restore_works($sessionId = 0)
3725
    {
3726
        require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
3727
        if ($this->course->has_resources(RESOURCE_WORK)) {
3728
            $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
3729
3730
            $resources = $this->course->resources;
3731
            foreach ($resources[RESOURCE_WORK] as $obj) {
3732
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3733
                $obj->params['description'] = DocumentManager::replaceUrlWithNewCourseCode(
3734
                    $obj->params['description'],
3735
                    $this->course->code,
3736
                    $this->course->destination_path,
3737
                    $this->course->backup_path,
3738
                    $this->course->info['path']
3739
                );
3740
3741
                $id_work = $obj->params['id'];
3742
                $obj->params['id'] = null;
3743
                $obj->params['c_id'] = $this->destination_course_info['real_id'];
3744
3745
                // re-create dir
3746
                // @todo check security against injection of dir in crafted course backup here!
3747
                $path = $obj->params['url'];
3748
                $path = '/'.str_replace('/', '', substr($path, 1));
3749
3750
                $workData = [];
3751
3752
                switch ($this->file_option) {
3753
                    case FILE_SKIP:
3754
                        $workData = get_work_data_by_path(
3755
                            $path,
3756
                            $this->destination_course_info['real_id']
3757
                        );
3758
                        if (!empty($workData)) {
3759
                            break;
3760
                        }
3761
                        break;
3762
                    case FILE_OVERWRITE:
3763
                        if (!empty($this->course_origin_id)) {
3764
                            $sql = 'SELECT * FROM '.$table.'
3765
                                    WHERE
3766
                                        c_id = '.$this->course_origin_id.' AND
3767
                                        publication_id = '.$id_work;
3768
                            $result = Database::query($sql);
3769
                            $cant = Database::num_rows($result);
3770
                            if ($cant > 0) {
3771
                                $row = Database::fetch_assoc($result);
3772
                            }
3773
3774
                            $obj->params['enableExpiryDate'] = empty($row['expires_on']) ? false : true;
3775
                            $obj->params['enableEndDate'] = empty($row['ends_on']) ? false : true;
3776
                            $obj->params['expires_on'] = $row['expires_on'];
3777
                            $obj->params['ends_on'] = $row['ends_on'];
3778
                            $obj->params['enable_qualification'] = $row['enable_qualification'];
3779
                            $obj->params['add_to_calendar'] = !empty($row['add_to_calendar']) ? 1 : 0;
3780
                        }
3781
                        //no break
3782
                    case FILE_RENAME:
3783
                        $workData = get_work_data_by_path(
3784
                            $path,
3785
                            $this->destination_course_info['real_id']
3786
                        );
3787
                        break;
3788
                }
3789
3790
                $obj->params['work_title'] = $obj->params['title'];
3791
                $obj->params['new_dir'] = $obj->params['title'];
3792
3793
                if (empty($workData)) {
3794
                    $workId = addDir(
3795
                        $obj->params,
3796
                        api_get_user_id(),
3797
                        $this->destination_course_info,
3798
                        0,
3799
                        $sessionId
3800
                    );
3801
                    $this->course->resources[RESOURCE_WORK][$id_work]->destination_id = $workId;
3802
                } else {
3803
                    $workId = $workData['iid'];
3804
                    updateWork(
3805
                        $workId,
3806
                        $obj->params,
3807
                        $this->destination_course_info,
3808
                        $sessionId
3809
                    );
3810
                    updatePublicationAssignment(
3811
                        $workId,
3812
                        $obj->params,
3813
                        $this->destination_course_info,
3814
                        0
3815
                    );
3816
                    $this->course->resources[RESOURCE_WORK][$id_work]->destination_id = $workId;
3817
                }
3818
            }
3819
        }
3820
    }
3821
3822
    /**
3823
     * Restore gradebook.
3824
     *
3825
     * @param int $sessionId
3826
     *
3827
     * @return bool
3828
     */
3829
    public function restore_gradebook($sessionId = 0)
3830
    {
3831
        if (in_array($this->file_option, [FILE_SKIP, FILE_RENAME])) {
3832
            return false;
3833
        }
3834
        // if overwrite
3835
        if ($this->course->has_resources(RESOURCE_GRADEBOOK)) {
3836
            $resources = $this->course->resources;
3837
            $destinationCourseCode = $this->destination_course_info['code'];
3838
            // Delete destination gradebook
3839
            $cats = \Category::load(
3840
                null,
3841
                null,
3842
                $destinationCourseCode,
3843
                null,
3844
                null,
3845
                $sessionId
3846
            );
3847
3848
            if (!empty($cats)) {
3849
                /** @var \Category $cat */
3850
                foreach ($cats as $cat) {
3851
                    $cat->delete_all();
3852
                }
3853
            }
3854
3855
            /** @var GradeBookBackup $obj */
3856
            foreach ($resources[RESOURCE_GRADEBOOK] as $id => $obj) {
3857
                if (!empty($obj->categories)) {
3858
                    $categoryIdList = [];
3859
                    /** @var \Category $cat */
3860
                    foreach ($obj->categories as $cat) {
3861
                        $cat->set_course_code($destinationCourseCode);
3862
                        $cat->set_session_id($sessionId);
3863
3864
                        $parentId = $cat->get_parent_id();
3865
                        if (!empty($parentId)) {
3866
                            if (isset($categoryIdList[$parentId])) {
3867
                                $cat->set_parent_id($categoryIdList[$parentId]);
3868
                            }
3869
                        }
3870
                        $oldId = $cat->get_id();
3871
                        $categoryId = $cat->add();
3872
                        $categoryIdList[$oldId] = $categoryId;
3873
                        if (!empty($cat->evaluations)) {
3874
                            /** @var \Evaluation $evaluation */
3875
                            foreach ($cat->evaluations as $evaluation) {
3876
                                $evaluation->set_category_id($categoryId);
3877
                                $evaluation->set_course_code($destinationCourseCode);
3878
                                $evaluation->setSessionId($sessionId);
3879
                                $evaluation->add();
3880
                            }
3881
                        }
3882
3883
                        if (!empty($cat->links)) {
3884
                            /** @var \AbstractLink $link */
3885
                            foreach ($cat->links as $link) {
3886
                                $link->set_category_id($categoryId);
3887
                                $link->set_course_code($destinationCourseCode);
3888
                                $link->set_session_id($sessionId);
3889
                                $import = false;
3890
                                $itemId = $link->get_ref_id();
3891
                                switch ($link->get_type()) {
3892
                                    case LINK_EXERCISE:
3893
                                        $type = RESOURCE_QUIZ;
3894
                                        break;
3895
                                    /*case LINK_DROPBOX:
3896
                                        break;*/
3897
                                    case LINK_STUDENTPUBLICATION:
3898
                                        $type = RESOURCE_WORK;
3899
                                        break;
3900
                                    case LINK_LEARNPATH:
3901
                                        $type = RESOURCE_LEARNPATH;
3902
                                        break;
3903
                                    case LINK_FORUM_THREAD:
3904
                                        $type = RESOURCE_FORUMTOPIC;
3905
                                        break;
3906
                                    case LINK_ATTENDANCE:
3907
                                        $type = RESOURCE_ATTENDANCE;
3908
                                        break;
3909
                                    case LINK_SURVEY:
3910
                                        $type = RESOURCE_ATTENDANCE;
3911
                                        break;
3912
                                    case LINK_HOTPOTATOES:
3913
                                        $type = RESOURCE_QUIZ;
3914
                                        break;
3915
                                }
3916
3917
                                if ($this->course->has_resources($type) &&
3918
                                    isset($this->course->resources[$type][$itemId])
3919
                                ) {
3920
                                    $item = $this->course->resources[$type][$itemId];
3921
                                    if ($item && $item->is_restored()) {
3922
                                        $link->set_ref_id($item->destination_id);
3923
                                        $import = true;
3924
                                    }
3925
                                }
3926
3927
                                if ($import) {
3928
                                    $link->add();
3929
                                }
3930
                            }
3931
                        }
3932
                    }
3933
                }
3934
            }
3935
        }
3936
    }
3937
3938
    /**
3939
     * Restore course assets (not included in documents).
3940
     */
3941
    public function restore_assets()
3942
    {
3943
        if ($this->course->has_resources(RESOURCE_ASSET)) {
3944
            $resources = $this->course->resources;
3945
            $path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/';
3946
3947
            foreach ($resources[RESOURCE_ASSET] as $asset) {
3948
                if (is_file($this->course->backup_path.'/'.$asset->path) &&
3949
                    is_readable($this->course->backup_path.'/'.$asset->path) &&
3950
                    is_dir(dirname($path.$asset->path)) &&
3951
                    is_writeable(dirname($path.$asset->path))
3952
                ) {
3953
                    switch ($this->file_option) {
3954
                        case FILE_SKIP:
3955
                            break;
3956
                        case FILE_OVERWRITE:
3957
                            copy(
3958
                                $this->course->backup_path.'/'.$asset->path,
3959
                                $path.$asset->path
3960
                            );
3961
                            break;
3962
                    }
3963
                }
3964
            }
3965
        }
3966
    }
3967
3968
    /**
3969
     * @param string $str
3970
     *
3971
     * @return string
3972
     */
3973
    public function DBUTF8($str)
3974
    {
3975
        if (UTF8_CONVERT) {
3976
            $str = utf8_encode($str);
3977
        }
3978
3979
        return $str;
3980
    }
3981
3982
    /**
3983
     * @param string $str
3984
     *
3985
     * @return string
3986
     */
3987
    public function DBUTF8escapestring($str)
3988
    {
3989
        if (UTF8_CONVERT) {
3990
            $str = utf8_encode($str);
3991
        }
3992
3993
        return Database::escape_string($str);
3994
    }
3995
3996
    /**
3997
     * @param array $array
3998
     *
3999
     * @return mixed
4000
     */
4001
    public function DBUTF8_array($array)
4002
    {
4003
        if (UTF8_CONVERT) {
4004
            foreach ($array as &$item) {
4005
                $item = utf8_encode($item);
4006
            }
4007
4008
            return $array;
4009
        } else {
4010
            return $array;
4011
        }
4012
    }
4013
4014
    /**
4015
     * @param int $groupId
4016
     *
4017
     * @return array
4018
     */
4019
    public function checkGroupId($groupId)
4020
    {
4021
        return \GroupManager::get_group_properties($groupId);
4022
    }
4023
4024
    /**
4025
     * @param string $documentPath
4026
     * @param string $webEditorCss
4027
     */
4028
    public function fixEditorHtmlContent($documentPath, $webEditorCss = '')
4029
    {
4030
        $extension = pathinfo(basename($documentPath), PATHINFO_EXTENSION);
4031
4032
        switch ($extension) {
4033
            case 'html':
4034
            case 'htm':
4035
                $contents = file_get_contents($documentPath);
4036
                $contents = str_replace(
4037
                    '{{css_editor}}',
4038
                    $webEditorCss,
4039
                    $contents
4040
                );
4041
                file_put_contents($documentPath, $contents);
4042
                break;
4043
        }
4044
    }
4045
4046
    /**
4047
     * Check if user exist otherwise use current user.
4048
     *
4049
     * @param int  $userId
4050
     * @param bool $returnNull
4051
     *
4052
     * @return int
4053
     */
4054
    private function checkUserId($userId, $returnNull = false)
4055
    {
4056
        if (!empty($userId)) {
4057
            $userInfo = api_get_user_info($userId);
4058
            if (empty($userInfo)) {
4059
                return api_get_user_id();
4060
            }
4061
        }
4062
4063
        if ($returnNull) {
4064
            return null;
4065
        }
4066
4067
        if (empty($userId)) {
4068
            return api_get_user_id();
4069
        }
4070
4071
        return $userId;
4072
    }
4073
}
4074