Passed
Push — master ( 4c9a82...f78b85 )
by Julito
12:50 queued 04:06
created

getLinkForQuestion()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 4
eloc 14
nc 3
nop 7
dl 0
loc 28
rs 9.7998
c 1
b 1
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
use Knp\Component\Pager\Paginator;
6
7
/**
8
 * Question Pool
9
 * This script allows administrators to manage questions and add them into their exercises.
10
 * One question can be in several exercises.
11
 *
12
 * @package chamilo.exercise
13
 *
14
 * @author Olivier Brouckaert
15
 * @author Julio Montoya adding support to query all questions from all session, courses, exercises
16
 * @author Modify by hubert borderiou 2011-10-21 Question's category
17
 */
18
require_once __DIR__.'/../inc/global.inc.php';
19
20
$this_section = SECTION_COURSES;
21
22
$is_allowedToEdit = api_is_allowed_to_edit(null, true);
23
24
$delete = isset($_GET['delete']) ? intval($_GET['delete']) : null;
25
$recup = isset($_GET['recup']) ? intval($_GET['recup']) : null;
26
$fromExercise = isset($_REQUEST['fromExercise']) ? intval($_REQUEST['fromExercise']) : null;
27
$exerciseId = isset($_REQUEST['exerciseId']) ? intval($_REQUEST['exerciseId']) : null;
28
$courseCategoryId = isset($_REQUEST['courseCategoryId']) ? intval($_REQUEST['courseCategoryId']) : null;
29
$exerciseLevel = isset($_REQUEST['exerciseLevel']) ? intval($_REQUEST['exerciseLevel']) : -1;
30
$answerType = isset($_REQUEST['answerType']) ? intval($_REQUEST['answerType']) : null;
31
$question_copy = isset($_REQUEST['question_copy']) ? intval($_REQUEST['question_copy']) : 0;
32
$session_id = isset($_REQUEST['session_id']) ? intval($_REQUEST['session_id']) : null;
33
$selected_course = isset($_GET['selected_course']) ? intval($_GET['selected_course']) : null;
34
// save the id of the previous course selected by user to reset menu if we detect that user change course hub 13-10-2011
35
$course_id_changed = isset($_GET['course_id_changed']) ? intval($_GET['course_id_changed']) : null;
36
// save the id of the previous exercise selected by user to reset menu if we detect that user change course hub 13-10-2011
37
$exercise_id_changed = isset($_GET['exercise_id_changed']) ? intval($_GET['exercise_id_changed']) : null;
38
$questionId = isset($_GET['question_id']) && !empty($_GET['question_id']) ? (int) $_GET['question_id'] : '';
39
$description = isset($_GET['description']) ? Database::escape_string($_GET['description']) : '';
40
$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
41
42
// by default when we go to the page for the first time, we select the current course
43
if (!isset($_GET['selected_course']) && !isset($_GET['exerciseId'])) {
44
    $selected_course = api_get_course_int_id();
45
}
46
47
$_course = api_get_course_info();
48
49
if (empty($objExercise) && !empty($fromExercise)) {
50
    $objExercise = new Exercise();
51
    $objExercise->read($fromExercise);
52
}
53
54
$nameTools = get_lang('QuestionPool');
55
$interbreadcrumb[] = ['url' => 'exercise.php?'.api_get_cidreq(), 'name' => get_lang('Exercises')];
56
57
if (!empty($objExercise)) {
58
    $interbreadcrumb[] = [
59
        'url' => 'admin.php?exerciseId='.$objExercise->id.'&'.api_get_cidreq(),
60
        'name' => $objExercise->selectTitle(true),
61
    ];
62
}
63
64
// message to be displayed if actions successful
65
$displayMessage = '';
66
if ($is_allowedToEdit) {
67
    // Duplicating a Question
68
    if (!isset($_POST['recup']) && $question_copy != 0 && isset($fromExercise)) {
69
        $origin_course_id = (int) $_GET['course_id'];
70
        $origin_course_info = api_get_course_info_by_id($origin_course_id);
71
        $current_course = api_get_course_info();
72
        $old_question_id = $question_copy;
73
        // Reading the source question
74
        $old_question_obj = Question::read($old_question_id, $origin_course_id);
75
        $courseId = $current_course['real_id'];
76
        if ($old_question_obj) {
77
            $old_question_obj->updateTitle($old_question_obj->selectTitle().' - '.get_lang('Copy'));
78
            //Duplicating the source question, in the current course
79
            $new_id = $old_question_obj->duplicate($current_course);
80
            //Reading new question
81
            $new_question_obj = Question::read($new_id);
82
            $new_question_obj->addToList($fromExercise);
83
            //Reading Answers obj of the current course
84
            $new_answer_obj = new Answer($old_question_id, $origin_course_id);
85
            $new_answer_obj->read();
86
            //Duplicating the Answers in the current course
87
            $new_answer_obj->duplicate($new_question_obj, $current_course);
88
            // destruction of the Question object
89
            unset($new_question_obj);
90
            unset($old_question_obj);
91
92
            $objExercise = new Exercise($courseId);
93
            $objExercise->read($fromExercise);
94
            Session::write('objExercise', $objExercise);
95
        }
96
        $displayMessage = get_lang('ItemAdded');
97
    }
98
99
    // Deletes a question from the database and all exercises
100
    if ($delete) {
101
        $limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
102
        if ($limitTeacherAccess && !api_is_platform_admin()) {
103
            api_not_allowed(true);
104
        }
105
        // Construction of the Question object
106
        $objQuestionTmp = Question::read($delete);
107
        // if the question exists
108
        if ($objQuestionTmp) {
109
            // deletes the question from all exercises
110
            $objQuestionTmp->delete();
111
        }
112
        // destruction of the Question object
113
        unset($objQuestionTmp);
114
    } elseif ($recup && $fromExercise) {
115
        // gets an existing question and copies it into a new exercise
116
        $objQuestionTmp = Question :: read($recup);
117
        // if the question exists
118
        if ($objQuestionTmp) {
119
            /* Adds the exercise ID represented by $fromExercise into the list
120
            of exercises for the current question */
121
            $objQuestionTmp->addToList($fromExercise);
122
        }
123
        // destruction of the Question object
124
        unset($objQuestionTmp);
125
126
        if (!$objExercise instanceof Exercise) {
127
            $objExercise = new Exercise();
128
            $objExercise->read($fromExercise);
129
        }
130
        // Adds the question ID represented by $recup into the list of questions for the current exercise
131
        $objExercise->addToList($recup);
132
        Session::write('objExercise', $objExercise);
133
        Display::addFlash(
134
            Display::return_message(get_lang('ItemAdded'), 'success')
135
        );
136
    } elseif (isset($_POST['recup']) && is_array($_POST['recup']) && $fromExercise) {
137
        $list_recup = $_POST['recup'];
138
        foreach ($list_recup as $course_id => $question_data) {
139
            $origin_course_id = (int) $course_id;
140
            $origin_course_info = api_get_course_info_by_id($origin_course_id);
141
            $current_course = api_get_course_info();
142
            foreach ($question_data as $old_question_id) {
143
                //Reading the source question
144
                $old_question_obj = Question::read($old_question_id, $origin_course_id);
145
                if ($old_question_obj) {
146
                    $old_question_obj->updateTitle(
147
                        $old_question_obj->selectTitle().' - '.get_lang('Copy')
148
                    );
149
150
                    // Duplicating the source question, in the current course
151
                    $new_id = $old_question_obj->duplicate($current_course);
152
153
                    // Reading new question
154
                    $new_question_obj = Question::read($new_id);
155
                    $new_question_obj->addToList($fromExercise);
156
157
                    //Reading Answers obj of the current course
158
                    $new_answer_obj = new Answer($old_question_id, $origin_course_id);
159
                    $new_answer_obj->read();
160
161
                    //Duplicating the Answers in the current course
162
                    $new_answer_obj->duplicate($new_question_obj, $current_course);
163
164
                    // destruction of the Question object
165
                    unset($new_question_obj);
166
                    unset($old_question_obj);
167
168
                    if (!$objExercise instanceof Exercise) {
169
                        $objExercise = new Exercise();
170
                        $objExercise->read($fromExercise);
171
                    }
172
                }
173
            }
174
        }
175
        Session::write('objExercise', $objExercise);
176
    }
177
}
178
179
if (api_is_in_gradebook()) {
180
    $interbreadcrumb[] = [
181
        'url' => Category::getUrl(),
182
        'name' => get_lang('ToolGradebook'),
183
    ];
184
}
185
186
// if admin of course
187
if (!$is_allowedToEdit) {
188
    api_not_allowed(true);
189
}
190
191
$confirmYourChoice = addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset));
192
$htmlHeadXtra[] = "
193
<script>
194
    function submit_form(obj) {
195
        document.question_pool.submit();
196
    }
197
198
    function mark_course_id_changed() {
199
        $('#course_id_changed').val('1');
200
    }
201
202
    function mark_exercise_id_changed() {
203
        $('#exercise_id_changed').val('1');
204
    }
205
206
    function confirm_your_choice() {
207
        return confirm('$confirmYourChoice');
208
    }
209
</script>";
210
211
Display::display_header($nameTools, 'Exercise');
212
213
// Menu
214
echo '<div class="actions">';
215
$url = api_get_self().'?'.api_get_cidreq().'&'.http_build_query(
216
    [
217
        'fromExercise' => $fromExercise,
218
        'session_id' => $session_id,
219
        'selected_course' => $selected_course,
220
        'courseCategoryId' => $courseCategoryId,
221
        'exerciseId' => $exerciseId,
222
        'exerciseLevel' => $exerciseLevel,
223
        'answerType' => $answerType,
224
        'question_id' => $questionId,
225
        'description' => Security::remove_XSS($description),
226
        'course_id_changed' => $course_id_changed,
227
        'exercise_id_changed' => $exercise_id_changed,
228
    ]
229
);
230
231
if (isset($fromExercise) && $fromExercise > 0) {
232
    echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$fromExercise.'">'.
233
            Display::return_icon('back.png', get_lang('GoBackToQuestionList'), '', ICON_SIZE_MEDIUM).'</a>';
234
    $titleAdd = get_lang('AddQuestionToTest');
235
} else {
236
    echo '<a href="exercise.php?'.api_get_cidreq().'">'.
237
        Display::return_icon('back.png', get_lang('BackToExercisesList'), '', ICON_SIZE_MEDIUM).'</a>';
238
    echo "<a href='admin.php?exerciseId=0'>".
239
        Display::return_icon('add_question.gif', get_lang('NewQu'), '', ICON_SIZE_MEDIUM)."</a>";
240
    $titleAdd = get_lang('ManageAllQuestions');
241
}
242
echo '</div>';
243
244
if ($displayMessage != '') {
245
    echo Display::return_message($displayMessage, 'confirm');
246
    $displayMessage = '';
247
}
248
249
// Form
250
echo '<form class="form-horizontal" name="question_pool" method="GET" action="'.$url.'">';
251
// Title
252
echo '<legend>'.$nameTools.' - '.$titleAdd.'</legend>';
253
echo '<input type="hidden" name="fromExercise" value="'.$fromExercise.'">';
254
255
// Session list, if sessions are used.
256
$sessionList = SessionManager::get_sessions_by_user(api_get_user_id(), api_is_platform_admin());
257
$session_select_list = [];
258
foreach ($sessionList as $item) {
259
    $session_select_list[$item['session_id']] = $item['session_name'];
260
}
261
$select_session_html = Display::select(
262
    'session_id',
263
    $session_select_list,
264
    $session_id,
265
    ['onchange' => 'submit_form(this)']
266
);
267
echo Display::form_row(get_lang('Session'), $select_session_html);
268
269
// Course list, get course list of session, or for course where user is admin
270
if (!empty($session_id) && $session_id != '-1' && !empty($sessionList)) {
271
    $sessionInfo = [];
272
    foreach ($sessionList as $session) {
273
        if ($session['session_id'] == $session_id) {
274
            $sessionInfo = $session;
275
        }
276
    }
277
    $course_list = $sessionInfo['courses'];
278
} else {
279
    if (api_is_platform_admin()) {
280
        $course_list = CourseManager::get_courses_list(0, 0, 'title');
281
    } else {
282
        $course_list = CourseManager::get_course_list_of_user_as_course_admin(api_get_user_id());
283
    }
284
285
    // Admin fix, add the current course in the question pool.
286
    if (api_is_platform_admin()) {
287
        $courseInfo = api_get_course_info();
288
        if (!empty($course_list)) {
289
            if (!in_array($courseInfo['real_id'], $course_list)) {
290
                $course_list = array_merge($course_list, [$courseInfo]);
291
            }
292
        } else {
293
            $course_list = [$courseInfo];
294
        }
295
    }
296
}
297
298
$course_select_list = [];
299
foreach ($course_list as $item) {
300
    $courseItemId = $item['real_id'];
301
    $courseInfo = api_get_course_info_by_id($courseItemId);
302
    $course_select_list[$courseItemId] = '';
303
    if ($courseItemId == api_get_course_int_id()) {
304
        $course_select_list[$courseItemId] = ">&nbsp;&nbsp;&nbsp;&nbsp;";
305
    }
306
    $course_select_list[$courseItemId] .= $courseInfo['title'];
307
}
308
309
$select_course_html = Display::select(
310
    'selected_course',
311
    $course_select_list,
312
    $selected_course,
313
    ['onchange' => 'mark_course_id_changed(); submit_form(this);']
314
);
315
316
echo Display::form_row(get_lang('Course'), $select_course_html);
317
318
if (empty($selected_course) || $selected_course == '-1') {
319
    $course_info = api_get_course_info();
320
    // no course selected, reset menu test / difficult� / type de reponse
321
    reset_menu_exo_lvl_type();
322
} else {
323
    $course_info = api_get_course_info_by_id($selected_course);
324
}
325
// If course has changed, reset the menu default
326
if ($course_id_changed) {
327
    reset_menu_exo_lvl_type();
328
}
329
330
$course_id = $course_info['real_id'];
331
332
// Get category list for the course $selected_course
333
$categoryList = TestCategory::getCategoriesIdAndName($selected_course);
334
$selectCourseCategory = Display::select(
335
    'courseCategoryId',
336
    $categoryList,
337
    $courseCategoryId,
338
    ['onchange' => 'submit_form(this);'],
339
    false
340
);
341
echo Display::form_row(get_lang('QuestionCategory'), $selectCourseCategory);
342
343
// Get exercise list for this course
344
$exercise_list = ExerciseLib::get_all_exercises_for_course_id(
345
    $course_info,
346
    $session_id,
347
    $selected_course,
348
    false
349
);
350
351
// Exercise List
352
$my_exercise_list = [];
353
$my_exercise_list['0'] = get_lang('AllExercises');
354
$my_exercise_list['-1'] = get_lang('OrphanQuestions');
355
if (is_array($exercise_list)) {
356
    foreach ($exercise_list as $row) {
357
        $my_exercise_list[$row['id']] = '';
358
        if ($row['id'] == $fromExercise && $selected_course == api_get_course_int_id()) {
359
            $my_exercise_list[$row['id']] = ">&nbsp;&nbsp;&nbsp;&nbsp;";
360
        }
361
        $my_exercise_list[$row['id']] .= $row['title'];
362
    }
363
}
364
365
if ($exercise_id_changed == 1) {
366
    reset_menu_lvl_type();
367
}
368
369
$select_exercise_html = Display::select(
370
    'exerciseId',
371
    $my_exercise_list,
372
    $exerciseId,
373
    ['onchange' => 'mark_exercise_id_changed(); submit_form(this);'],
374
    false
375
);
376
377
echo Display::form_row(get_lang('Exercise'), $select_exercise_html);
378
379
// Difficulty list (only from 0 to 5)
380
$levels = [
381
    -1 => get_lang('All'),
382
    0 => 0,
383
    1 => 1,
384
    2 => 2,
385
    3 => 3,
386
    4 => 4,
387
    5 => 5,
388
];
389
390
$select_difficulty_html = Display::select(
391
    'exerciseLevel',
392
    $levels,
393
    $exerciseLevel,
394
    ['onchange' => 'submit_form(this);'],
395
    false
396
);
397
echo Display::form_row(get_lang('Difficulty'), $select_difficulty_html);
398
399
// Answer type
400
$question_list = Question::get_question_type_list();
401
402
$new_question_list = [];
403
$new_question_list['-1'] = get_lang('All');
404
if (!empty($_course)) {
405
    $objExercise = new Exercise();
406
    $objExercise->read($fromExercise);
407
    foreach ($question_list as $key => $item) {
408
        if ($objExercise->feedback_type == EXERCISE_FEEDBACK_TYPE_DIRECT) {
409
            if (!in_array($key, [HOT_SPOT_DELINEATION, UNIQUE_ANSWER])) {
410
                continue;
411
            }
412
            $new_question_list[$key] = get_lang($item[1]);
413
        } else {
414
            if ($key == HOT_SPOT_DELINEATION) {
415
                continue;
416
            }
417
            $new_question_list[$key] = get_lang($item[1]);
418
        }
419
    }
420
}
421
422
// Answer type list
423
$select_answer_html = Display::select(
424
    'answerType',
425
    $new_question_list,
426
    $answerType,
427
    ['onchange' => 'submit_form(this);'],
428
    false
429
);
430
431
echo Display::form_row(get_lang('AnswerType'), $select_answer_html);
432
echo Display::form_row(get_lang('Id'), Display::input('text', 'question_id', $questionId));
433
echo Display::form_row(
434
    get_lang('Description'),
435
    Display::input('text', 'description', Security::remove_XSS($description))
436
);
437
438
$button = '<button class="btn btn-primary save" type="submit" name="name" value="'.get_lang('Filter').'">'.
439
    get_lang('Filter').'</button>';
440
echo Display::form_row('', $button);
441
echo "<input type='hidden' id='course_id_changed' name='course_id_changed' value='0' />";
442
echo "<input type='hidden' id='exercise_id_changed' name='exercise_id_changed' value='0' />";
443
?>
444
</form>
445
<div class="clear"></div>
446
<?php
447
448
function getQuestions(
449
    $getCount,
450
    $start,
451
    $length,
452
    $exerciseId,
453
    $courseCategoryId,
454
    $selected_course,
455
    $session_id,
456
    $exerciseLevel,
457
    $answerType,
458
    $questionId,
459
    $description
460
) {
461
    $start = (int) $start;
462
    $length = (int) $length;
463
    $exerciseId = (int) $exerciseId;
464
    $courseCategoryId = (int) $courseCategoryId;
465
    $selected_course = (int) $selected_course;
466
    $session_id = (int) $session_id;
467
    $exerciseLevel = (int) $exerciseLevel;
468
    $answerType = (int) $answerType;
469
    $questionId = (int) $questionId;
470
    $description  = Database::escape_string($description);
471
472
    $TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
473
    $TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST);
474
    $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
475
    $TBL_COURSE_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
476
477
    // if we have selected an exercise in the list-box 'Filter'
478
    if ($exerciseId > 0) {
479
        $where = '';
480
        $from = '';
481
        if (isset($courseCategoryId) && $courseCategoryId > 0) {
482
            $from = ", $TBL_COURSE_REL_CATEGORY crc ";
483
            $where .= " AND 
484
                    crc.c_id = $selected_course AND 
485
                    crc.question_id = qu.id AND 
486
                    crc.category_id = $courseCategoryId";
487
        }
488
        if (isset($exerciseLevel) && $exerciseLevel != -1) {
489
            $where .= ' AND level='.$exerciseLevel;
490
        }
491
        if (isset($answerType) && $answerType > 0) {
492
            $where .= ' AND type='.$answerType;
493
        }
494
495
        if (!empty($questionId)) {
496
            $where .= ' AND qu.iid='.$questionId;
497
        }
498
499
        if (!empty($description)) {
500
            $where .= " AND qu.description LIKE '%$description%'";
501
        }
502
503
        $select = 'DISTINCT
504
                    id,
505
                    question,
506
                    type,
507
                    level,  
508
                    qt.exercice_id exerciseId';
509
        if ($getCount) {
510
            $select = 'count(qu.iid) as count';
511
        }
512
        $sql = "SELECT $select
513
                FROM
514
                    $TBL_EXERCISE_QUESTION qt,
515
                    $TBL_QUESTIONS qu
516
                    $from
517
                WHERE
518
                    qt.question_id = qu.id AND 
519
                    qt.exercice_id = $exerciseId AND 
520
                    qt.c_id = $selected_course  AND 
521
                    qu.c_id = $selected_course
522
                    $where
523
                ORDER BY question_order";
524
    } elseif ($exerciseId == -1) {
525
        // If we have selected the option 'Orphan questions' in the list-box 'Filter'
526
        $level_where = '';
527
        $from = '';
528
        if (isset($courseCategoryId) && $courseCategoryId > 0) {
529
            $from = " INNER JOIN $TBL_COURSE_REL_CATEGORY crc 
530
                      ON crc.question_id = q.id AND crc.c_id = q.c_id ";
531
            $level_where .= " AND
532
                    crc.c_id = $selected_course AND
533
                    crc.category_id = $courseCategoryId";
534
        }
535
        if (isset($exerciseLevel) && $exerciseLevel != -1) {
536
            $level_where = ' AND level='.$exerciseLevel;
537
        }
538
        $answer_where = '';
539
        if (isset($answerType) && $answerType > 0 - 1) {
540
            $answer_where = ' AND type='.$answerType;
541
        }
542
543
        if (!empty($questionId)) {
544
            $answer_where .= ' AND q.iid='.$questionId;
545
        }
546
547
        if (!empty($description)) {
548
            $answer_where .= " AND q.description LIKE '%$description%'";
549
        }
550
551
        $select = ' q.*, r.exercice_id exerciseId  ';
552
        if ($getCount) {
553
            $select = 'count(q.iid) as count';
554
        }
555
556
        // @todo fix this query with the new id field
557
        $sql = " (
558
                    SELECT $select
559
                    FROM $TBL_QUESTIONS q
560
                    INNER JOIN $TBL_EXERCISE_QUESTION r
561
                    ON (q.c_id = r.c_id AND q.id = r.question_id)
562
                    INNER JOIN $TBL_EXERCISES ex
563
                    ON (ex.id = r.exercice_id AND ex.c_id = r.c_id)
564
                    $from
565
                    WHERE
566
                        ex.c_id = '$selected_course' AND
567
                        ex.active = '-1'
568
                        $level_where 
569
                        $answer_where
570
                )                  
571
                UNION                 
572
                (
573
                    SELECT $select
574
                    FROM $TBL_QUESTIONS q
575
                    LEFT OUTER JOIN $TBL_EXERCISE_QUESTION r
576
                    ON (q.c_id = r.c_id AND q.id = r.question_id)
577
                    $from
578
                    WHERE
579
                        q.c_id = '$selected_course' AND
580
                        r.question_id is null
581
                        $level_where 
582
                        $answer_where
583
                )                  
584
                UNION                 
585
                (
586
                        SELECT $select
587
                        FROM $TBL_QUESTIONS q
588
                        INNER JOIN $TBL_EXERCISE_QUESTION r
589
                        ON (q.c_id = r.c_id AND q.id = r.question_id)
590
                        $from
591
                        WHERE
592
                            r.c_id = '$selected_course' AND
593
                            (r.exercice_id = '-1' OR r.exercice_id = '0')
594
                            $level_where 
595
                            $answer_where
596
                    ) 
597
                 ";
598
        if ($getCount) {
599
            $sql = "SELECT SUM(count) count FROM ($sql) as total";
600
        }
601
    } else {
602
        // All tests for selected course
603
        // If we have not selected any option in the list-box 'Filter'
604
        $filter = '';
605
        $from = '';
606
        if (isset($courseCategoryId) && $courseCategoryId > 0) {
607
            $from = ", $TBL_COURSE_REL_CATEGORY crc ";
608
            $filter .= " AND
609
                        crc.c_id = $selected_course AND
610
                        crc.question_id = qu.id AND
611
                        crc.category_id = $courseCategoryId";
612
        }
613
        if (isset($exerciseLevel) && $exerciseLevel != -1) {
614
            $filter .= ' AND level='.$exerciseLevel.' ';
615
        }
616
        if (isset($answerType) && $answerType > 0) {
617
            $filter .= ' AND qu.type='.$answerType.' ';
618
        }
619
620
        if (!empty($questionId)) {
621
            $filter .= ' AND qu.iid='.$questionId;
622
        }
623
624
        if (!empty($description)) {
625
            $filter .= " AND qu.description LIKE '%$description%'";
626
        }
627
628
        if ($session_id == -1 || empty($session_id)) {
629
            $session_id = 0;
630
        }
631
        $sessionCondition = api_get_session_condition($session_id, true, 'q.session_id');
632
633
        $select = 'qu.id, question, qu.type, level, q.session_id, qt.exercice_id exerciseId  ';
634
        if ($getCount) {
635
            $select = 'count(qu.iid) as count';
636
        }
637
638
        // All tests for the course selected, not in session
639
        $sql = "SELECT DISTINCT
640
                    $select
641
                FROM
642
                $TBL_QUESTIONS as qu,
643
                $TBL_EXERCISE_QUESTION as qt,
644
                $TBL_EXERCISES as q
645
                $from
646
                WHERE
647
                    qu.c_id = $selected_course AND
648
                    qt.c_id = $selected_course AND
649
                    q.c_id = $selected_course AND
650
                    qu.id = qt.question_id
651
                    $sessionCondition AND
652
                    q.id = qt.exercice_id
653
                    $filter
654
                ORDER BY session_id ASC";
655
    }
656
657
    if ($getCount) {
658
        $result = Database::query($sql);
659
        $row = Database::fetch_array($result, 'ASSOC');
660
661
        return (int) $row['count'];
662
    }
663
664
    $sql .= " LIMIT $start, $length";
665
666
    $result = Database::query($sql);
667
668
    $mainQuestionList = [];
669
    while ($row = Database::fetch_array($result, 'ASSOC')) {
670
        $mainQuestionList[] = $row;
671
    }
672
673
    return $mainQuestionList;
674
}
675
676
$nbrQuestions = getQuestions(
677
    true,
678
    null,
679
    null,
680
    $exerciseId,
681
    $courseCategoryId,
682
    $selected_course,
683
    $session_id,
684
    $exerciseLevel,
685
    $answerType,
686
    $questionId,
687
    $description
688
);
689
690
$length = api_get_configuration_value('question_pagination_length');
691
if (empty($length)) {
692
    $length = 20;
693
}
694
695
$start = ($page - 1) * $length;
696
697
$paginator = new Paginator();
698
$pagination = $paginator->paginate([]);
699
$pagination->setTotalItemCount($nbrQuestions);
700
$pagination->setItemNumberPerPage($length);
701
$pagination->setCurrentPageNumber($page);
702
703
$pagination->renderer = function ($data) use ($url) {
704
    $render = '';
705
    if ($data['pageCount'] > 1) {
706
        $render = '<ul class="pagination">';
707
        for ($i = 1; $i <= $data['pageCount']; $i++) {
708
            $page = (int) $i;
709
            $pageContent = '<li><a href="'.$url.'&page='.$page.'">'.$page.'</a></li>';
710
            if ($data['current'] == $page) {
711
                $pageContent = '<li class="active"><a href="#" >'.$page.'</a></li>';
712
            }
713
            $render .= $pageContent;
714
        }
715
        $render .= '</ul>';
716
    }
717
718
    return $render;
719
};
720
721
$mainQuestionList = getQuestions(
722
    false,
723
    $start,
724
    $length,
725
    $exerciseId,
726
    $courseCategoryId,
727
    $selected_course,
728
    $session_id,
729
    $exerciseLevel,
730
    $answerType,
731
    $questionId,
732
    $description
733
);
734
735
// build the line of the array to display questions
736
// Actions are different if you launch the question_pool page
737
// They are different too if you have displayed questions from your course
738
// Or from another course you are the admin(or session admin)
739
// from a test or not
740
/*
741
+--------------------------------------------+--------------------------------------------+
742
|   NOT IN A TEST                            |         IN A TEST                          |
743
+----------------------+---------------------+---------------------+----------------------+
744
|IN THE COURSE (*)  "x | NOT IN THE COURSE o | IN THE COURSE    +  | NOT IN THE COURSE  o |
745
+----------------------+---------------------+---------------------+----------------------+
746
|Edit the question     | Do nothing          | Add question to test|Clone question in test|
747
|Delete the question   |                     |                     |                      |
748
|(true delete)         |                     |                     |                      |
749
+----------------------+---------------------+---------------------+----------------------+
750
(*) this is the only way to delete or modify orphan questions
751
*/
752
753
if ($fromExercise <= 0) {
754
    // NOT IN A TEST - NOT IN THE COURSE
755
    $actionLabel = get_lang('Reuse');
756
    $actionIcon1 = get_lang('MustBeInATest');
757
    $actionIcon2 = '';
758
    // We are not in this course, to messy if we link to the question in another course
759
    $questionTagA = 0;
760
    if ($selected_course == api_get_course_int_id()) {
761
        // NOT IN A TEST - IN THE COURSE
762
        $actionLabel = get_lang('Modify');
763
        $actionIcon1 = 'edit';
764
        $actionIcon2 = 'delete';
765
        // We are in the course, question title can be a link to the question edit page
766
        $questionTagA = 1;
767
    }
768
} else {
769
    // IN A TEST - NOT IN THE COURSE
770
    $actionLabel = get_lang('Reuse');
771
    $actionIcon1 = 'clone';
772
    $actionIcon2 = '';
773
    $questionTagA = 0;
774
775
    if ($selected_course == api_get_course_int_id()) {
776
        // IN A TEST - IN THE COURSE
777
        $actionLabel = get_lang('Reuse');
778
        $actionIcon1 = 'add';
779
        $actionIcon2 = '';
780
        $questionTagA = 1;
781
    }
782
}
783
784
$data = [];
785
if (is_array($mainQuestionList)) {
786
    foreach ($mainQuestionList as $question) {
787
        $row = [];
788
        // This function checks if the question can be read
789
        $question_type = get_question_type_for_question($selected_course, $question['id']);
790
791
        if (empty($question_type)) {
792
            continue;
793
        }
794
795
        $sessionId = isset($question['session_id']) ? $question['session_id'] : null;
796
        $exerciseName = isset($question['exercise_name']) ? '<br />('.$question['exercise_id'].') ' : null;
797
        $row[] = getLinkForQuestion(
798
            $questionTagA,
799
            $fromExercise,
800
            $question['id'],
801
            $question['type'],
802
            $question['question'],
803
            $sessionId,
804
            $question['exerciseId']
805
        ).$exerciseName;
806
        $row[] = $question_type;
807
        $row[] = TestCategory::getCategoryNameForQuestion($question['id'], $selected_course);
808
        $row[] = $question['level'];
809
        $row[] = get_action_icon_for_question(
810
            $actionIcon1,
811
            $fromExercise,
812
            $question['id'],
813
            $question['type'],
814
            $question['question'],
815
            $selected_course,
816
            $courseCategoryId,
817
            $exerciseLevel,
818
            $answerType,
819
            $session_id,
820
            $question['exerciseId']
821
        ).'&nbsp;'.
822
        get_action_icon_for_question(
823
            $actionIcon2,
824
            $fromExercise,
825
            $question['id'],
826
            $question['type'],
827
            $question['question'],
828
            $selected_course,
829
            $courseCategoryId,
830
            $exerciseLevel,
831
            $answerType,
832
            $session_id,
833
            $question['exerciseId']
834
        );
835
        $data[] = $row;
836
    }
837
}
838
839
// Display table
840
$header = [
841
    [
842
        get_lang('QuestionUpperCaseFirstLetter'),
843
        false,
844
        ['style' => 'text-align:center'],
845
        '',
846
    ],
847
    [
848
        get_lang('Type'),
849
        false,
850
        ['style' => 'text-align:center'],
851
        ['style' => 'text-align:center'],
852
        '',
853
    ],
854
    [
855
        get_lang('QuestionCategory'),
856
        false,
857
        ['style' => 'text-align:center'],
858
        ['style' => 'text-align:center'],
859
        '',
860
    ],
861
    [
862
        get_lang('Difficulty'),
863
        false,
864
        ['style' => 'text-align:center'],
865
        ['style' => 'text-align:center'],
866
        '',
867
    ],
868
    [
869
        $actionLabel,
870
        false,
871
        ['style' => 'text-align:center'],
872
        ['style' => 'text-align:center'],
873
        '',
874
    ],
875
];
876
877
echo $pagination;
878
879
Display::display_sortable_table(
880
    $header,
881
    $data,
882
    '',
883
    ['per_page_default' => 999, 'per_page' => 999, 'page_nr' => 1]
884
);
885
886
Display::display_footer();
887
888
/**
889
 * Put the menu entry for level and type to default "Choice"
890
 * It is useful if you change the exercise, you need to reset the other menus.
891
 *
892
 * @author hubert.borderiou 13-10-2011
893
 */
894
function reset_menu_lvl_type()
895
{
896
    global $exerciseLevel, $answerType;
897
    $answerType = -1;
898
    $exerciseLevel = -1;
899
}
900
901
/**
902
 * Put the menu entry for exercise and level and type to default "Choice"
903
 * It is useful if you change the course, you need to reset the other menus.
904
 *
905
 * @author hubert.borderiou 13-10-2011
906
 */
907
function reset_menu_exo_lvl_type()
908
{
909
    global $exerciseId, $courseCategoryId;
910
    reset_menu_lvl_type();
911
    $exerciseId = 0;
912
    $courseCategoryId = 0;
913
}
914
915
/**
916
 * return the <a> link to admin question, if needed.
917
 *
918
 * @param int    $in_addA
919
 * @param int    $in_fromex
920
 * @param int    $questionId
921
 * @param int    $questiontype
922
 * @param string $questionName
923
 * @param int    $sessionId
924
 * @param int    $exerciseId
925
 *
926
 * @return string
927
 *
928
 * @author hubert.borderiou
929
 */
930
function getLinkForQuestion(
931
    $in_addA,
932
    $fromExercise,
933
    $questionId,
934
    $questionType,
935
    $questionName,
936
    $sessionId,
937
    $exerciseId
938
) {
939
    $result = $questionName;
940
    if ($in_addA) {
941
        $sessionIcon = '';
942
        if (!empty($sessionId) && $sessionId != -1) {
943
            $sessionIcon = ' '.Display::return_icon('star.png', get_lang('Session'));
944
        }
945
        $exerciseId = (int) $exerciseId;
946
        $questionId = (int) $questionId;
947
        $questionType = (int) $questionType;
948
        $fromExercise = (int) $fromExercise;
949
950
        $result = Display::url(
951
            $questionName.$sessionIcon,
952
            "admin.php?".api_get_cidreq().
953
            "&exerciseId=$exerciseId&editQuestion=$questionId&type=$questionType&fromExercise=$fromExercise"
954
        );
955
    }
956
957
    return $result;
958
}
959
960
/**
961
    Return the <a> html code for delete, add, clone, edit a question
962
    in_action = the code of the action triggered by the button
963
    from_exercise = the id of the current exercise from which we click on question pool
964
    in_questionid = the id of the current question
965
    in_questiontype = the code of the type of the current question
966
    in_questionname = the name of the question
967
    in_selected_course = the if of the course chosen in the FILTERING MENU
968
    in_courseCategoryId = the id of the category chosen in the FILTERING MENU
969
    in_exerciseLevel = the level of the exercise chosen in the FILTERING MENU
970
    in_answerType = the code of the type of the question chosen in the FILTERING MENU
971
    in_session_id = the id of the session_id chosen in the FILTERING MENU
972
    in_exercise_id = the id of the exercise chosen in the FILTERING MENU
973
 */
974
function get_action_icon_for_question(
975
    $in_action,
976
    $from_exercise,
977
    $in_questionid,
978
    $in_questiontype,
979
    $in_questionname,
980
    $in_selected_course,
981
    $in_courseCategoryId,
982
    $in_exerciseLevel,
983
    $in_answerType,
984
    $in_session_id,
985
    $in_exercise_id
986
) {
987
    $limitTeacherAccess = api_get_configuration_value('limit_exercise_teacher_access');
988
    $getParams = "&selected_course=$in_selected_course&courseCategoryId=$in_courseCategoryId&exerciseId=$in_exercise_id&exerciseLevel=$in_exerciseLevel&answerType=$in_answerType&session_id=$in_session_id";
989
    $res = '';
990
    switch ($in_action) {
991
        case 'delete':
992
            if ($limitTeacherAccess && !api_is_platform_admin()) {
993
                break;
994
            }
995
            $res = "<a href='".api_get_self()."?".
996
                api_get_cidreq().$getParams."&delete=$in_questionid' onclick='return confirm_your_choice()'>";
997
            $res .= Display::return_icon('delete.png', get_lang('Delete'));
998
            $res .= "</a>";
999
            break;
1000
        case 'edit':
1001
            $res = getLinkForQuestion(
1002
                1,
1003
                $from_exercise,
1004
                $in_questionid,
1005
                $in_questiontype,
1006
                Display::return_icon('edit.png', get_lang('Modify')),
1007
                $in_session_id,
1008
                $in_exercise_id
1009
            );
1010
            break;
1011
        case 'add':
1012
            // add if question is not already in test
1013
            $myObjEx = new Exercise();
1014
            $myObjEx->read($from_exercise);
1015
            $res = "-";
1016
            if (!$myObjEx->isInList($in_questionid)) {
1017
                $res = "<a href='".api_get_self()."?".
1018
                    api_get_cidreq().$getParams."&recup=$in_questionid&fromExercise=$from_exercise'>";
1019
                $res .= Display::return_icon("view_more_stats.gif", get_lang('InsertALinkToThisQuestionInTheExercise'));
1020
                $res .= "</a>";
1021
            }
1022
            unset($myObjEx);
1023
            break;
1024
        case 'clone':
1025
            $url = api_get_self()."?".api_get_cidreq().$getParams.
1026
                "&question_copy=$in_questionid&course_id=$in_selected_course&fromExercise=$from_exercise";
1027
            $res = Display::url(
1028
                Display::return_icon('cd.png', get_lang('ReUseACopyInCurrentTest')),
1029
                $url
1030
            );
1031
            break;
1032
        default:
1033
            $res = $in_action;
1034
            break;
1035
    }
1036
1037
    return $res;
1038
}
1039
1040
/**
1041
 * Return the icon for the question type.
1042
 *
1043
 * @author hubert.borderiou 13-10-2011
1044
 */
1045
function get_question_type_for_question($in_selectedcourse, $in_questionid)
1046
{
1047
    $myObjQuestion = Question::read($in_questionid, $in_selectedcourse);
1048
    $questionType = null;
1049
    if (!empty($myObjQuestion)) {
1050
        list($typeImg, $typeExpl) = $myObjQuestion->get_type_icon_html();
1051
        $questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, [], 32), []);
1052
    }
1053
1054
    return $questionType;
1055
}
1056