This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
0 ignored issues
–
show
|
|||
2 | if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly |
||
3 | |||
4 | /** |
||
5 | * Sensei Quiz Class |
||
6 | * |
||
7 | * All functionality pertaining to the quiz post type in Sensei. |
||
8 | * |
||
9 | * @package Assessment |
||
10 | * @author Automattic |
||
11 | * |
||
12 | * @since 1.0.0 |
||
13 | */ |
||
14 | class Sensei_Quiz { |
||
15 | public $token; |
||
16 | public $meta_fields; |
||
17 | public $file; |
||
18 | |||
19 | /** |
||
20 | * Constructor. |
||
21 | * @since 1.0.0 |
||
22 | * |
||
23 | * @param $file |
||
24 | */ |
||
25 | public function __construct ( $file = __FILE__ ) { |
||
26 | $this->file = $file; |
||
27 | $this->token = 'quiz'; |
||
28 | $this->meta_fields = array( 'quiz_passmark', 'quiz_lesson', 'quiz_type', 'quiz_grade_type', 'pass_required','enable_quiz_reset' ); |
||
29 | add_action( 'save_post', array( $this, 'update_author' )); |
||
30 | |||
31 | // listen to the reset button click |
||
32 | add_action( 'template_redirect', array( $this, 'reset_button_click_listener' ) ); |
||
33 | |||
34 | // fire the complete quiz button submit for grading action |
||
35 | add_action( 'sensei_single_quiz_content_inside_before', array( $this, 'user_quiz_submit_listener' ) ); |
||
36 | |||
37 | // fire the save user answers quiz button click responder |
||
38 | add_action( 'sensei_single_quiz_content_inside_before', array( $this, 'user_save_quiz_answers_listener' ) ); |
||
39 | |||
40 | // fire the load global data function |
||
41 | add_action( 'sensei_single_quiz_content_inside_before', array( $this, 'load_global_quiz_data' ), 80 ); |
||
42 | |||
43 | add_action( 'template_redirect', array ( $this, 'quiz_has_no_questions') ); |
||
44 | |||
45 | |||
46 | } // End __construct() |
||
47 | |||
48 | /** |
||
49 | * Update the quiz author when the lesson post type is save |
||
50 | * |
||
51 | * @param int $post_id |
||
52 | * @return void |
||
53 | */ |
||
54 | public function update_author( $post_id ){ |
||
55 | |||
56 | // If this isn't a 'lesson' post, don't update it. |
||
57 | // if this is a revision don't save it |
||
58 | if ( isset( $_POST['post_type'] ) && 'lesson' != $_POST['post_type'] |
||
59 | || wp_is_post_revision( $post_id ) ) { |
||
60 | |||
61 | return; |
||
62 | |||
63 | } |
||
64 | // get the lesson author id to be use late |
||
65 | $saved_post = get_post( $post_id ); |
||
66 | $new_lesson_author_id = $saved_post->post_author; |
||
67 | |||
68 | //get the lessons quiz |
||
69 | $lesson_quizzes = Sensei()->lesson->lesson_quizzes( $post_id ); |
||
70 | foreach ( (array) $lesson_quizzes as $quiz_item ) { |
||
71 | |||
72 | if( ! $quiz_item ) { |
||
73 | continue; |
||
74 | } |
||
75 | |||
76 | // setup the quiz items new author value |
||
77 | $my_post = array( |
||
78 | 'ID' => $quiz_item, |
||
79 | 'post_author' => $new_lesson_author_id |
||
80 | ); |
||
81 | |||
82 | // remove the action so that it doesn't fire again |
||
83 | remove_action( 'save_post', array( $this, 'update_author' )); |
||
84 | |||
85 | // Update the post into the database |
||
86 | wp_update_post( $my_post ); |
||
87 | } |
||
88 | |||
89 | return; |
||
90 | }// end update_author |
||
91 | |||
92 | |||
93 | /** |
||
94 | * Get the lesson this quiz belongs to |
||
95 | * |
||
96 | * @since 1.7.2 |
||
97 | * @param int $quiz_id |
||
98 | * @return int @lesson_id |
||
99 | */ |
||
100 | public function get_lesson_id( $quiz_id ){ |
||
101 | |||
102 | if( empty( $quiz_id ) || ! intval( $quiz_id ) > 0 ){ |
||
103 | global $post; |
||
104 | if( 'quiz' == get_post_type( $post ) ){ |
||
105 | $quiz_id = $post->ID; |
||
106 | }else{ |
||
107 | return false; |
||
108 | } |
||
109 | |||
110 | } |
||
111 | |||
112 | $quiz = get_post( $quiz_id ); |
||
113 | $lesson_id = $quiz->post_parent; |
||
114 | |||
115 | return $lesson_id; |
||
116 | |||
117 | } // end lesson |
||
118 | |||
119 | |||
120 | /** |
||
121 | * user_save_quiz_answers_listener |
||
122 | * |
||
123 | * This function hooks into the quiz page and accepts the answer form save post. |
||
124 | * @since 1.7.3 |
||
125 | * @return bool $saved; |
||
126 | */ |
||
127 | public function user_save_quiz_answers_listener(){ |
||
128 | |||
129 | View Code Duplication | if( ! isset( $_POST[ 'quiz_save' ]) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
130 | || !isset( $_POST[ 'sensei_question' ] ) |
||
131 | || empty( $_POST[ 'sensei_question' ] ) |
||
132 | || ! wp_verify_nonce( $_POST['woothemes_sensei_save_quiz_nonce'], 'woothemes_sensei_save_quiz_nonce' ) > 1 ) { |
||
133 | return; |
||
134 | } |
||
135 | |||
136 | global $post; |
||
137 | $lesson_id = $this->get_lesson_id( $post->ID ); |
||
138 | $quiz_answers = $_POST[ 'sensei_question' ]; |
||
139 | // call the save function |
||
140 | self::save_user_answers( $quiz_answers, $_FILES , $lesson_id , get_current_user_id() ); |
||
141 | |||
142 | // remove the hook as it should only fire once per click |
||
143 | remove_action( 'sensei_single_quiz_content_inside_before', 'user_save_quiz_answers_listener' ); |
||
144 | |||
145 | } // end user_save_quiz_answers_listener |
||
146 | |||
147 | /** |
||
148 | * Save the user answers for the given lesson's quiz |
||
149 | * |
||
150 | * For this function you must supply all three parameters. If will return false one is left out. |
||
151 | * |
||
152 | * @since 1.7.4 |
||
153 | * @access public |
||
154 | * |
||
155 | * @param array $quiz_answers |
||
156 | * @param array $files from global $_FILES |
||
157 | * @param int $lesson_id |
||
158 | * @param int $user_id |
||
159 | * |
||
160 | * @return false or int $answers_saved |
||
161 | */ |
||
162 | public static function save_user_answers( $quiz_answers, $files = array(), $lesson_id , $user_id = 0 ){ |
||
163 | |||
164 | if( ! ( $user_id > 0 ) ){ |
||
165 | $user_id = get_current_user_id(); |
||
166 | } |
||
167 | |||
168 | // make sure the parameters are valid before continuing |
||
169 | View Code Duplication | if( empty( $lesson_id ) || empty( $user_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
170 | || 'lesson' != get_post_type( $lesson_id ) |
||
171 | ||!get_userdata( $user_id ) |
||
172 | || !is_array( $quiz_answers ) ){ |
||
173 | |||
174 | return false; |
||
175 | |||
176 | } |
||
177 | |||
178 | |||
179 | // start the lesson before saving the data in case the user has not started the lesson |
||
180 | $activity_logged = Sensei_Utils::sensei_start_lesson( $lesson_id, $user_id ); |
||
0 ignored issues
–
show
$activity_logged is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
181 | |||
182 | //prepare the answers |
||
183 | $prepared_answers = self::prepare_form_submitted_answers( $quiz_answers , $files ); |
||
184 | |||
185 | // save the user data |
||
186 | $answers_saved = Sensei_Utils::add_user_data( 'quiz_answers', $lesson_id, $prepared_answers, $user_id ) ; |
||
187 | |||
188 | // were the answers saved correctly? |
||
189 | if( intval( $answers_saved ) > 0){ |
||
190 | |||
191 | // save transient to make retrieval faster |
||
192 | $transient_key = 'sensei_answers_'.$user_id.'_'.$lesson_id; |
||
193 | set_transient( $transient_key, $prepared_answers, 10 * DAY_IN_SECONDS ); |
||
194 | |||
195 | // update the message showed to user |
||
196 | Sensei()->frontend->messages = '<div class="sensei-message note">' . __( 'Quiz Saved Successfully.', 'woothemes-sensei' ) . '</div>'; |
||
197 | } |
||
198 | |||
199 | return $answers_saved; |
||
200 | |||
201 | }// end save_user_answers() |
||
202 | |||
203 | /** |
||
204 | * Get the user answers for the given lesson's quiz. |
||
205 | * |
||
206 | * This function returns the data that is stored on the lesson as meta and is not compatible with |
||
207 | * retrieving data for quiz answer before sensei 1.7.4 |
||
208 | * |
||
209 | * |
||
210 | * @since 1.7.4 |
||
211 | * @access public |
||
212 | * |
||
213 | * @param int $lesson_id |
||
214 | * @param int $user_id |
||
215 | * |
||
216 | * @return array $answers or false |
||
217 | */ |
||
218 | public function get_user_answers( $lesson_id, $user_id ){ |
||
219 | |||
220 | $answers = false; |
||
221 | |||
222 | View Code Duplication | if ( ! intval( $lesson_id ) > 0 || 'lesson' != get_post_type( $lesson_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
223 | || ! intval( $user_id ) > 0 || !get_userdata( $user_id ) ) { |
||
224 | return false; |
||
225 | } |
||
226 | |||
227 | // save some time and get the transient cached data |
||
228 | $transient_key = 'sensei_answers_'.$user_id.'_'.$lesson_id; |
||
229 | $transient_cached_answers = get_transient( $transient_key ); |
||
230 | |||
231 | // return the transient or get the values get the values from the comment meta |
||
232 | if( !empty( $transient_cached_answers ) && false != $transient_cached_answers ){ |
||
233 | |||
234 | $encoded_user_answers = $transient_cached_answers; |
||
235 | |||
236 | }else{ |
||
237 | |||
238 | $encoded_user_answers = Sensei_Utils::get_user_data( 'quiz_answers', $lesson_id , $user_id ); |
||
239 | |||
240 | } // end if transient check |
||
241 | |||
242 | if( ! is_array( $encoded_user_answers ) ){ |
||
243 | return false; |
||
244 | } |
||
245 | |||
246 | //set the transient with the new valid data for faster retrieval in future |
||
247 | set_transient( $transient_key, $encoded_user_answers, 10 * DAY_IN_SECONDS); |
||
248 | |||
249 | // decode an unserialize all answers |
||
250 | foreach( $encoded_user_answers as $question_id => $encoded_answer ) { |
||
251 | $decoded_answer = base64_decode( $encoded_answer ); |
||
252 | $answers[$question_id] = maybe_unserialize( $decoded_answer ); |
||
253 | } |
||
254 | |||
255 | return $answers; |
||
256 | |||
257 | }// end get_user_answers() |
||
258 | |||
259 | |||
260 | /** |
||
261 | * |
||
262 | * This function runs on the init hook and checks if the reset quiz button was clicked. |
||
263 | * |
||
264 | * @since 1.7.2 |
||
265 | * @hooked init |
||
266 | * |
||
267 | * @return void; |
||
0 ignored issues
–
show
The doc-type
void; could not be parsed: Expected "|" or "end of type", but got ";" at position 4. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
268 | */ |
||
269 | public function reset_button_click_listener( ){ |
||
270 | |||
271 | if( ! isset( $_POST[ 'quiz_reset' ]) |
||
272 | || ! wp_verify_nonce( $_POST['woothemes_sensei_reset_quiz_nonce'], 'woothemes_sensei_reset_quiz_nonce' ) > 1 ) { |
||
273 | |||
274 | return; // exit |
||
275 | } |
||
276 | |||
277 | global $post; |
||
278 | $current_quiz_id = $post->ID; |
||
279 | $lesson_id = $this->get_lesson_id( $current_quiz_id ); |
||
280 | |||
281 | // reset all user data |
||
282 | $this->reset_user_lesson_data( $lesson_id, get_current_user_id() ); |
||
283 | |||
284 | //this function should only run once |
||
285 | remove_action( 'template_redirect', array( $this, 'reset_button_click_listener' ) ); |
||
286 | |||
287 | } // end reset_button_click_listener |
||
288 | |||
289 | /** |
||
290 | * Complete/ submit quiz hooked function |
||
291 | * |
||
292 | * This function listens to the complete button submit action and processes the users submitted answers |
||
293 | * not that this function submits the given users quiz answers for grading. |
||
294 | * |
||
295 | * @since 1.7.4 |
||
296 | * @access public |
||
297 | * |
||
298 | * @since |
||
299 | * @return void |
||
300 | */ |
||
301 | public function user_quiz_submit_listener() { |
||
302 | |||
303 | // only respond to valid quiz completion submissions |
||
304 | View Code Duplication | if( ! isset( $_POST[ 'quiz_complete' ]) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
305 | || !isset( $_POST[ 'sensei_question' ] ) |
||
306 | || empty( $_POST[ 'sensei_question' ] ) |
||
307 | || ! wp_verify_nonce( $_POST['woothemes_sensei_complete_quiz_nonce'], 'woothemes_sensei_complete_quiz_nonce' ) > 1 ) { |
||
308 | return; |
||
309 | } |
||
310 | |||
311 | global $post, $current_user; |
||
312 | $lesson_id = $this->get_lesson_id( $post->ID ); |
||
313 | $quiz_answers = $_POST[ 'sensei_question' ]; |
||
314 | |||
315 | self::submit_answers_for_grading( $quiz_answers, $_FILES , $lesson_id , $current_user->ID ); |
||
316 | |||
317 | } // End sensei_complete_quiz() |
||
318 | |||
319 | /** |
||
320 | * This function set's up the data need for the quiz page |
||
321 | * |
||
322 | * This function hooks into sensei_complete_quiz and load the global data for the |
||
323 | * current quiz. |
||
324 | * |
||
325 | * @since 1.7.4 |
||
326 | * @access public |
||
327 | * |
||
328 | */ |
||
329 | public function load_global_quiz_data(){ |
||
330 | |||
331 | global $post, $current_user; |
||
332 | $this->data = new stdClass(); |
||
333 | |||
334 | // Default grade |
||
335 | $grade = 0; |
||
0 ignored issues
–
show
$grade is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
336 | |||
337 | // Get Quiz Questions |
||
338 | $lesson_quiz_questions = Sensei()->lesson->lesson_quiz_questions( $post->ID ); |
||
339 | |||
340 | $quiz_lesson_id = absint( get_post_meta( $post->ID, '_quiz_lesson', true ) ); |
||
341 | |||
342 | // Get quiz grade type |
||
343 | $quiz_grade_type = get_post_meta( $post->ID, '_quiz_grade_type', true ); |
||
344 | |||
345 | // Get quiz pass setting |
||
346 | $pass_required = get_post_meta( $post->ID, '_pass_required', true ); |
||
0 ignored issues
–
show
$pass_required is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
347 | |||
348 | // Get quiz pass mark |
||
349 | $quiz_passmark = abs( round( doubleval( get_post_meta( $post->ID, '_quiz_passmark', true ) ), 2 ) ); |
||
350 | |||
351 | // Get latest quiz answers and grades |
||
352 | $lesson_id = Sensei()->quiz->get_lesson_id( $post->ID ); |
||
353 | $user_quizzes = Sensei()->quiz->get_user_answers( $lesson_id, get_current_user_id() ); |
||
354 | $user_lesson_status = Sensei_Utils::user_lesson_status( $quiz_lesson_id, $current_user->ID ); |
||
355 | $user_quiz_grade = 0; |
||
356 | if( isset( $user_lesson_status->comment_ID ) ) { |
||
357 | $user_quiz_grade = get_comment_meta( $user_lesson_status->comment_ID, 'grade', true ); |
||
358 | } |
||
359 | |||
360 | if ( ! is_array($user_quizzes) ) { $user_quizzes = array(); } |
||
0 ignored issues
–
show
$user_quizzes is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
361 | |||
362 | // Check again that the lesson is complete |
||
363 | $user_lesson_end = Sensei_Utils::user_completed_lesson( $user_lesson_status ); |
||
0 ignored issues
–
show
$user_lesson_status is of type object , but the function expects a integer .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
364 | $user_lesson_complete = false; |
||
365 | if ( $user_lesson_end ) { |
||
366 | $user_lesson_complete = true; |
||
367 | } // End If Statement |
||
368 | |||
369 | $reset_allowed = get_post_meta( $post->ID, '_enable_quiz_reset', true ); |
||
370 | //backwards compatibility |
||
371 | if( 'on' == $reset_allowed ) { |
||
372 | $reset_allowed = 1; |
||
373 | } |
||
374 | |||
375 | // Build frontend data object for backwards compatibility |
||
376 | // using this is no longer recommended |
||
377 | $this->data->user_quiz_grade = $user_quiz_grade;// Sensei_Quiz::get_user_quiz_grade( $lesson_id, get_current_user_id() ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
54% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
378 | $this->data->quiz_passmark = $quiz_passmark; |
||
379 | $this->data->quiz_lesson = $quiz_lesson_id; |
||
380 | $this->data->quiz_grade_type = $quiz_grade_type; // get_post_meta( $quiz_id, '_quiz_grade_type', true ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
381 | $this->data->user_lesson_end = $user_lesson_end; |
||
382 | $this->data->user_lesson_complete = $user_lesson_complete; //Sensei_Utils::user_completed_lesson( $lesson_id, get_current_user_id() ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
383 | $this->data->lesson_quiz_questions = $lesson_quiz_questions; |
||
384 | $this->data->reset_quiz_allowed = $reset_allowed; // Sensei_Quiz::is_reset_allowed( $lesson_id ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
385 | |||
386 | } // end load_global_quiz_data |
||
387 | |||
388 | |||
389 | /** |
||
390 | * This function converts the submitted array and makes it ready it for storage |
||
391 | * |
||
392 | * Creating a single array of all question types including file id's to be stored |
||
393 | * as comment meta by the calling function. |
||
394 | * |
||
395 | * @since 1.7.4 |
||
396 | * @access public |
||
397 | * |
||
398 | * @param array $unprepared_answers |
||
399 | * @param $files |
||
400 | * @return array |
||
401 | */ |
||
402 | public static function prepare_form_submitted_answers( $unprepared_answers, $files ){ |
||
403 | |||
404 | |||
405 | $prepared_answers = array(); |
||
406 | |||
407 | // validate incoming answers |
||
408 | if( empty( $unprepared_answers ) || ! is_array( $unprepared_answers ) ){ |
||
409 | return false; |
||
410 | } |
||
411 | |||
412 | // Loop through submitted quiz answers and save them appropriately |
||
413 | foreach( $unprepared_answers as $question_id => $answer ) { |
||
414 | |||
415 | //get the current questions question type |
||
416 | $question_type = Sensei()->question->get_question_type( $question_id ); |
||
417 | |||
418 | // Sanitise answer |
||
419 | if( 0 == get_magic_quotes_gpc() ) { |
||
420 | $answer = wp_unslash( $answer ); |
||
421 | } |
||
422 | |||
423 | // compress the answer for saving |
||
424 | if( 'multi-line' == $question_type ) { |
||
425 | $answer = esc_html( $answer ); |
||
426 | }elseif( 'file-upload' == $question_type ){ |
||
427 | $file_key = 'file_upload_' . $question_id; |
||
428 | if( isset( $files[ $file_key ] ) ) { |
||
429 | $attachment_id = Sensei_Utils::upload_file( $files[ $file_key ] ); |
||
430 | if( $attachment_id ) { |
||
431 | $answer = $attachment_id; |
||
432 | } |
||
433 | } |
||
434 | } // end if |
||
435 | |||
436 | $prepared_answers[ $question_id ] = base64_encode( maybe_serialize( $answer ) ); |
||
437 | |||
438 | }// end for each $quiz_answers |
||
439 | |||
440 | return $prepared_answers; |
||
441 | } // prepare_form_submitted_answers |
||
442 | |||
443 | /** |
||
444 | * Reset user submitted questions |
||
445 | * |
||
446 | * This function resets the quiz data for a user that has been submitted fro grading already. It is different to |
||
447 | * the save_user_answers as currently the saved and submitted answers are stored differently. |
||
448 | * |
||
449 | * @since 1.7.4 |
||
450 | * @access public |
||
451 | * |
||
452 | * @return bool $reset_success |
||
453 | * @param int $user_id |
||
454 | * @param int $lesson_id |
||
455 | */ |
||
456 | public function reset_user_lesson_data( $lesson_id , $user_id = 0 ){ |
||
457 | |||
458 | //make sure the parameters are valid |
||
459 | if( empty( $lesson_id ) || empty( $user_id ) |
||
460 | || 'lesson' != get_post_type( $lesson_id ) |
||
461 | || ! get_userdata( $user_id ) ){ |
||
462 | return false; |
||
463 | } |
||
464 | |||
465 | |||
466 | |||
467 | //get the users lesson status to make |
||
468 | $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $user_id ); |
||
469 | if( ! isset( $user_lesson_status->comment_ID ) ) { |
||
470 | // this user is not taking this lesson so this process is not needed |
||
471 | return false; |
||
472 | } |
||
473 | |||
474 | //get the lesson quiz and course |
||
475 | $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id ); |
||
476 | $course_id = Sensei()->lesson->get_course_id( $lesson_id ); |
||
477 | |||
478 | // reset the transients |
||
479 | $answers_transient_key = 'sensei_answers_'.$user_id.'_'.$lesson_id; |
||
480 | $grades_transient_key = 'quiz_grades_'.$user_id.'_'.$lesson_id; |
||
481 | $answers_feedback_transient_key = 'sensei_answers_feedback_'.$user_id.'_'.$lesson_id; |
||
482 | delete_transient( $answers_transient_key ); |
||
483 | delete_transient( $grades_transient_key ); |
||
484 | delete_transient( $answers_feedback_transient_key ); |
||
485 | |||
486 | // reset the quiz answers and feedback notes |
||
487 | $deleted_answers = Sensei_Utils::delete_user_data( 'quiz_answers', $lesson_id, $user_id ); |
||
488 | $deleted_grades = Sensei_Utils::delete_user_data( 'quiz_grades', $lesson_id, $user_id ); |
||
489 | $deleted_user_feedback = Sensei_Utils::delete_user_data( 'quiz_answers_feedback', $lesson_id, $user_id ); |
||
0 ignored issues
–
show
$deleted_user_feedback is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
490 | |||
491 | // Delete quiz answers, this auto deletes the corresponding meta data, such as the question/answer grade |
||
492 | Sensei_Utils::sensei_delete_quiz_answers( $quiz_id, $user_id ); |
||
493 | |||
494 | Sensei_Utils::update_lesson_status( $user_id , $lesson_id, 'in-progress', array( 'questions_asked' => '', 'grade' => '' ) ); |
||
495 | |||
496 | // Update course completion |
||
497 | Sensei_Utils::update_course_status( $user_id, $course_id ); |
||
0 ignored issues
–
show
It seems like
$course_id defined by Sensei()->lesson->get_course_id($lesson_id) on line 476 can also be of type boolean ; however, Sensei_Utils::update_course_status() does only seem to accept integer , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
498 | |||
499 | // Run any action on quiz/lesson reset (previously this didn't occur on resetting a quiz, see resetting a lesson in sensei_complete_lesson() |
||
500 | do_action( 'sensei_user_lesson_reset', $user_id, $lesson_id ); |
||
501 | Sensei()->frontend->messages = '<div class="sensei-message note">' . __( 'Quiz Reset Successfully.', 'woothemes-sensei' ) . '</div>'; |
||
502 | |||
503 | return ( $deleted_answers && $deleted_grades ) ; |
||
504 | |||
505 | } // end reset_user_lesson_data |
||
506 | |||
507 | /** |
||
508 | * Submit the users quiz answers for grading |
||
509 | * |
||
510 | * This function accepts users answers and stores it but also initiates the grading |
||
511 | * if a quiz can be graded automatically it will, if not the answers can be graded by the teacher. |
||
512 | * |
||
513 | * @since 1.7.4 |
||
514 | * @access public |
||
515 | * |
||
516 | * @param array $quiz_answers |
||
517 | * @param array $files from $_FILES |
||
518 | * @param int $user_id |
||
519 | * @param int $lesson_id |
||
520 | * |
||
521 | * @return bool $answers_submitted |
||
522 | */ |
||
523 | public static function submit_answers_for_grading( $quiz_answers , $files = array() , $lesson_id , $user_id = 0 ){ |
||
524 | |||
525 | $answers_submitted = false; |
||
0 ignored issues
–
show
$answers_submitted is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
526 | |||
527 | // get the user_id if none was passed in use the current logged in user |
||
528 | if( ! intval( $user_id ) > 0 ) { |
||
529 | $user_id = get_current_user_id(); |
||
530 | } |
||
531 | |||
532 | // make sure the parameters are valid before continuing |
||
533 | View Code Duplication | if( empty( $lesson_id ) || empty( $user_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
534 | || 'lesson' != get_post_type( $lesson_id ) |
||
535 | ||!get_userdata( $user_id ) |
||
536 | || !is_array( $quiz_answers ) ){ |
||
537 | |||
538 | return false; |
||
539 | |||
540 | } |
||
541 | |||
542 | // Default grade |
||
543 | $grade = 0; |
||
0 ignored issues
–
show
$grade is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
544 | |||
545 | // Get Quiz ID |
||
546 | $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id ); |
||
547 | |||
548 | // Get quiz grade type |
||
549 | $quiz_grade_type = get_post_meta( $quiz_id, '_quiz_grade_type', true ); |
||
550 | |||
551 | // Get quiz pass setting |
||
552 | $pass_required = get_post_meta( $quiz_id, '_pass_required', true ); |
||
553 | |||
554 | // Get the minimum percentage need to pass this quiz |
||
555 | $quiz_pass_percentage = abs( round( doubleval( get_post_meta( $quiz_id, '_quiz_passmark', true ) ), 2 ) ); |
||
556 | |||
557 | // Handle Quiz Questions asked |
||
558 | // This is to ensure we save the questions that we've asked this user and that this can't be change unless |
||
559 | // the quiz is reset by admin or user( user: only if the setting is enabled ). |
||
560 | // get the questions asked when when the quiz questions were generated for the user : Sensei_Lesson::lesson_quiz_questions |
||
561 | $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $user_id ); |
||
562 | $questions_asked = get_comment_meta( $user_lesson_status->comment_ID, 'questions_asked', true ); |
||
563 | if( empty( $questions_asked ) ){ |
||
564 | |||
565 | $questions_asked = array_keys( $quiz_answers ); |
||
566 | $questions_asked_string = implode( ',', $questions_asked ); |
||
567 | |||
568 | // Save questions that were asked in this quiz |
||
569 | update_comment_meta( $user_lesson_status->comment_ID, 'questions_asked', $questions_asked_string ); |
||
570 | |||
571 | } |
||
572 | |||
573 | // Save Quiz Answers for grading, the save function also calls the sensei_start_lesson |
||
574 | self::save_user_answers( $quiz_answers , $files , $lesson_id , $user_id ); |
||
575 | |||
576 | // Grade quiz |
||
577 | $grade = Sensei_Grading::grade_quiz_auto( $quiz_id, $quiz_answers, 0 , $quiz_grade_type ); |
||
578 | |||
579 | // Get Lesson Grading Setting |
||
580 | $lesson_metadata = array(); |
||
581 | $lesson_status = 'ungraded'; // Default when completing a quiz |
||
582 | |||
583 | // At this point the answers have been submitted |
||
584 | $answers_submitted = true; |
||
585 | |||
586 | // if this condition is false the quiz should manually be graded by admin |
||
587 | if ('auto' == $quiz_grade_type && ! is_wp_error( $grade ) ) { |
||
588 | |||
589 | // Quiz has been automatically Graded |
||
590 | View Code Duplication | if ( 'on' == $pass_required ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
591 | |||
592 | // Student has reached the pass mark and lesson is complete |
||
593 | if ( $quiz_pass_percentage <= $grade ) { |
||
594 | |||
595 | $lesson_status = 'passed'; |
||
596 | |||
597 | } else { |
||
598 | |||
599 | $lesson_status = 'failed'; |
||
600 | |||
601 | } // End If Statement |
||
602 | |||
603 | } else { |
||
604 | |||
605 | // Student only has to partake the quiz |
||
606 | $lesson_status = 'graded'; |
||
607 | |||
608 | } |
||
609 | |||
610 | $lesson_metadata['grade'] = $grade; // Technically already set as part of "WooThemes_Sensei_Utils::sensei_grade_quiz_auto()" above |
||
611 | |||
612 | } // end if ! is_wp_error( $grade ... |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
39% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
613 | |||
614 | Sensei_Utils::update_lesson_status( $user_id, $lesson_id, $lesson_status, $lesson_metadata ); |
||
615 | |||
616 | if( 'passed' == $lesson_status || 'graded' == $lesson_status ){ |
||
617 | |||
618 | /** |
||
619 | * Lesson end action hook |
||
620 | * |
||
621 | * This hook is fired after a lesson quiz has been graded and the lesson status is 'passed' OR 'graded' |
||
622 | * |
||
623 | * @param int $user_id |
||
624 | * @param int $lesson_id |
||
625 | */ |
||
626 | do_action( 'sensei_user_lesson_end', $user_id, $lesson_id ); |
||
627 | |||
628 | } |
||
629 | |||
630 | /** |
||
631 | * User quiz has been submitted |
||
632 | * |
||
633 | * Fires the end of the submit_answers_for_grading function. It will fire irrespective of the submission |
||
634 | * results. |
||
635 | * |
||
636 | * @param int $user_id |
||
637 | * @param int $quiz_id |
||
638 | * @param string $grade |
||
639 | * @param string $quiz_pass_percentage |
||
640 | * @param string $quiz_grade_type |
||
641 | */ |
||
642 | do_action( 'sensei_user_quiz_submitted', $user_id, $quiz_id, $grade, $quiz_pass_percentage, $quiz_grade_type ); |
||
643 | |||
644 | return $answers_submitted; |
||
645 | |||
646 | }// end submit_answers_for_grading |
||
647 | |||
648 | /** |
||
649 | * Get the user question answer |
||
650 | * |
||
651 | * This function gets the the users saved answer on given quiz for the given question parameter |
||
652 | * this function allows for a fallback to users still using the question saved data from before 1.7.4 |
||
653 | * |
||
654 | * @since 1.7.4 |
||
655 | * |
||
656 | * @param int $lesson_id |
||
657 | * @param int $question_id |
||
658 | * @param int $user_id ( optional ) |
||
659 | * |
||
660 | * @return bool|null $answers_submitted |
||
661 | */ |
||
662 | public function get_user_question_answer( $lesson_id, $question_id, $user_id = 0 ){ |
||
663 | |||
664 | // parameter validation |
||
665 | View Code Duplication | if( empty( $lesson_id ) || empty( $question_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
666 | || ! ( intval( $lesson_id ) > 0 ) |
||
667 | || ! ( intval( $question_id ) > 0 ) |
||
668 | || 'lesson' != get_post_type( $lesson_id ) |
||
669 | || 'question' != get_post_type( $question_id )) { |
||
670 | |||
671 | return false; |
||
672 | } |
||
673 | |||
674 | if( ! ( intval( $user_id ) > 0 ) ){ |
||
675 | $user_id = get_current_user_id(); |
||
676 | } |
||
677 | |||
678 | $users_answers = $this->get_user_answers( $lesson_id, $user_id ); |
||
679 | |||
680 | if( !$users_answers || empty( $users_answers ) |
||
681 | || ! is_array( $users_answers ) || ! isset( $users_answers[ $question_id ] ) ){ |
||
682 | |||
683 | //Fallback for pre 1.7.4 data |
||
684 | $comment = Sensei_Utils::sensei_check_for_activity( array( 'post_id' => $question_id, 'user_id' => $user_id, 'type' => 'sensei_user_answer' ), true ); |
||
685 | |||
686 | if( ! isset( $comment->comment_content ) ){ |
||
687 | return NULL; |
||
688 | } |
||
689 | |||
690 | return maybe_unserialize( base64_decode( $comment->comment_content ) ); |
||
691 | } |
||
692 | |||
693 | return $users_answers[ $question_id ]; |
||
694 | |||
695 | }// end get_user_question_answer |
||
696 | |||
697 | /** |
||
698 | * Saving the users quiz question grades |
||
699 | * |
||
700 | * This function save all the grades for all the question in a given quiz on the lesson |
||
701 | * comment meta. It makes use of transients to save the grades for easier access at a later stage |
||
702 | * |
||
703 | * @since 1.7.4 |
||
704 | * |
||
705 | * @param array $quiz_grades{ |
||
0 ignored issues
–
show
There is no parameter named
$quiz_grades{ . Did you maybe mean $quiz_grades ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not. ![]() |
|||
706 | * @type int $question_id |
||
707 | * @type int $question_grade |
||
708 | * } |
||
709 | * @param $lesson_id |
||
710 | * @param $user_id (Optional) will use the current user if not supplied |
||
711 | * |
||
712 | * @return bool |
||
713 | */ |
||
714 | public function set_user_grades( $quiz_grades, $lesson_id, $user_id = 0 ){ |
||
715 | |||
716 | // get the user_id if none was passed in use the current logged in user |
||
717 | if( ! intval( $user_id ) > 0 ) { |
||
718 | $user_id = get_current_user_id(); |
||
719 | } |
||
720 | |||
721 | // make sure the parameters are valid before continuing |
||
722 | View Code Duplication | if( empty( $lesson_id ) || empty( $user_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
723 | || 'lesson' != get_post_type( $lesson_id ) |
||
724 | ||!get_userdata( $user_id ) |
||
725 | || !is_array( $quiz_grades ) ){ |
||
726 | |||
727 | return false; |
||
728 | |||
729 | } |
||
730 | |||
731 | $success = false; |
||
732 | |||
733 | // save that data for the user on the lesson comment meta |
||
734 | $comment_meta_id = Sensei_Utils::add_user_data( 'quiz_grades', $lesson_id, $quiz_grades, $user_id ); |
||
735 | |||
736 | // were the grades save successfully ? |
||
737 | View Code Duplication | if( intval( $comment_meta_id ) > 0 ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
738 | |||
739 | $success = true; |
||
740 | // save transient |
||
741 | $transient_key = 'quiz_grades_'. $user_id . '_' . $lesson_id; |
||
742 | set_transient( $transient_key, $quiz_grades, 10 * DAY_IN_SECONDS ); |
||
743 | } |
||
744 | |||
745 | return $success; |
||
746 | |||
747 | }// end set_user_grades |
||
748 | |||
749 | /** |
||
750 | * Retrieve the users quiz question grades |
||
751 | * |
||
752 | * This function gets all the grades for all the questions in the given lesson quiz for a specific user. |
||
753 | * |
||
754 | * @since 1.7.4 |
||
755 | * |
||
756 | * @param $lesson_id |
||
757 | * @param $user_id (Optional) will use the current user if not supplied |
||
758 | * |
||
759 | * @return array $user_quiz_grades or false if none exists for this users |
||
760 | */ |
||
761 | public function get_user_grades( $lesson_id, $user_id = 0 ){ |
||
762 | |||
763 | $user_grades = array(); |
||
0 ignored issues
–
show
$user_grades is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
764 | |||
765 | // get the user_id if none was passed in use the current logged in user |
||
766 | if( ! intval( $user_id ) > 0 ) { |
||
767 | $user_id = get_current_user_id(); |
||
768 | } |
||
769 | |||
770 | View Code Duplication | if ( ! intval( $lesson_id ) > 0 || 'lesson' != get_post_type( $lesson_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
771 | || ! intval( $user_id ) > 0 || !get_userdata( $user_id ) ) { |
||
772 | return false; |
||
773 | } |
||
774 | |||
775 | // save some time and get the transient cached data |
||
776 | $transient_key = 'quiz_grades_'. $user_id . '_' . $lesson_id; |
||
777 | $user_grades = get_transient( $transient_key ); |
||
778 | |||
779 | // get the data if nothing was stored in the transient |
||
780 | View Code Duplication | if( empty( $user_grades ) || false != $user_grades ){ |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
781 | |||
782 | $user_grades = Sensei_Utils::get_user_data( 'quiz_grades', $lesson_id, $user_id ); |
||
783 | |||
784 | //set the transient with the new valid data for faster retrieval in future |
||
785 | set_transient( $transient_key, $user_grades, 10 * DAY_IN_SECONDS ); |
||
786 | |||
787 | } // end if transient check |
||
788 | |||
789 | // if there is no data for this user |
||
790 | if( ! is_array( $user_grades ) ){ |
||
791 | return false; |
||
792 | } |
||
793 | |||
794 | return $user_grades; |
||
795 | |||
796 | }// end get_user_grades |
||
797 | |||
798 | /** |
||
799 | * Get the user question grade |
||
800 | * |
||
801 | * This function gets the grade on a quiz for the given question parameter |
||
802 | * It does NOT do any grading. It simply retrieves the data that was stored during grading. |
||
803 | * this function allows for a fallback to users still using the question saved data from before 1.7.4 |
||
804 | * |
||
805 | * @since 1.7.4 |
||
806 | * |
||
807 | * @param int $lesson_id |
||
808 | * @param int $question_id |
||
809 | * @param int $user_id ( optional ) |
||
810 | * |
||
811 | * @return bool $question_grade |
||
812 | */ |
||
813 | public function get_user_question_grade( $lesson_id, $question_id, $user_id = 0 ){ |
||
814 | |||
815 | // parameter validation |
||
816 | View Code Duplication | if( empty( $lesson_id ) || empty( $question_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
817 | || ! ( intval( $lesson_id ) > 0 ) |
||
818 | || ! ( intval( $question_id ) > 0 ) |
||
819 | || 'lesson' != get_post_type( $lesson_id ) |
||
820 | || 'question' != get_post_type( $question_id )) { |
||
821 | |||
822 | return false; |
||
823 | } |
||
824 | |||
825 | $all_user_grades = self::get_user_grades( $lesson_id,$user_id ); |
||
826 | |||
827 | if( ! $all_user_grades || ! isset( $all_user_grades[ $question_id ] ) ){ |
||
828 | |||
829 | //fallback to data pre 1.7.4 |
||
830 | $args = array( |
||
831 | 'post_id' => $question_id, |
||
832 | 'user_id' => $user_id, |
||
833 | 'type' => 'sensei_user_answer' |
||
834 | ); |
||
835 | |||
836 | $question_activity = Sensei_Utils::sensei_check_for_activity( $args , true ); |
||
837 | $fall_back_grade = false; |
||
838 | if( isset( $question_activity->comment_ID ) ){ |
||
839 | $fall_back_grade = get_comment_meta( $question_activity->comment_ID , 'user_grade', true ); |
||
840 | } |
||
841 | |||
842 | return $fall_back_grade; |
||
843 | |||
844 | } // end if $all_user_grades... |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
43% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
845 | |||
846 | return $all_user_grades[ $question_id ]; |
||
847 | |||
848 | }// end get_user_question_grade |
||
849 | |||
850 | /** |
||
851 | * Save the user's answers feedback |
||
852 | * |
||
853 | * For this function you must supply all three parameters. If will return false one is left out. |
||
854 | * The data will be saved on the lesson ID supplied. |
||
855 | * |
||
856 | * @since 1.7.5 |
||
857 | * @access public |
||
858 | * |
||
859 | * @param array $answers_feedback{ |
||
0 ignored issues
–
show
There is no parameter named
$answers_feedback{ . Did you maybe mean $answers_feedback ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not. ![]() |
|||
860 | * $type int $question_id |
||
861 | * $type string $question_feedback |
||
862 | * } |
||
863 | * @param int $lesson_id |
||
864 | * @param int $user_id |
||
865 | * |
||
866 | * @return false or int $feedback_saved |
||
867 | */ |
||
868 | public function save_user_answers_feedback( $answers_feedback, $lesson_id , $user_id = 0 ){ |
||
869 | |||
870 | // make sure the parameters are valid before continuing |
||
871 | View Code Duplication | if( empty( $lesson_id ) || empty( $user_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
872 | || 'lesson' != get_post_type( $lesson_id ) |
||
873 | ||!get_userdata( $user_id ) |
||
874 | || !is_array( $answers_feedback ) ){ |
||
875 | |||
876 | return false; |
||
877 | |||
878 | } |
||
879 | |||
880 | |||
881 | // check if the lesson is started before saving, if not start the lesson for the user |
||
882 | if ( !( 0 < intval( Sensei_Utils::user_started_lesson( $lesson_id, $user_id) ) ) ) { |
||
883 | Sensei_Utils::sensei_start_lesson( $lesson_id, $user_id ); |
||
884 | } |
||
885 | |||
886 | // encode the feedback |
||
887 | $encoded_answers_feedback = array(); |
||
888 | foreach( $answers_feedback as $question_id => $feedback ){ |
||
889 | $encoded_answers_feedback[ $question_id ] = base64_encode( $feedback ); |
||
890 | } |
||
891 | |||
892 | // save the user data |
||
893 | $feedback_saved = Sensei_Utils::add_user_data( 'quiz_answers_feedback', $lesson_id , $encoded_answers_feedback, $user_id ) ; |
||
894 | |||
895 | //Were the the question feedback save correctly? |
||
896 | View Code Duplication | if( intval( $feedback_saved ) > 0){ |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
897 | |||
898 | // save transient to make retrieval faster in future |
||
899 | $transient_key = 'sensei_answers_feedback_'.$user_id.'_'.$lesson_id; |
||
900 | set_transient( $transient_key, $encoded_answers_feedback, 10 * DAY_IN_SECONDS ); |
||
901 | |||
902 | } |
||
903 | |||
904 | return $feedback_saved; |
||
905 | |||
906 | } // end save_user_answers_feedback |
||
907 | |||
908 | /** |
||
909 | * Get the user's answers feedback. |
||
910 | * |
||
911 | * This function returns the feedback submitted by the teacher/admin |
||
912 | * during grading. Grading occurs manually or automatically. |
||
913 | * |
||
914 | * @since 1.7.5 |
||
915 | * @access public |
||
916 | * |
||
917 | * @param int $lesson_id |
||
918 | * @param int $user_id |
||
919 | * |
||
920 | * @return false | array $answers_feedback{ |
||
921 | * $type int $question_id |
||
922 | * $type string $question_feedback |
||
923 | * } |
||
924 | */ |
||
925 | public function get_user_answers_feedback( $lesson_id , $user_id = 0 ){ |
||
926 | |||
927 | $answers_feedback = array(); |
||
928 | |||
929 | // get the user_id if none was passed in use the current logged in user |
||
930 | if( ! intval( $user_id ) > 0 ) { |
||
931 | $user_id = get_current_user_id(); |
||
932 | } |
||
933 | |||
934 | View Code Duplication | if ( ! intval( $lesson_id ) > 0 || 'lesson' != get_post_type( $lesson_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
935 | || ! intval( $user_id ) > 0 || !get_userdata( $user_id ) ) { |
||
936 | return false; |
||
937 | } |
||
938 | |||
939 | // first check the transient to save a few split seconds |
||
940 | $transient_key = 'sensei_answers_feedback_'.$user_id.'_'.$lesson_id; |
||
941 | $encoded_feedback = get_transient( $transient_key ); |
||
942 | |||
943 | // get the data if nothing was stored in the transient |
||
944 | View Code Duplication | if( empty( $encoded_feedback ) || !$encoded_feedback ){ |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
945 | |||
946 | $encoded_feedback = Sensei_Utils::get_user_data( 'quiz_answers_feedback', $lesson_id, $user_id ); |
||
947 | |||
948 | //set the transient with the new valid data for faster retrieval in future |
||
949 | set_transient( $transient_key, $encoded_feedback, 10 * DAY_IN_SECONDS); |
||
950 | |||
951 | } // end if transient check |
||
952 | |||
953 | // if there is no data for this user |
||
954 | if( ! is_array( $encoded_feedback ) ){ |
||
955 | return false; |
||
956 | } |
||
957 | |||
958 | foreach( $encoded_feedback as $question_id => $feedback ){ |
||
959 | |||
960 | $answers_feedback[ $question_id ] = base64_decode( $feedback ); |
||
961 | |||
962 | } |
||
963 | |||
964 | return $answers_feedback; |
||
965 | |||
966 | } // end get_user_answers_feedback |
||
967 | |||
968 | /** |
||
969 | * Get the user's answer feedback for a specific question. |
||
970 | * |
||
971 | * This function gives you a single answer note/feedback string |
||
972 | * for the user on the given question. |
||
973 | * |
||
974 | * @since 1.7.5 |
||
975 | * @access public |
||
976 | * |
||
977 | * @param int $lesson_id |
||
978 | * @param int $question_id |
||
979 | * @param int $user_id |
||
980 | * |
||
981 | * @return string $feedback or bool if false |
||
982 | */ |
||
983 | public function get_user_question_feedback( $lesson_id, $question_id, $user_id = 0 ){ |
||
984 | |||
985 | $feedback = false; |
||
986 | |||
987 | // parameter validation |
||
988 | View Code Duplication | if( empty( $lesson_id ) || empty( $question_id ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
989 | || ! ( intval( $lesson_id ) > 0 ) |
||
990 | || ! ( intval( $question_id ) > 0 ) |
||
991 | || 'lesson' != get_post_type( $lesson_id ) |
||
992 | || 'question' != get_post_type( $question_id )) { |
||
993 | |||
994 | return false; |
||
995 | } |
||
996 | |||
997 | // get all the feedback for the user on the given lesson |
||
998 | $all_feedback = $this->get_user_answers_feedback( $lesson_id, $user_id ); |
||
999 | |||
1000 | if( !$all_feedback || empty( $all_feedback ) |
||
1001 | || ! is_array( $all_feedback ) || ! isset( $all_feedback[ $question_id ] ) ){ |
||
1002 | |||
1003 | //fallback to data pre 1.7.4 |
||
1004 | |||
1005 | // setup the sensei data query |
||
1006 | $args = array( |
||
1007 | 'post_id' => $question_id, |
||
1008 | 'user_id' => $user_id, |
||
1009 | 'type' => 'sensei_user_answer' |
||
1010 | ); |
||
1011 | $question_activity = Sensei_Utils::sensei_check_for_activity( $args , true ); |
||
1012 | |||
1013 | // set the default to false and return that if no old data is available. |
||
1014 | if( isset( $question_activity->comment_ID ) ){ |
||
1015 | $feedback = base64_decode( get_comment_meta( $question_activity->comment_ID , 'answer_note', true ) ); |
||
1016 | } |
||
1017 | |||
1018 | // finally use the default question feedback |
||
1019 | if( empty( $feedback ) ){ |
||
1020 | $feedback = get_post_meta( $question_id, '_answer_feedback', true ); |
||
1021 | } |
||
1022 | |||
1023 | return $feedback; |
||
1024 | |||
1025 | } |
||
1026 | |||
1027 | return $all_feedback[ $question_id ]; |
||
1028 | |||
1029 | } // end get_user_question_feedback |
||
1030 | |||
1031 | /** |
||
1032 | * Check if a quiz has no questions, and redirect back to lesson. |
||
1033 | * |
||
1034 | * Though a quiz is created for each lesson, it should not be visible |
||
1035 | * unless it has questions. |
||
1036 | * |
||
1037 | * @since 1.9.0 |
||
1038 | * @access public |
||
1039 | * @param none |
||
1040 | * @return void |
||
1041 | */ |
||
1042 | |||
1043 | public function quiz_has_no_questions() { |
||
1044 | |||
1045 | if( ! is_singular( 'quiz' ) ) { |
||
1046 | return; |
||
1047 | } |
||
1048 | |||
1049 | global $post; |
||
1050 | |||
1051 | $lesson_id = $this->get_lesson_id($post->ID); |
||
1052 | |||
1053 | $has_questions = get_post_meta( $lesson_id, '_quiz_has_questions', true ); |
||
1054 | |||
1055 | $lesson = get_post($lesson_id); |
||
1056 | |||
1057 | if ( is_singular('quiz') && ! $has_questions && $_SERVER['REQUEST_URI'] != "/lesson/$lesson->post_name" ) { |
||
1058 | |||
1059 | wp_redirect(get_permalink($lesson->ID), 301); |
||
1060 | exit; |
||
1061 | |||
1062 | } |
||
1063 | |||
1064 | } // end quiz_has_no_questions |
||
1065 | |||
1066 | /** |
||
1067 | * Deprecate the sensei_single_main_content on the single-quiz template. |
||
1068 | * |
||
1069 | * @deprecated since 1.9.0 |
||
1070 | */ |
||
1071 | public static function deprecate_quiz_sensei_single_main_content_hook(){ |
||
1072 | |||
1073 | sensei_do_deprecated_action('sensei_single_main_content', '1.9.0', 'sensei_single_quiz_content_inside_before or sensei_single_quiz_content_inside_after'); |
||
1074 | |||
1075 | } |
||
1076 | /* |
||
1077 | * Deprecate the sensei_quiz_single_title on the single-quiz template. |
||
1078 | * |
||
1079 | * @deprecated since 1.9.0 |
||
1080 | */ |
||
1081 | public static function deprecate_quiz_sensei_quiz_single_title_hook(){ |
||
1082 | |||
1083 | sensei_do_deprecated_action('sensei_quiz_single_title', '1.9.0', 'sensei_single_quiz_content_inside_before '); |
||
1084 | |||
1085 | } |
||
1086 | |||
1087 | /** |
||
1088 | * Filter the single title and add the Quiz to it. |
||
1089 | * |
||
1090 | * @param string $title |
||
1091 | * @param int $id title post id |
||
0 ignored issues
–
show
There is no parameter named
$id . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
1092 | * @return string $quiz_title |
||
1093 | */ |
||
1094 | public static function single_quiz_title( $title, $post_id ){ |
||
1095 | |||
1096 | if( 'quiz' == get_post_type( $post_id ) ){ |
||
1097 | |||
1098 | $title_with_no_quizzes = $title; |
||
1099 | |||
1100 | // if the title has quiz, remove it: legacy titles have the word quiz stored. |
||
1101 | if( 1 < substr_count( strtoupper( $title_with_no_quizzes ), 'QUIZ' ) ){ |
||
1102 | |||
1103 | // remove all possible appearances of quiz |
||
1104 | $title_with_no_quizzes = str_replace( 'quiz', '', $title ); |
||
1105 | $title_with_no_quizzes = str_replace( 'Quiz', '', $title_with_no_quizzes ); |
||
1106 | $title_with_no_quizzes = str_replace( 'QUIZ', '', $title_with_no_quizzes ); |
||
1107 | |||
1108 | } |
||
1109 | |||
1110 | $title = $title_with_no_quizzes . ' ' . __( 'Quiz', 'woothemes-sensei' ); |
||
1111 | } |
||
1112 | |||
1113 | /** |
||
1114 | * hook document in class-woothemes-sensei-message.php |
||
1115 | */ |
||
1116 | return apply_filters( 'sensei_single_title', $title, get_post_type( ) ); |
||
1117 | |||
1118 | } |
||
1119 | |||
1120 | /** |
||
1121 | * Initialize the quiz question loop on the single quiz template |
||
1122 | * |
||
1123 | * The function will create a global quiz loop varialbe. |
||
1124 | * |
||
1125 | * @since 1.9.0 |
||
1126 | * |
||
1127 | */ |
||
1128 | public static function start_quiz_questions_loop(){ |
||
1129 | |||
1130 | global $sensei_question_loop; |
||
1131 | |||
1132 | //intialize the questions loop object |
||
1133 | $sensei_question_loop['current'] = -1; |
||
1134 | $sensei_question_loop['total'] = 0; |
||
1135 | $sensei_question_loop['questions'] = array(); |
||
1136 | |||
1137 | |||
1138 | $questions = Sensei()->lesson->lesson_quiz_questions( get_the_ID() ); |
||
1139 | |||
1140 | if( count( $questions ) > 0 ){ |
||
1141 | |||
1142 | $sensei_question_loop['total'] = count( $questions ); |
||
1143 | $sensei_question_loop['questions'] = $questions; |
||
1144 | $sensei_question_loop['quiz_id'] = get_the_ID(); |
||
1145 | |||
1146 | } |
||
1147 | |||
1148 | }// static function |
||
1149 | |||
1150 | /** |
||
1151 | * Initialize the quiz question loop on the single quiz template |
||
1152 | * |
||
1153 | * The function will create a global quiz loop varialbe. |
||
1154 | * |
||
1155 | * @since 1.9.0 |
||
1156 | * |
||
1157 | */ |
||
1158 | public static function stop_quiz_questions_loop(){ |
||
1159 | |||
1160 | $sensei_question_loop['total'] = 0; |
||
1161 | $sensei_question_loop['questions'] = array(); |
||
1162 | $sensei_question_loop['quiz_id'] = ''; |
||
1163 | |||
1164 | } |
||
1165 | |||
1166 | /** |
||
1167 | * Output the title for the single quiz page |
||
1168 | * |
||
1169 | * @since 1.9.0 |
||
1170 | */ |
||
1171 | public static function the_title(){ |
||
1172 | ?> |
||
1173 | <header> |
||
1174 | |||
1175 | <h1> |
||
1176 | |||
1177 | <?php |
||
1178 | /** |
||
1179 | * Filter documented in class-sensei-messages.php the_title |
||
1180 | */ |
||
1181 | echo apply_filters( 'sensei_single_title', get_the_title( get_post() ), get_post_type( get_the_ID() ) ); |
||
1182 | ?> |
||
1183 | |||
1184 | </h1> |
||
1185 | |||
1186 | </header> |
||
1187 | |||
1188 | <?php |
||
1189 | }//the_title |
||
1190 | |||
1191 | /** |
||
1192 | * Output the sensei quiz status message. |
||
1193 | * |
||
1194 | * @param $quiz_id |
||
1195 | */ |
||
1196 | public static function the_user_status_message( $quiz_id ){ |
||
1197 | |||
1198 | $lesson_id = Sensei()->quiz->get_lesson_id( $quiz_id ); |
||
1199 | $status = Sensei_Utils::sensei_user_quiz_status_message( $lesson_id , get_current_user_id() ); |
||
1200 | echo '<div class="sensei-message ' . $status['box_class'] . '">' . $status['message'] . '</div>'; |
||
1201 | |||
1202 | } |
||
1203 | |||
1204 | /** |
||
1205 | * This functions runs the old sensei_quiz_action_buttons action |
||
1206 | * for backwards compatiblity sake. |
||
1207 | * |
||
1208 | * @since 1.9.0 |
||
1209 | * @deprecated |
||
1210 | */ |
||
1211 | public static function deprecate_sensei_quiz_action_buttons_hook(){ |
||
1212 | |||
1213 | sensei_do_deprecated_action( 'sensei_quiz_action_buttons', '1.9.0', 'sensei_single_quiz_questions_after'); |
||
1214 | |||
1215 | } |
||
1216 | |||
1217 | /** |
||
1218 | * The quiz action buttons needed to ouput quiz |
||
1219 | * action such as reset complete and save. |
||
1220 | * |
||
1221 | * @since 1.3.0 |
||
1222 | */ |
||
1223 | public static function action_buttons() { |
||
1224 | |||
1225 | global $post, $current_user; |
||
1226 | |||
1227 | $lesson_id = (int) get_post_meta( $post->ID, '_quiz_lesson', true ); |
||
1228 | $lesson_course_id = (int) get_post_meta( $lesson_id, '_lesson_course', true ); |
||
1229 | $lesson_prerequisite = (int) get_post_meta( $lesson_id, '_lesson_prerequisite', true ); |
||
1230 | $show_actions = true; |
||
1231 | $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $current_user->ID ); |
||
1232 | |||
1233 | //setup quiz grade |
||
1234 | $user_quiz_grade = ''; |
||
1235 | if( ! empty( $user_lesson_status ) ){ |
||
1236 | $user_quiz_grade = get_comment_meta( $user_lesson_status->comment_ID, 'grade', true ); |
||
1237 | } |
||
1238 | |||
1239 | |||
1240 | if( intval( $lesson_prerequisite ) > 0 ) { |
||
1241 | |||
1242 | // If the user hasn't completed the prereq then hide the current actions |
||
1243 | $show_actions = Sensei_Utils::user_completed_lesson( $lesson_prerequisite, $current_user->ID ); |
||
1244 | |||
1245 | } |
||
1246 | if ( $show_actions && is_user_logged_in() && Sensei_Utils::user_started_course( $lesson_course_id, $current_user->ID ) ) { |
||
1247 | |||
1248 | // Get Reset Settings |
||
1249 | $reset_quiz_allowed = get_post_meta( $post->ID, '_enable_quiz_reset', true ); ?> |
||
1250 | |||
1251 | <!-- Action Nonce's --> |
||
1252 | <input type="hidden" name="woothemes_sensei_complete_quiz_nonce" id="woothemes_sensei_complete_quiz_nonce" |
||
1253 | value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_complete_quiz_nonce' ) ); ?>" /> |
||
1254 | <input type="hidden" name="woothemes_sensei_reset_quiz_nonce" id="woothemes_sensei_reset_quiz_nonce" |
||
1255 | value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_reset_quiz_nonce' ) ); ?>" /> |
||
1256 | <input type="hidden" name="woothemes_sensei_save_quiz_nonce" id="woothemes_sensei_save_quiz_nonce" |
||
1257 | value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_save_quiz_nonce' ) ); ?>" /> |
||
1258 | <!--#end Action Nonce's --> |
||
1259 | |||
1260 | <?php if ( '' == $user_quiz_grade) { ?> |
||
1261 | |||
1262 | <span><input type="submit" name="quiz_complete" class="quiz-submit complete" value="<?php _e( 'Complete Quiz', 'woothemes-sensei' ); ?>"/></span> |
||
1263 | |||
1264 | <span><input type="submit" name="quiz_save" class="quiz-submit save" value="<?php _e( 'Save Quiz', 'woothemes-sensei' ); ?>"/></span> |
||
1265 | |||
1266 | <?php } // End If Statement ?> |
||
1267 | |||
1268 | <?php if ( isset( $reset_quiz_allowed ) && $reset_quiz_allowed ) { ?> |
||
1269 | |||
1270 | <span><input type="submit" name="quiz_reset" class="quiz-submit reset" value="<?php _e( 'Reset Quiz', 'woothemes-sensei' ); ?>"/></span> |
||
1271 | |||
1272 | <?php } ?> |
||
1273 | |||
1274 | <?php } |
||
1275 | |||
1276 | } // End sensei_quiz_action_buttons() |
||
1277 | |||
1278 | /** |
||
1279 | * Fetch the quiz grade |
||
1280 | * |
||
1281 | * @since 1.9.0 |
||
1282 | * |
||
1283 | * @param int $lesson_id |
||
1284 | * @param int $user_id |
||
1285 | * |
||
1286 | * @return double $user_quiz_grade |
||
1287 | */ |
||
1288 | public static function get_user_quiz_grade( $lesson_id, $user_id ){ |
||
1289 | |||
1290 | // get the quiz grade |
||
1291 | $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $user_id ); |
||
1292 | $user_quiz_grade = 0; |
||
1293 | if( isset( $user_lesson_status->comment_ID ) ) { |
||
1294 | $user_quiz_grade = get_comment_meta( $user_lesson_status->comment_ID, 'grade', true ); |
||
1295 | } |
||
1296 | |||
1297 | return (double) $user_quiz_grade; |
||
1298 | |||
1299 | } |
||
1300 | |||
1301 | /** |
||
1302 | * Check the quiz reset property for a given lesson's quiz. |
||
1303 | * |
||
1304 | * The data is stored on the quiz but going forward the quiz post |
||
1305 | * type will be retired, hence the lesson_id is a require parameter. |
||
1306 | * |
||
1307 | * @since 1.9.0 |
||
1308 | * |
||
1309 | * @param int $lesson_id |
||
1310 | * @return bool |
||
1311 | */ |
||
1312 | public static function is_reset_allowed( $lesson_id ){ |
||
1313 | |||
1314 | $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id ); |
||
1315 | |||
1316 | $reset_allowed = get_post_meta( $quiz_id, '_enable_quiz_reset', true ); |
||
1317 | //backwards compatibility |
||
1318 | if( 'on' == $reset_allowed ) { |
||
1319 | $reset_allowed = 1; |
||
1320 | } |
||
1321 | |||
1322 | return (bool) $reset_allowed; |
||
1323 | |||
1324 | } |
||
1325 | |||
1326 | } // End Class WooThemes_Sensei_Quiz |
||
1327 | |||
1328 | |||
1329 | |||
1330 | /** |
||
1331 | * Class WooThemes_Sensei_Quiz |
||
1332 | * @ignore only for backward compatibility |
||
1333 | * @since 1.9.0 |
||
1334 | */ |
||
1335 | class WooThemes_Sensei_Quiz extends Sensei_Quiz{} |
||
1336 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.