Issues (1798)

public/main/exercise/ReadingComprehension.php (1 issue)

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
/**
6
 * Class ReadingComprehension.
7
 *
8
 * This class allows to instantiate an object of type READING_COMPREHENSION
9
 * extending the class question
10
 */
11
class ReadingComprehension extends UniqueAnswer
12
{
13
    public $typePicture = 'reading-comprehension.png';
14
    public $explanationLangVar = 'Reading comprehension';
15
16
    /**
17
     * Defines the different speeds of scrolling for the reading window,
18
     * in words per minute. If 300 words text in 50w/m, then the moving
19
     * window will progress from top to bottom in 6 minutes.
20
     */
21
    public static $speeds = [
22
        1 => 50,
23
        2 => 100,
24
        3 => 175,
25
        4 => 300,
26
        5 => 600,
27
    ];
28
29
    /**
30
     * The number of words in the question description (which serves as the
31
     * text to read).
32
     *
33
     * @var int
34
     */
35
    public $wordsCount = 0;
36
37
    /**
38
     * Number of words expected to show per refresh.
39
     *
40
     * @var int
41
     */
42
    public $expectedWordsPerRefresh = 0;
43
44
    /**
45
     * Refresh delay in seconds.
46
     *
47
     * @var int
48
     */
49
    public $refreshTime = 3;
50
51
    /**
52
     * Indicates how show the question list.
53
     * 1 = all in one page; 2 = one per page (default).
54
     *
55
     * @var int
56
     */
57
    private $exerciseType = 2;
58
59
    public function __construct()
60
    {
61
        parent::__construct();
62
        $this->type = READING_COMPREHENSION;
63
        $this->isContent = $this->getIsContent();
64
    }
65
66
    public function processText($text)
67
    {
68
        // Refresh is set to 5s, but speed is in words per minute
69
        $wordsPerSecond = self::$speeds[$this->level] / 60;
70
        $this->expectedWordsPerRefresh = (int) ($wordsPerSecond * $this->refreshTime);
71
72
        if (empty($text)) {
73
            // We have an issue here... how do we treat this case?
74
            // For now, let's define a default case
75
            $text = get_lang('No tests');
76
        }
77
        $words = str_word_count($text, 2, '0..9');
78
        $indexes = array_keys($words);
79
80
        $tagEnd = '</span>';
81
        $tagStart = $tagEnd.'<span class="text-highlight">';
82
        $this->wordsCount = count($words);
83
84
        $turns = ceil(
85
            $this->wordsCount / $this->expectedWordsPerRefresh
86
        );
87
88
        $firstIndex = $indexes[0];
89
90
        for ($i = 1; $i <= $turns; $i++) {
91
            $text = substr_replace($text, $tagStart, $firstIndex, 0);
92
93
            if ($i * $this->expectedWordsPerRefresh <= count($words)) {
94
                $newIndex = $i * $this->expectedWordsPerRefresh;
95
                if (isset($indexes[$newIndex])) {
96
                    $nextFirstIndex = $indexes[$newIndex];
97
                    $firstIndex = $nextFirstIndex + (strlen($tagStart) * $i);
98
                }
99
            }
100
        }
101
102
        $pos = strpos($text, $tagEnd);
103
104
        $text = substr_replace($text, '', $pos, strlen($tagEnd));
105
        $text .= $tagEnd;
106
107
        $this->displayReading($this->wordsCount, $turns, $text);
108
    }
109
110
    /**
111
     * Returns total count of words of the text to read.
112
     *
113
     * @return int
114
     */
115
    public function getWordsCount()
116
    {
117
        $words = str_word_count($this->selectDescription(), 2, '0..9');
118
        $this->wordsCount = count($words);
119
120
        return $this->wordsCount;
121
    }
122
123
    public function createForm(&$form, $exercise)
124
    {
125
        // Categories
126
        $tabCat = TestCategory::getCategoriesIdAndName();
127
        $form->addSelect('questionCategory', get_lang('Category'), $tabCat);
128
        // Advanced parameters
129
        $levels = self::get_default_levels();
130
        $form->addSelect('questionLevel', get_lang('Difficulty'), $levels);
131
        $form->addElement('hidden', 'answerType', READING_COMPREHENSION);
132
        $form->addTextarea('questionDescription', get_lang('Text'), ['rows' => 20]);
133
        // question name
134
        if ('true' === api_get_setting('editor.save_titles_as_html')) {
135
            $editorConfig = ['ToolbarSet' => 'TitleAsHtml'];
136
            $form->addHtmlEditor(
137
                'questionName',
138
                get_lang('Question'),
139
                true,
140
                false,
141
                $editorConfig,
142
            );
143
        } else {
144
            $form->addText('questionName', get_lang('Question'), false);
145
        }
146
147
        // hidden values
148
        $form->addRule('questionName', get_lang('Please type the question'), 'required');
149
        $isContent = isset($_REQUEST['isContent']) ? (int) $_REQUEST['isContent'] : null;
150
151
        // default values
152
        $defaults = [];
153
        $defaults['questionName'] = $this->question;
154
        $defaults['questionDescription'] = $this->description;
155
        $defaults['questionLevel'] = $this->level;
156
        $defaults['questionCategory'] = $this->category;
157
158
        // Came from he question pool
159
        if (isset($_GET['fromExercise'])) {
160
            $form->setDefaults($defaults);
161
        }
162
163
        if (!isset($_GET['newQuestion']) || $isContent) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $isContent of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
164
            $form->setDefaults($defaults);
165
        }
166
    }
167
168
    public static function get_default_levels()
169
    {
170
        return [
171
            1 => sprintf(get_lang('%s words per minute'), self::$speeds[1]),
172
            2 => sprintf(get_lang('%s words per minute'), self::$speeds[2]),
173
            3 => sprintf(get_lang('%s words per minute'), self::$speeds[3]),
174
            4 => sprintf(get_lang('%s words per minute'), self::$speeds[4]),
175
            5 => sprintf(get_lang('%s words per minute'), self::$speeds[5]),
176
        ];
177
    }
178
179
    /**
180
     * @param int $type
181
     *
182
     * @return ReadingComprehension
183
     */
184
    public function setExerciseType($type)
185
    {
186
        $this->exerciseType = (int) $type;
187
188
        return $this;
189
    }
190
191
    /**
192
     * @param $wordsCount
193
     * @param $turns
194
     * @param $text
195
     */
196
    private function displayReading($wordsCount, $turns, $text)
197
    {
198
        $view = new Template('', false, false, false, true, false, false);
199
200
        $template = $view->get_template('exercise/reading_comprehension.tpl');
201
202
        $view->assign('id', $this->id);
203
        $view->assign('text', nl2br($text));
204
        $view->assign('words_count', $wordsCount);
205
        $view->assign('turns', $turns);
206
        $view->assign('refresh_time', $this->refreshTime);
207
        $view->assign('exercise_type', $this->exerciseType);
208
        $view->display($template);
209
    }
210
}
211