Completed
Push — master ( be93f6...2f2834 )
by greg
06:57 queued 03:44
created

Quiz::updateQuestion()   D

Complexity

Conditions 21
Paths 74

Size

Total Lines 161
Code Lines 98

Duplication

Lines 17
Ratio 10.56 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 17
loc 161
rs 4.6956
cc 21
eloc 98
nc 74
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PlaygroundGame\Service;
4
5
use PlaygroundGame\Entity\QuizReply;
6
use PlaygroundGame\Entity\QuizReplyAnswer;
7
use Zend\ServiceManager\ServiceManagerAwareInterface;
8
use PlaygroundGame\Mapper\GameInterface as GameMapperInterface;
9
use Zend\Stdlib\ErrorHandler;
10
11
class Quiz extends Game implements ServiceManagerAwareInterface
12
{
13
    /**
14
     * @var QuizMapperInterface
15
     */
16
    protected $quizMapper;
17
18
    /**
19
     * @var QuizAnswerMapperInterface
20
     */
21
    protected $quizAnswerMapper;
22
23
    /**
24
     * @var QuizQuestionMapperInterface
25
     */
26
    protected $quizQuestionMapper;
27
28
    /**
29
     * @var QuizReplyMapperInterface
30
     */
31
    protected $quizReplyMapper;
32
33
    /**
34
     * @var quizReplyAnswerMapper
35
     */
36
    protected $quizReplyAnswerMapper;
37
38
    /**
39
     *
40
     *
41
     * @param  array                  $data
42
     * @return \PlaygroundGame\Entity\Game
43
     */
44
    public function createQuestion(array $data)
45
    {
46
        $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
47
        $media_url = $this->getOptions()->getMediaUrl() . '/';
48
49
        $question  = new \PlaygroundGame\Entity\QuizQuestion();
50
        $form  = $this->getServiceManager()->get('playgroundgame_quizquestion_form');
51
        $form->bind($question);
52
        $form->setData($data);
53
54
        $quiz = $this->getGameMapper()->findById($data['quiz_id']);
55
        if (!$form->isValid()) {
56
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\Quiz::createQuestion of type PlaygroundGame\Entity\Game.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
57
        }
58
59
        $question->setQuiz($quiz);
60
61
        // If question is a prediction, no need to calculate max good answers
62
        if (!$question->getPrediction()) {
63
            // Max points and correct answers calculation for the question
64
            if (!$question = $this->calculateMaxAnswersQuestion($question)) {
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->calculateMaxAnswersQuestion($question); of type string adds the type string to the return on line 90 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::createQuestion of type PlaygroundGame\Entity\Game.
Loading history...
65
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\Quiz::createQuestion of type PlaygroundGame\Entity\Game.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
66
            }
67
        }
68
69
        // Max points and correct answers recalculation for the quiz
70
        $quiz = $this->calculateMaxAnswersQuiz($question->getQuiz());
71
72
        $this->getEventManager()->trigger(__FUNCTION__, $this, array('game' => $question, 'data' => $data));
73
        $this->getQuizQuestionMapper()->insert($question);
74
        $this->getEventManager()->trigger(__FUNCTION__.'.post', $this, array('game' => $question, 'data' => $data));
75
76 View Code Duplication
        if (!empty($data['upload_image']['tmp_name'])) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
77
            ErrorHandler::start();
78
            $data['upload_image']['name'] = $this->fileNewname(
79
                $path,
80
                $question->getId() . "-" . $data['upload_image']['name']
81
            );
82
            move_uploaded_file($data['upload_image']['tmp_name'], $path . $data['upload_image']['name']);
83
            $question->setImage($media_url . $data['upload_image']['name']);
84
            ErrorHandler::stop(true);
85
        }
86
87
        $this->getQuizQuestionMapper()->update($question);
88
        $this->getQuizMapper()->update($quiz);
89
90
        return $question;
91
    }
92
93
    /**
94
     * @param  array                  $data
95
     * @return \PlaygroundGame\Entity\Game
96
     */
97
    public function updateQuestion(array $data, $question)
98
    {
99
        $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
100
        $media_url = $this->getOptions()->getMediaUrl() . '/';
101
102
        $form  = $this->getServiceManager()->get('playgroundgame_quizquestion_form');
103
        $form->bind($question);
104
        $form->setData($data);
105
106
        if (!$form->isValid()) {
107
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\Quiz::updateQuestion of type PlaygroundGame\Entity\Game.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
108
        }
109
110
        // If question is a prediction, no need to calculate max good answers
111
        if (!$question->getPrediction()) {
112
            // Max points and correct answers calculation for the question
113
            if (!$question = $this->calculateMaxAnswersQuestion($question)) {
114
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\Quiz::updateQuestion of type PlaygroundGame\Entity\Game.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
115
            }
116
        }
117
118 View Code Duplication
        if (!empty($data['upload_image']['tmp_name'])) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
119
            ErrorHandler::start();
120
            $data['upload_image']['name'] = $this->fileNewname(
121
                $path,
122
                $question->getId() . "-" . $data['upload_image']['name']
123
            );
124
            move_uploaded_file($data['upload_image']['tmp_name'], $path . $data['upload_image']['name']);
125
            $question->setImage($media_url . $data['upload_image']['name']);
126
            ErrorHandler::stop(true);
127
        }
128
129 View Code Duplication
        if (isset($data['delete_image']) && empty($data['upload_image']['tmp_name'])) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
130
            ErrorHandler::start();
131
            $image = $question->getImage();
132
            $image = str_replace($media_url, '', $image);
133
            if (file_exists($path .$image)) {
134
                unlink($path .$image);
135
            }
136
            $question->setImage(null);
137
            ErrorHandler::stop(true);
138
        }
139
        
140
        $i = 0;
141
        foreach ($question->getAnswers() as $answer) {
142
            if (!empty($data['answers'][$i]['upload_image']['tmp_name'])) {
143
                ErrorHandler::start();
144
                $data['answers'][$i]['upload_image']['name'] = $this->fileNewname(
145
                    $path,
146
                    $question->getId() . "-" . $data['answers'][$i]['upload_image']['name']
147
                );
148
                move_uploaded_file(
149
                    $data['answers'][$i]['upload_image']['tmp_name'],
150
                    $path . $data['answers'][$i]['upload_image']['name']
151
                );
152
                $answer->setImage($media_url . $data['answers'][$i]['upload_image']['name']);
153
                ErrorHandler::stop(true);
154
            }
155
            $i++;
156
        }
157
158
        // Max points and correct answers recalculation for the quiz
159
        $quiz = $this->calculateMaxAnswersQuiz($question->getQuiz());
160
161
        // If the question was a pronostic, I update entries with the results !
162
        if ($question->getPrediction()) {
163
            // je recherche toutes les participations au jeu
164
            $entries = $this->getEntryMapper()->findByGameId($question->getQuiz());
165
166
            $answers = $question->getAnswers();
167
168
            $answersarray = array();
169
            foreach ($answers as $answer) {
170
                $answersarray[$answer->getId()] = $answer;
171
            }
172
173
            // I update all answers with points and correctness
174
            // Refactorer findByEntryAndQuestion pour qu'elle fonctionne avec QuizReplyAnswer
175
            /**
176
             * 1. Je recherche $this->getQuizReplyMapper()->findByEntry($entry)
177
             * 2. Pour chaque entrée trouvée, je recherche
178
             * $this->getQuizReplyAnswerMapper()->findByReplyAndQuestion($reply, $question->getId())
179
             * 3. Je mets à jour reply avec le nb de bonnes réponses
180
             * 4. Je trigger une story ?
181
             */
182
            foreach ($entries as $entry) {
183
                $quizReplies = $this->getQuizReplyMapper()->findByEntry($entry);
184
                if ($quizReplies) {
185
                    foreach ($quizReplies as $reply) {
186
                        $quizReplyAnswers = $this->getQuizReplyAnswerMapper()->findByReplyAndQuestion(
187
                            $reply,
188
                            $question->getId()
189
                        );
190
                        $quizPoints = 0;
191
                        $quizCorrectAnswers = 0;
192
                        if ($quizReplyAnswers) {
193
                            foreach ($quizReplyAnswers as $quizReplyAnswer) {
194
                                if (2 != $question->getType()) {
195
                                    if ($answersarray[$quizReplyAnswer->getAnswerId()]) {
196
                                        $updatedAnswer = $answersarray[$quizReplyAnswer->getAnswerId()];
197
                                        $quizReplyAnswer->setPoints($updatedAnswer->getPoints());
198
                                        $quizPoints += $updatedAnswer->getPoints();
199
                                        $quizReplyAnswer->setCorrect($updatedAnswer->getCorrect());
200
                                        $quizCorrectAnswers += $updatedAnswer->getCorrect();
201
                                        $quizReplyAnswer = $this->getQuizReplyAnswerMapper()->update(
202
                                            $quizReplyAnswer
203
                                        );
204
                                    }
205
                                } else {
206
                                    // question is a textarea
207
                                    // search for a matching answer
208
                                    foreach ($answers as $answer) {
209
                                        if (trim(strip_tags($answer->getAnswer())) == trim(
210
                                            strip_tags($quizReplyAnswer->getAnswer())
211
                                        )
212
                                        ) {
213
                                            $quizReplyAnswer->setPoints($answer->getPoints());
214
                                            $quizPoints += $answer->getPoints();
215
                                            $quizReplyAnswer->setCorrect($answer->getCorrect());
216
                                            $quizCorrectAnswers += $answer->getCorrect();
217
                                            $quizReplyAnswer = $this->getQuizReplyAnswerMapper()->update(
218
                                                $quizReplyAnswer
219
                                            );
220
                                            break;
221
                                        }
222
                                    }
223
                                }
224
                            }
225
                        }
226
                    }
227
                }
228
                $winner = $this->isWinner($quiz, $quizCorrectAnswers);
0 ignored issues
show
Bug introduced by
The variable $quizCorrectAnswers does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
229
                $entry->setWinner($winner);
230
                $entry->setPoints($quizPoints);
0 ignored issues
show
Bug introduced by
The variable $quizPoints does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
231
                $entry->setActive(false);
232
                $entry = $this->getEntryMapper()->update($entry);
233
            }
234
235
            $this->getEventManager()->trigger(
236
                __FUNCTION__.'.prediction',
237
                $this,
238
                array('question' => $question, 'data' => $data)
239
            );
240
        }
241
242
        $this->getEventManager()->trigger(
243
            __FUNCTION__,
244
            $this,
245
            array('question' => $question, 'data' => $data)
246
        );
247
        $this->getQuizQuestionMapper()->update($question);
248
        $this->getEventManager()->trigger(
249
            __FUNCTION__.'.post',
250
            $this,
251
            array('question' => $question, 'data' => $data)
252
        );
253
254
        $this->getQuizMapper()->update($quiz);
255
256
        return $question;
257
    }
258
259
    /**
260
     * This function update the sort order of the questions in a Quiz
261
     *
262
     * @param  string $data
263
     * @return boolean
264
     */
265
    public function sortQuestion($data)
266
    {
267
        $arr = explode(",", $data);
268
269
        foreach ($arr as $k => $v) {
270
            $question = $this->getQuizQuestionMapper()->findById($v);
271
            $question->setPosition($k);
272
            $this->getQuizQuestionMapper()->update($question);
273
        }
274
275
        return true;
276
    }
277
278
    /**
279
     * @return string
280
     */
281
    public function calculateMaxAnswersQuestion($question)
282
    {
283
        $question_max_points = 0;
284
        $question_max_correct_answers = 0;
285
        // Closed question : Only one answer allowed
286
        if ($question->getType() == 0) {
287
            foreach ($question->getAnswers() as $answer) {
288
                if ($answer->getPoints() > $question_max_points) {
289
                    $question_max_points = $answer->getPoints();
290
                }
291
                if ($answer->getCorrect() && $question_max_correct_answers==0) {
292
                    $question_max_correct_answers=1;
293
                }
294
            }
295
            if ($question_max_correct_answers == 0) {
296
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\Q...ulateMaxAnswersQuestion of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
297
            }
298
        // Closed question : Many answers allowed
299
        } elseif ($question->getType() == 1) {
300
            foreach ($question->getAnswers() as $answer) {
301
                $question_max_points += $answer->getPoints();
302
303
                if ($answer->getCorrect()) {
304
                    ++$question_max_correct_answers;
305
                }
306
            }
307
            if ($question_max_correct_answers == 0) {
308
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\Q...ulateMaxAnswersQuestion of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
309
            }
310
        // Not a question : A textarea to fill in
311
        } elseif ($question->getType() == 2) {
312
            $question_max_correct_answers = 0;
313
        }
314
315
        $question->setMaxPoints($question_max_points);
316
        $question->setMaxCorrectAnswers($question_max_correct_answers);
317
318
        return $question;
319
    }
320
321
    public function calculateMaxAnswersQuiz($quiz)
322
    {
323
        $question_max_points = 0;
324
        $question_max_correct_answers = 0;
325
        foreach ($quiz->getQuestions() as $question) {
326
            $question_max_points += $question->getMaxPoints();
327
            $question_max_correct_answers += $question->getMaxCorrectAnswers();
328
        }
329
        $quiz->setMaxPoints($question_max_points);
330
        $quiz->setMaxCorrectAnswers($question_max_correct_answers);
331
332
        return $quiz;
333
    }
334
335 View Code Duplication
    public function getNumberCorrectAnswersQuiz($user, $count = 'count')
0 ignored issues
show
Unused Code introduced by
The parameter $count is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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.

Loading history...
336
    {
337
        $em = $this->getServiceManager()->get('doctrine.entitymanager.orm_default');
338
339
        $query = $em->createQuery(
340
            "SELECT COUNT(e.id) FROM PlaygroundGame\Entity\Entry e, PlaygroundGame\Entity\Game g
341
                WHERE e.user = :user
342
                AND g.classType = 'quiz'
343
                AND e.points > 0"
344
        );
345
        $query->setParameter('user', $user);
346
        $number = $query->getSingleScalarResult();
347
348
        return $number;
349
    }
350
351
    public function createQuizReply($data, $game, $user)
352
    {
353
        // Si mon nb de participation est < au nb autorisé, j'ajoute une entry + reponses au quiz et points
354
        $quizReplyMapper = $this->getQuizReplyMapper();
355
        $entryMapper = $this->getEntryMapper();
356
        $entry = $this->findLastActiveEntry($game, $user);
357
358
        if (!$entry) {
359
            return false;
360
        }
361
362
        $quizPoints          = 0;
363
        $quizCorrectAnswers  = 0;
364
        $maxCorrectAnswers = $game->getMaxCorrectAnswers();
365
        $totalQuestions = 0;
366
367
        $quizReply = new QuizReply();
368
        
369
        foreach ($data as $group) {
370
            foreach ($group as $q => $a) {
371
                if (strlen($q) > 5 && strpos($q, '-data', strlen($q) - 5) !== false) {
372
                    continue; // answer data is processed below
373
                }
374
                $question = $this->getQuizQuestionMapper()->findById((int) str_replace('q', '', $q));
375
                ++$totalQuestions;
376
                if (is_array($a)) {
377
                    foreach ($a as $k => $answer_id) {
378
                        $answer = $this->getQuizAnswerMapper()->findById($answer_id);
379 View Code Duplication
                        if ($answer) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
380
                            $quizReplyAnswer = new QuizReplyAnswer();
381
                            $quizReplyAnswer->setAnswer($answer->getAnswer());
382
                            $quizReplyAnswer->setAnswerId($answer_id);
383
                            $quizReplyAnswer->setQuestion($question->getQuestion());
384
                            $quizReplyAnswer->setQuestionId($question->getId());
385
                            $quizReplyAnswer->setPoints($answer->getPoints());
386
                            $quizReplyAnswer->setCorrect($answer->getCorrect());
387
388
                            $quizReply->addAnswer($quizReplyAnswer);
389
                            $quizPoints += $answer->getPoints();
390
                            $quizCorrectAnswers += $answer->getCorrect();
391
392
                            if (isset($group[$q.'-'.$answer_id.'-data'])) {
393
                                $quizReplyAnswer->setAnswerData($group[$q.'-'.$answer_id.'-data']);
394
                            }
395
                        }
396
                    }
397
                } elseif ($question->getType() == 0 || $question->getType() == 1) {
398
                    ++$totalQuestions;
399
                    $answer = $this->getQuizAnswerMapper()->findById($a);
400 View Code Duplication
                    if ($answer) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
401
                        $quizReplyAnswer = new QuizReplyAnswer();
402
                        $quizReplyAnswer->setAnswer($answer->getAnswer());
403
                        $quizReplyAnswer->setAnswerId($a);
404
                        $quizReplyAnswer->setQuestion($question->getQuestion());
405
                        $quizReplyAnswer->setQuestionId($question->getId());
406
                        $quizReplyAnswer->setPoints($answer->getPoints());
407
                        $quizReplyAnswer->setCorrect($answer->getCorrect());
408
409
                        $quizReply->addAnswer($quizReplyAnswer);
410
                        $quizPoints += $answer->getPoints();
411
                        $quizCorrectAnswers += $answer->getCorrect();
412
                        if (isset($group[$q.'-'.$a.'-data'])) {
413
                            $quizReplyAnswer->setAnswerData($group[$q.'-'.$a.'-data']);
414
                        }
415
                    }
416
                } elseif ($question->getType() == 2) {
417
                    ++$totalQuestions;
418
                    $quizReplyAnswer = new QuizReplyAnswer();
419
                    
420
                    $quizReplyAnswer->setAnswer($a);
421
                    $quizReplyAnswer->setAnswerId(0);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a object<PlaygroundGame\Entity\unknown_type>.

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);
Loading history...
422
                    $quizReplyAnswer->setQuestion($question->getQuestion());
423
                    $quizReplyAnswer->setQuestionId($question->getId());
424
                    $quizReplyAnswer->setPoints(0);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a object<PlaygroundGame\Entity\field_type>.

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);
Loading history...
425
                    $quizReplyAnswer->setCorrect(0);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a object<PlaygroundGame\Entity\unknown_type>.

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);
Loading history...
426
427
                    $quizReply->addAnswer($quizReplyAnswer);
428
                    $quizPoints += 0;
429
                    $quizCorrectAnswers += 0;
430
                    $qAnswers = $question->getAnswers();
431
                    foreach ($qAnswers as $qAnswer) {
432
                        if (trim(strip_tags($a)) == trim(strip_tags($qAnswer->getAnswer()))) {
433
                            $quizReplyAnswer->setPoints($qAnswer->getPoints());
434
                            $quizPoints += $qAnswer->getPoints();
435
                            $quizReplyAnswer->setCorrect($qAnswer->getCorrect());
436
                            $quizCorrectAnswers += $qAnswer->getCorrect();
437
                            break;
438
                        }
439
                    }
440
441
                    if (isset($group[$q.'-'.$a.'-data'])) {
442
                        $quizReplyAnswer->setAnswerData($group[$q.'-'.$a.'-data']);
443
                    }
444
                }
445
            }
446
        }
447
448
        $winner = $this->isWinner($game, $quizCorrectAnswers);
449
450
        $entry->setWinner($winner);
0 ignored issues
show
Bug introduced by
The method setWinner cannot be called on $entry (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
451
        // Every winning participation is eligible to draw
452
        // Make this modifiable in the admin (choose who can participate to draw)
453
        $entry->setDrawable($winner);
0 ignored issues
show
Bug introduced by
The method setDrawable cannot be called on $entry (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
454
        $entry->setPoints($quizPoints);
0 ignored issues
show
Bug introduced by
The method setPoints cannot be called on $entry (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
455
        $entry->setActive(false);
0 ignored issues
show
Bug introduced by
The method setActive cannot be called on $entry (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
456
        $entry = $entryMapper->update($entry);
457
458
        $quizReply->setEntry($entry);
459
        $quizReply->setTotalCorrectAnswers($quizCorrectAnswers);
460
        $quizReply->setMaxCorrectAnswers($maxCorrectAnswers);
461
        $quizReply->setTotalQuestions($totalQuestions);
462
463
        $quizReplyMapper->insert($quizReply);
464
465
        $this->getEventManager()->trigger(
466
            'complete_quiz.post',
467
            $this,
468
            array('user' => $user, 'entry' => $entry, 'reply' => $quizReply, 'game' => $game)
469
        );
470
471
        return $entry;
472
    }
473
474
    public function isWinner($game, $quizCorrectAnswers = 0)
475
    {
476
        // Pour déterminer le gagnant, je regarde le nombre max de reponses correctes possibles
477
        // dans le jeu, puis je calcule le ratio de bonnes réponses et le compare aux conditions
478
        // de victoire
479
        $winner = false;
0 ignored issues
show
Unused Code introduced by
$winner 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
480
        $maxCorrectAnswers = $game->getMaxCorrectAnswers();
481
        if ($maxCorrectAnswers > 0) {
482
            $ratioCorrectAnswers = ($quizCorrectAnswers / $maxCorrectAnswers) * 100;
483
        } elseif ($game->getVictoryConditions() > 0) {
484
            // In the case I have a pronostic game for example
485
            $ratioCorrectAnswers = 0;
486
        } else {
487
            // In the case I want everybody to win
488
            $ratioCorrectAnswers = 100;
489
        }
490
491
        $winner = false;
492
        if ($game->getVictoryConditions() >= 0) {
493
            if ($ratioCorrectAnswers >= $game->getVictoryConditions()) {
494
                $winner = true;
495
            }
496
        }
497
        return $winner;
498
    }
499
500
    public function getEntriesHeader($game)
501
    {
502
        $header = parent::getEntriesHeader($game);
503
        $header['totalCorrectAnswers'] = 1;
504
505
        return $header;
506
    }
507
508 View Code Duplication
    public function getEntriesQuery($game)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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.

Loading history...
509
    {
510
        $em = $this->getServiceManager()->get('doctrine.entitymanager.orm_default');
511
512
        $qb = $em->createQueryBuilder();
513
        $qb->select('
514
            r.id,
515
            u.username,
516
            u.title,
517
            u.firstname,
518
            u.lastname,
519
            u.email,
520
            u.optin,
521
            u.optinPartner,
522
            u.address,
523
            u.address2,
524
            u.postalCode,
525
            u.city,
526
            u.telephone,
527
            u.mobile,
528
            u.created_at,
529
            u.dob,
530
            e.winner,
531
            e.socialShares,
532
            e.playerData,
533
            e.updated_at,
534
            r.totalCorrectAnswers
535
            ')
536
            ->from('PlaygroundGame\Entity\QuizReply', 'r')
537
            ->innerJoin('r.entry', 'e')
538
            ->leftJoin('e.user', 'u')
539
            ->where($qb->expr()->eq('e.game', ':game'));
540
        
541
        $qb->setParameter('game', $game);
542
543
        return $qb->getQuery();
544
    }
545
546
    public function getGameEntity()
547
    {
548
        return new \PlaygroundGame\Entity\Quiz;
549
    }
550
551
    /**
552
     * getQuizMapper
553
     *
554
     * @return QuizMapperInterface
555
     */
556
    public function getQuizMapper()
557
    {
558
        if (null === $this->quizMapper) {
559
            $this->quizMapper = $this->getServiceManager()->get('playgroundgame_quiz_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceManager...roundgame_quiz_mapper') can also be of type array. However, the property $quizMapper is declared as type object<PlaygroundGame\Se...ce\QuizMapperInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
560
        }
561
562
        return $this->quizMapper;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->quizMapper; of type object|array adds the type array to the return on line 562 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizMapper of type PlaygroundGame\Service\QuizMapperInterface.
Loading history...
563
    }
564
565
    /**
566
     * setQuizMapper
567
     *
568
     * @param  QuizMapperInterface $quizMapper
569
     * @return Game
570
     */
571
    public function setQuizMapper(GameMapperInterface $quizMapper)
572
    {
573
        $this->quizMapper = $quizMapper;
0 ignored issues
show
Documentation Bug introduced by
It seems like $quizMapper of type object<PlaygroundGame\Mapper\GameInterface> is incompatible with the declared type object<PlaygroundGame\Se...ce\QuizMapperInterface> of property $quizMapper.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
574
575
        return $this;
576
    }
577
578
    /**
579
     * getQuizQuestionMapper
580
     *
581
     * @return QuizQuestionMapperInterface
582
     */
583
    public function getQuizQuestionMapper()
584
    {
585
        if (null === $this->quizQuestionMapper) {
586
            $this->quizQuestionMapper = $this->getServiceManager()->get('playgroundgame_quizquestion_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceManager...e_quizquestion_mapper') can also be of type array. However, the property $quizQuestionMapper is declared as type object<PlaygroundGame\Se...uestionMapperInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
587
        }
588
589
        return $this->quizQuestionMapper;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->quizQuestionMapper; of type object|array adds the type array to the return on line 589 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizQuestionMapper of type PlaygroundGame\Service\QuizQuestionMapperInterface.
Loading history...
590
    }
591
592
    /**
593
     * setQuizQuestionMapper
594
     *
595
     * @param  QuizQuestionMapperInterface $quizquestionMapper
596
     * @return Quiz
597
     */
598
    public function setQuizQuestionMapper($quizquestionMapper)
599
    {
600
        $this->quizQuestionMapper = $quizquestionMapper;
601
602
        return $this;
603
    }
604
605
    /**
606
     * setQuizAnswerMapper
607
     *
608
     * @param  QuizAnswerMapperInterface $quizAnswerMapper
609
     * @return Quiz
610
     */
611
    public function setQuizAnswerMapper($quizAnswerMapper)
612
    {
613
        $this->quizAnswerMapper = $quizAnswerMapper;
614
615
        return $this;
616
    }
617
618
    /**
619
     * getQuizAnswerMapper
620
     *
621
     * @return QuizAnswerMapperInterface
622
     */
623
    public function getQuizAnswerMapper()
624
    {
625
        if (null === $this->quizAnswerMapper) {
626
            $this->quizAnswerMapper = $this->getServiceManager()->get('playgroundgame_quizanswer_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceManager...ame_quizanswer_mapper') can also be of type array. However, the property $quizAnswerMapper is declared as type object<PlaygroundGame\Se...zAnswerMapperInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
627
        }
628
629
        return $this->quizAnswerMapper;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->quizAnswerMapper; of type object|array adds the type array to the return on line 629 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizAnswerMapper of type PlaygroundGame\Service\QuizAnswerMapperInterface.
Loading history...
630
    }
631
632
    /**
633
     * getQuizReplyMapper
634
     *
635
     * @return QuizReplyMapperInterface
636
     */
637
    public function getQuizReplyMapper()
638
    {
639
        if (null === $this->quizReplyMapper) {
640
            $this->quizReplyMapper = $this->getServiceManager()->get('playgroundgame_quizreply_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceManager...game_quizreply_mapper') can also be of type array. However, the property $quizReplyMapper is declared as type object<PlaygroundGame\Se...izReplyMapperInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
641
        }
642
643
        return $this->quizReplyMapper;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->quizReplyMapper; of type object|array adds the type array to the return on line 643 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizReplyMapper of type PlaygroundGame\Service\QuizReplyMapperInterface.
Loading history...
644
    }
645
646
    /**
647
     * setQuizReplyMapper
648
     *
649
     * @param  QuizReplyMapperInterface $quizreplyMapper
650
     * @return Quiz
651
     */
652
    public function setQuizReplyMapper($quizreplyMapper)
653
    {
654
        $this->quizReplyMapper = $quizreplyMapper;
655
656
        return $this;
657
    }
658
659
    /**
660
     * getQuizReplyAnswerMapper
661
     *
662
     * @return QuizReplyAnswerMapper
663
     */
664
    public function getQuizReplyAnswerMapper()
665
    {
666
        if (null === $this->quizReplyAnswerMapper) {
667
            $this->quizReplyAnswerMapper = $this->getServiceManager()->get('playgroundgame_quizreplyanswer_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceManager...uizreplyanswer_mapper') can also be of type array. However, the property $quizReplyAnswerMapper is declared as type object<PlaygroundGame\Se...\QuizReplyAnswerMapper>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
668
        }
669
670
        return $this->quizReplyAnswerMapper;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->quizReplyAnswerMapper; of type object|array adds the type array to the return on line 670 which is incompatible with the return type documented by PlaygroundGame\Service\Q...etQuizReplyAnswerMapper of type PlaygroundGame\Service\QuizReplyAnswerMapper.
Loading history...
671
    }
672
673
     /**
674
     * setQuizReplyAnswerMapper
675
     *
676
     * @param  QuizReplyAnswerMapper $quizReplyAnswerMapper
677
     * @return Quiz
678
     */
679
    public function setQuizReplyAnswerMapper($quizReplyAnswerMapper)
680
    {
681
        $this->quizReplyAnswerMapper = $quizReplyAnswerMapper;
682
683
        return $this;
684
    }
685
}
686