Completed
Push — develop ( 52375c...f6676f )
by greg
02:38
created

Quiz::updatePredictionNEW()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 81
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 81
rs 8.3904
c 0
b 0
f 0
cc 6
eloc 36
nc 6
nop 1

How to fix   Long Method   

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 PlaygroundGame\Mapper\GameInterface as GameMapperInterface;
8
use Zend\Stdlib\ErrorHandler;
9
10
class Quiz extends Game
11
{
12
    /**
13
     * @var QuizMapperInterface
14
     */
15
    protected $quizMapper;
16
17
    /**
18
     * @var QuizAnswerMapperInterface
19
     */
20
    protected $quizAnswerMapper;
21
22
    /**
23
     * @var QuizQuestionMapperInterface
24
     */
25
    protected $quizQuestionMapper;
26
27
    /**
28
     * @var QuizReplyMapperInterface
29
     */
30
    protected $quizReplyMapper;
31
32
    /**
33
     * @var quizReplyAnswerMapper
34
     */
35
    protected $quizReplyAnswerMapper;
36
37
    /**
38
     *
39
     *
40
     * @param  array                  $data
41
     * @return \PlaygroundGame\Entity\Game
42
     */
43
    public function createQuestion(array $data)
44
    {
45
        $path      = $this->getOptions()->getMediaPath().DIRECTORY_SEPARATOR;
46
        $media_url = $this->getOptions()->getMediaUrl().'/';
47
48
        $question = new \PlaygroundGame\Entity\QuizQuestion();
49
        $form     = $this->serviceLocator->get('playgroundgame_quizquestion_form');
50
        $form->bind($question);
51
        $form->setData($data);
52
53
        $quiz = $this->getGameMapper()->findById($data['quiz_id']);
54
        if (!$form->isValid()) {
55
            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...
56
        }
57
58
        $question->setQuiz($quiz);
59
60
        // If question is a prediction, no need to calculate max good answers
61
        if (!$question->getPrediction()) {
62
            // Max points and correct answers calculation for the question
63
            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 89 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::createQuestion of type PlaygroundGame\Entity\Game.
Loading history...
64
                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...
65
            }
66
        }
67
68
        // Max points and correct answers recalculation for the quiz
69
        $quiz = $this->calculateMaxAnswersQuiz($question->getQuiz());
70
71
        $this->getEventManager()->trigger(__FUNCTION__, $this, array('game' => $question, 'data' => $data));
72
        $this->getQuizQuestionMapper()->insert($question);
73
        $this->getEventManager()->trigger(__FUNCTION__ .'.post', $this, array('game' => $question, 'data' => $data));
74
75 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...
76
            ErrorHandler::start();
77
            $data['upload_image']['name'] = $this->fileNewname(
78
                $path,
79
                $question->getId()."-".$data['upload_image']['name']
80
            );
81
            move_uploaded_file($data['upload_image']['tmp_name'], $path.$data['upload_image']['name']);
82
            $question->setImage($media_url.$data['upload_image']['name']);
83
            ErrorHandler::stop(true);
84
        }
85
86
        $this->getQuizQuestionMapper()->update($question);
87
        $this->getQuizMapper()->update($quiz);
88
89
        return $question;
90
    }
91
92
    /**
93
     * @param  array $data
94
     * @return \PlaygroundGame\Entity\Game
95
     */
96
    public function updateQuestion(array $data, $question)
97
    {
98
        $path      = $this->getOptions()->getMediaPath().DIRECTORY_SEPARATOR;
99
        $media_url = $this->getOptions()->getMediaUrl().'/';
100
101
        $form = $this->serviceLocator->get('playgroundgame_quizquestion_form');
102
        $form->bind($question);
103
        $form->setData($data);
104
105
        if (!$form->isValid()) {
106
            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...
107
        }
108
109
        // If question is a prediction, no need to calculate max good answers
110
        if (!$question->getPrediction()) {
111
            // Max points and correct answers calculation for the question
112
            if (!$question = $this->calculateMaxAnswersQuestion($question)) {
113
                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...
114
            }
115
        }
116
117 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...
118
            ErrorHandler::start();
119
            $data['upload_image']['name'] = $this->fileNewname(
120
                $path,
121
                $question->getId()."-".$data['upload_image']['name']
122
            );
123
            move_uploaded_file($data['upload_image']['tmp_name'], $path.$data['upload_image']['name']);
124
            $question->setImage($media_url.$data['upload_image']['name']);
125
            ErrorHandler::stop(true);
126
        }
127
128 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...
129
            ErrorHandler::start();
130
            $image = $question->getImage();
131
            $image = str_replace($media_url, '', $image);
132
            if (file_exists($path.$image)) {
133
                unlink($path.$image);
134
            }
135
            $question->setImage(null);
136
            ErrorHandler::stop(true);
137
        }
138
139
        $i = 0;
140
        foreach ($question->getAnswers() as $answer) {
141
            if (!empty($data['answers'][$i]['upload_image']['tmp_name'])) {
142
                ErrorHandler::start();
143
                $data['answers'][$i]['upload_image']['name'] = $this->fileNewname(
144
                    $path,
145
                    $question->getId()."-".$data['answers'][$i]['upload_image']['name']
146
                );
147
                move_uploaded_file(
148
                    $data['answers'][$i]['upload_image']['tmp_name'],
149
                    $path.$data['answers'][$i]['upload_image']['name']
150
                );
151
                $answer->setImage($media_url.$data['answers'][$i]['upload_image']['name']);
152
                ErrorHandler::stop(true);
153
            }
154
            $i++;
155
        }
156
157
        // Max points and correct answers recalculation for the quiz
158
        $quiz = $this->calculateMaxAnswersQuiz($question->getQuiz());
159
160
        // If the question was a pronostic, I update entries with the results !
161
        if ($question->getPrediction()) {
162
            $this->updatePrediction($question);
163
        }
164
165
        $this->getEventManager()->trigger(
166
            __FUNCTION__,
167
            $this,
168
            array('question' => $question, 'data' => $data)
169
        );
170
        $this->getQuizQuestionMapper()->update($question);
171
        $this->getEventManager()->trigger(
172
            __FUNCTION__ .'.post',
173
            $this,
174
            array('question' => $question, 'data' => $data)
175
        );
176
177
        $this->getQuizMapper()->update($quiz);
178
179
        return $question;
180
    }
181
182
    public function findRepliesByGame($game)
183
    {
184
        $em = $this->serviceLocator->get('doctrine.entitymanager.orm_default');
185
        $qb = $em->createQueryBuilder();
186
        $qb->select('r')
187
           ->from('PlaygroundGame\Entity\QuizReply', 'r')
188
           ->innerJoin('r.entry', 'e')
189
           ->where('e.game = :game')
190
           ->setParameter('game', $game);
191
        $query = $qb->getQuery();
192
193
        $replies = $query->getResult();
194
195
        return $replies;
196
    }
197
198
    public function updatePrediction($question)
199
    {
200
        set_time_limit(0);
201
        $em = $this->serviceLocator->get('doctrine.entitymanager.orm_default');
202
203
        /* @var $dbal \Doctrine\DBAL\Connection */
204
        $dbal = $em->getConnection();
205
206
        $answers = $question->getAnswers($question->getQuiz());
207
208
        // I update all the answers with points and correctness
209
        // Very fast (native query inside)
210
        if ($question->getType() == 2) {
211
            foreach ($answers as $answer) {
212
                $value  = trim(strip_tags($answer->getAnswer()));
213
                $points = ($answer->getCorrect())?$answer->getPoints():0;
214
                $sql    = "
215
                UPDATE game_quiz_reply_answer AS ra
216
                SET ra.points=IF(ra.answer=:answer, :points, 0),
217
                    ra.correct = IF(ra.answer=:answer, :isCorrect, 0)
218
                WHERE ra.question_id = :questionId
219
                ";
220
                $stmt = $dbal->prepare($sql);
221
                $stmt->execute(
222
                    array(
223
                        'answer'     => $value,
224
                        'points'     => $points,
225
                        'isCorrect'  => $answer->getCorrect(),
226
                        'questionId' => $question->getId()
227
                    )
228
                );
229
            }
230
        } else {
231
            foreach ($answers as $answer) {
232
                $points = ($answer->getCorrect())?$answer->getPoints():0;
233
                $sql    = "
234
                UPDATE game_quiz_reply_answer AS ra
235
                SET ra.points=:points,
236
                    ra.correct = :isCorrect
237
                WHERE ra.question_id = :questionId
238
                    AND ra.answer_id = :answerId
239
                ";
240
241
                $stmt = $dbal->prepare($sql);
242
                $stmt->execute(
243
                    array(
244
                        'points'     => $points,
245
                        'isCorrect'  => $answer->getCorrect(),
246
                        'questionId' => $question->getId(),
247
                        'answerId'   => $answer->getId()
248
                    )
249
                );
250
            }
251
        }
252
253
        // Entry update with points. WINNER as to be calculated also !
254
        $sql = "
255
        UPDATE game_entry as e
256
        INNER JOIN
257
        (
258
            SELECT e.id, SUM(ra.points) as points, SUM(ra.correct) as correct
259
            FROM game_entry as e
260
            INNER JOIN game_quiz_reply AS r ON r.entry_id = e.id
261
            INNER JOIN game_quiz_reply_answer AS ra ON ra.reply_id = r.id AND ra.correct = 1
262
            GROUP BY e.id
263
        ) i ON e.id = i.id
264
        SET e.points = i.points
265
        WHERE e.game_id = :gameId
266
        ";
267
268
        $stmt = $dbal->prepare($sql);
269
        $stmt->execute(
270
            array('gameId' => $question->getQuiz()->getId())
271
        );
272
273
        $this->getEventManager()->trigger(
274
            __FUNCTION__ .'.post',
275
            $this,
276
            array('question' => $question)
277
        );
278
    }
279
    /**
280
     * This function update the sort order of the questions in a Quiz
281
     * BEWARE : This function is time consuming (1s for 11 updates)
282
     * If you have many replies, switch to a  batch
283
     *
284
     * To improve performance, usage of DQL update
285
     * http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html
286
     *
287
     * @param  string $data
0 ignored issues
show
Bug introduced by
There is no parameter named $data. 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 $italy is not defined by the method finale(...).

/**
 * @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.

Loading history...
288
     * @return boolean
289
     */
290
    public function updatePredictionOLD($question)
291
    {
292
        set_time_limit(0);
293
        $em = $this->serviceLocator->get('doctrine.entitymanager.orm_default');
294
295
        $replies = $this->findRepliesByGame($question->getQuiz());
296
297
        $answers = $question->getAnswers($question->getQuiz());
298
299
        $answersarray = array();
300
        foreach ($answers as $answer) {
301
            $answersarray[$answer->getId()] = $answer;
302
        }
303
304
        foreach ($replies as $reply) {
305
            $quizPoints         = 0;
306
            $quizCorrectAnswers = 0;
307
308
            foreach ($reply->getAnswers() as $quizReplyAnswer) {
309
                if (2 != $question->getType() && $quizReplyAnswer->getQuestionId() === $question->getId()) {
310
                    if ($answersarray[$quizReplyAnswer->getAnswerId()]) {
311
                        $updatedAnswer = $answersarray[$quizReplyAnswer->getAnswerId()];
312
                        $quizReplyAnswer->setPoints($updatedAnswer->getPoints());
313
                        $quizReplyAnswer->setCorrect($updatedAnswer->getCorrect());
314
                        $q = $em->createQuery('
315
							UPDATE PlaygroundGame\Entity\QuizReplyAnswer a
316
              SET a.points = :points, a.correct=:isCorrect
317
              WHERE a.id=:answerId
318
						');
319
                        $q->setParameter('points', $updatedAnswer->getPoints());
320
                        $q->setParameter('isCorrect', $updatedAnswer->getCorrect());
321
                        $q->setParameter('answerId', $quizReplyAnswer->getId());
322
                        $q->execute();
323
                    }
324
                } elseif ($quizReplyAnswer->getQuestionId() === $question->getId()) {
325
                    // question is a textarea
326
                    // search for a matching answer
327
                    foreach ($answers as $answer) {
328
                        if (trim(strip_tags($answer->getAnswer())) == trim(
329
                            strip_tags($quizReplyAnswer->getAnswer())
330
                        )
331
                        ) {
332
                            $quizReplyAnswer->setPoints($answer->getPoints());
333
                            $quizReplyAnswer->setCorrect($answer->getCorrect());
334
                            $q = $em->createQuery('
335
                              UPDATE PlaygroundGame\Entity\QuizReplyAnswer a
336
                              SET a.points = :points, a.correct=:isCorrect
337
                              WHERE a.id=:answerId
338
                            ');
339
                            $q->setParameter('points', $updatedAnswer->getPoints());
0 ignored issues
show
Bug introduced by
The variable $updatedAnswer 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...
340
                            $q->setParameter('isCorrect', $updatedAnswer->getCorrect());
341
                            $q->setParameter('answerId', $quizReplyAnswer->getId());
342
                            $q->execute();
343
                        } else {
344
                            $quizReplyAnswer->setPoints(0);
345
                            $quizReplyAnswer->setCorrect(false);
346
                            $q = $em->createQuery('
347
                              UPDATE PlaygroundGame\Entity\QuizReplyAnswer a
348
                              SET a.points = 0, a.correct = false
349
                              WHERE a.id=:answerId
350
                            ');
351
                            $q->setParameter('answerId', $quizReplyAnswer->getId());
352
                            $q->execute();
353
                        }
354
                    }
355
                }
356
357
                // The reply has been updated with correct answers and points for this question.
358
                // I count the whole set of points for this reply and update the entry
359
                if ($quizReplyAnswer->getCorrect()) {
360
                    $quizPoints += $quizReplyAnswer->getPoints();
361
                    $quizCorrectAnswers += $quizReplyAnswer->getCorrect();
362
                }
363
            }
364
365
            $winner = $this->isWinner($question->getQuiz(), $quizCorrectAnswers);
366
            $reply->getEntry()->setWinner($winner);
367
            $reply->getEntry()->setPoints($quizPoints);
368
            // The entry should be inactive : entry->setActive(false);
369
            $this->getEntryMapper()->update($reply->getEntry());
370
        }
371
372
        $this->getEventManager()->trigger(
373
            __FUNCTION__ .'.post',
374
            $this,
375
            array('question' => $question)
376
        );
377
    }
378
379
    /**
380
     * This function update the sort order of the questions in a Quiz
381
     *
382
     * @param  string $data
383
     * @return boolean
384
     */
385
    public function sortQuestion($data)
386
    {
387
        $arr = explode(",", $data);
388
389
        foreach ($arr as $k => $v) {
390
            $question = $this->getQuizQuestionMapper()->findById($v);
391
            $question->setPosition($k);
392
            $this->getQuizQuestionMapper()->update($question);
393
        }
394
395
        return true;
396
    }
397
398
    /**
399
     * @return string
400
     */
401
    public function calculateMaxAnswersQuestion($question)
402
    {
403
        $question_max_points          = 0;
404
        $question_max_correct_answers = 0;
405
        // Closed question : Only one answer allowed
406
        if ($question->getType() == 0) {
407
            foreach ($question->getAnswers() as $answer) {
408
                if ($answer->getPoints() > $question_max_points) {
409
                    $question_max_points = $answer->getPoints();
410
                }
411
                if ($answer->getCorrect() && $question_max_correct_answers == 0) {
412
                    $question_max_correct_answers = 1;
413
                }
414
            }
415
            if ($question_max_correct_answers == 0) {
416
                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...
417
            }
418
            // Closed question : Many answers allowed
419
        } elseif ($question->getType() == 1) {
420
            foreach ($question->getAnswers() as $answer) {
421
                $question_max_points += $answer->getPoints();
422
423
                if ($answer->getCorrect()) {
424
                    ++$question_max_correct_answers;
425
                }
426
            }
427
            if ($question_max_correct_answers == 0) {
428
                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...
429
            }
430
            // Not a question : A textarea to fill in
431
        } elseif ($question->getType() == 2) {
432
            $question_max_correct_answers = 0;
433
        }
434
435
        $question->setMaxPoints($question_max_points);
436
        $question->setMaxCorrectAnswers($question_max_correct_answers);
437
438
        return $question;
439
    }
440
441
    public function calculateMaxAnswersQuiz($quiz)
442
    {
443
        $question_max_points          = 0;
444
        $question_max_correct_answers = 0;
445
        foreach ($quiz->getQuestions() as $question) {
446
            $question_max_points += $question->getMaxPoints();
447
            $question_max_correct_answers += $question->getMaxCorrectAnswers();
448
        }
449
        $quiz->setMaxPoints($question_max_points);
450
        $quiz->setMaxCorrectAnswers($question_max_correct_answers);
451
452
        return $quiz;
453
    }
454
455 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...
456
    {
457
        $em = $this->serviceLocator->get('doctrine.entitymanager.orm_default');
458
459
        $query = $em->createQuery(
460
            "SELECT COUNT(e.id) FROM PlaygroundGame\Entity\Entry e, PlaygroundGame\Entity\Game g
461
                WHERE e.user = :user
462
                AND g.classType = 'quiz'
463
                AND e.points > 0"
464
        );
465
        $query->setParameter('user', $user);
466
        $number = $query->getSingleScalarResult();
467
468
        return $number;
469
    }
470
471
    public function createQuizReply($data, $game, $user)
472
    {
473
        // Si mon nb de participation est < au nb autorisé, j'ajoute une entry + reponses au quiz et points
474
        $quizReplyMapper = $this->getQuizReplyMapper();
475
        $entryMapper     = $this->getEntryMapper();
476
        $entry           = $this->findLastActiveEntry($game, $user);
477
478
        if (!$entry) {
479
            return false;
480
        }
481
482
        $quizPoints         = 0;
483
        $quizCorrectAnswers = 0;
484
        $maxCorrectAnswers  = $game->getMaxCorrectAnswers();
485
        $totalQuestions     = 0;
486
487
        $quizReply = $this->getQuizReplyMapper()->getLastGameReply($entry);
488
        if (!$quizReply) {
489
            $quizReply = new QuizReply();
490
        } else {
491
            $quizReplyAnswered = [];
492
            foreach ($quizReply->getAnswers() as $answer) {
493
                $quizReplyAnswered[$answer->getQuestionId()] = $answer;
494
            }
495
        }
496
497
        foreach ($data as $group) {
498
            foreach ($group as $q => $a) {
499
                if (strlen($q) > 5 && strpos($q, '-data', strlen($q)-5) !== false) {
500
                    continue;// answer data is processed below
501
                }
502
                $question = $this->getQuizQuestionMapper()->findById((int) str_replace('q', '', $q));
503
                ++$totalQuestions;
504
                if (is_array($a)) {
505
                    foreach ($a as $k => $answer_id) {
506
                        $answer = $this->getQuizAnswerMapper()->findById($answer_id);
507 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...
508
                            if (isset($quizReplyAnswered[$question->getId()])) {
509
                                $this->getQuizReplyAnswerMapper()->remove($quizReplyAnswered[$question->getId()]);
510
                            }
511
512
                            $quizReplyAnswer = new QuizReplyAnswer();
513
                            $quizReplyAnswer->setAnswer($answer->getAnswer());
514
                            $quizReplyAnswer->setAnswerId($answer_id);
515
                            $quizReplyAnswer->setQuestion($question->getQuestion());
516
                            $quizReplyAnswer->setQuestionId($question->getId());
517
                            $quizReplyAnswer->setPoints($answer->getPoints());
518
                            $quizReplyAnswer->setCorrect($answer->getCorrect());
519
520
                            $quizReply->addAnswer($quizReplyAnswer);
521
522
                            $quizPoints += $answer->getPoints();
523
                            $quizCorrectAnswers += $answer->getCorrect();
524
525
                            if (isset($group[$q.'-'.$answer_id.'-data'])) {
526
                                $quizReplyAnswer->setAnswerData($group[$q.'-'.$answer_id.'-data']);
527
                            }
528
                        }
529
                    }
530
                } elseif ($question->getType() == 0 || $question->getType() == 1) {
531
                    ++$totalQuestions;
532
                    $answer = $this->getQuizAnswerMapper()->findById($a);
533 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...
534
                        if (isset($quizReplyAnswered[$question->getId()])) {
535
                            $this->getQuizReplyAnswerMapper()->remove($quizReplyAnswered[$question->getId()]);
536
                        }
537
                        $quizReplyAnswer = new QuizReplyAnswer();
538
                        $quizReplyAnswer->setAnswer($answer->getAnswer());
539
                        $quizReplyAnswer->setAnswerId($a);
540
                        $quizReplyAnswer->setQuestion($question->getQuestion());
541
                        $quizReplyAnswer->setQuestionId($question->getId());
542
                        $quizReplyAnswer->setPoints($answer->getPoints());
543
                        $quizReplyAnswer->setCorrect($answer->getCorrect());
544
545
                        $quizReply->addAnswer($quizReplyAnswer);
546
547
                        $quizPoints += $answer->getPoints();
548
                        $quizCorrectAnswers += $answer->getCorrect();
549
                        if (isset($group[$q.'-'.$a.'-data'])) {
550
                            $quizReplyAnswer->setAnswerData($group[$q.'-'.$a.'-data']);
551
                        }
552
                    }
553
                } elseif ($question->getType() == 2) {
554
                    ++$totalQuestions;
555
                    if (isset($quizReplyAnswered[$question->getId()])) {
556
                        $this->getQuizReplyAnswerMapper()->remove($quizReplyAnswered[$question->getId()]);
557
                    }
558
                    $quizReplyAnswer = new QuizReplyAnswer();
559
                    $quizReplyAnswer->setAnswer($a);
560
                    $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...
561
                    $quizReplyAnswer->setQuestion($question->getQuestion());
562
                    $quizReplyAnswer->setQuestionId($question->getId());
563
                    $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...
564
                    $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...
565
566
                    $quizReply->addAnswer($quizReplyAnswer);
567
568
                    $quizPoints += 0;
569
                    $quizCorrectAnswers += 0;
570
                    $qAnswers = $question->getAnswers();
571
                    foreach ($qAnswers as $qAnswer) {
572
                        if (trim(strip_tags($a)) == trim(strip_tags($qAnswer->getAnswer()))) {
573
                            $quizReplyAnswer->setPoints($qAnswer->getPoints());
574
                            $quizPoints += $qAnswer->getPoints();
575
                            $quizReplyAnswer->setCorrect($qAnswer->getCorrect());
576
                            $quizCorrectAnswers += $qAnswer->getCorrect();
577
                            break;
578
                        }
579
                    }
580
581
                    if (isset($group[$q.'-'.$a.'-data'])) {
582
                        $quizReplyAnswer->setAnswerData($group[$q.'-'.$a.'-data']);
583
                    }
584
                }
585
            }
586
        }
587
588
        $winner = $this->isWinner($game, $quizCorrectAnswers);
589
590
        $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...
591
        // Every winning participation is eligible to draw
592
        // Make this modifiable in the admin (choose who can participate to draw)
593
        $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...
594
        $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...
595
        $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...
596
        $entry = $entryMapper->update($entry);
597
598
        $quizReply->setEntry($entry);
599
        $quizReply->setTotalCorrectAnswers($quizCorrectAnswers);
600
        $quizReply->setMaxCorrectAnswers($maxCorrectAnswers);
601
        $quizReply->setTotalQuestions($totalQuestions);
602
603
        $quizReplyMapper->insert($quizReply);
604
605
        $this->getEventManager()->trigger(
606
            __FUNCTION__ .'.post',
607
            $this,
608
            array('user' => $user, 'entry' => $entry, 'reply' => $quizReply, 'game' => $game)
609
        );
610
611
        return $entry;
612
    }
613
614
    public function isWinner($game, $quizCorrectAnswers = 0)
615
    {
616
        // Pour déterminer le gagnant, je regarde le nombre max de reponses correctes possibles
617
        // dans le jeu, puis je calcule le ratio de bonnes réponses et le compare aux conditions
618
        // de victoire
619
        $winner            = false;
620
        $maxCorrectAnswers = $game->getMaxCorrectAnswers();
621
        if ($maxCorrectAnswers > 0) {
622
            $ratioCorrectAnswers = ($quizCorrectAnswers/$maxCorrectAnswers)*100;
623
        } elseif ($game->getVictoryConditions() > 0) {
624
            // In the case I have a pronostic game for example
625
            $ratioCorrectAnswers = 0;
626
        } else {
627
            // In the case I want everybody to win
628
            $ratioCorrectAnswers = 100;
629
        }
630
631
        if ($game->getVictoryConditions() >= 0) {
632
            if ($ratioCorrectAnswers >= $game->getVictoryConditions()) {
633
                $winner = true;
634
            }
635
        }
636
        return $winner;
637
    }
638
639
    public function getEntriesHeader($game)
640
    {
641
        $header                        = parent::getEntriesHeader($game);
642
        $header['totalCorrectAnswers'] = 1;
643
644
        return $header;
645
    }
646
647 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...
648
    {
649
        $em = $this->serviceLocator->get('doctrine.entitymanager.orm_default');
650
651
        $qb = $em->createQueryBuilder();
652
        $qb->select('
653
            r.id,
654
            u.username,
655
            u.title,
656
            u.firstname,
657
            u.lastname,
658
            u.email,
659
            u.optin,
660
            u.optinPartner,
661
            u.address,
662
            u.address2,
663
            u.postalCode,
664
            u.city,
665
            u.telephone,
666
            u.mobile,
667
            u.created_at,
668
            u.dob,
669
            e.winner,
670
            e.socialShares,
671
            e.playerData,
672
            e.updated_at,
673
            r.totalCorrectAnswers
674
            ')
675
        ->from('PlaygroundGame\Entity\QuizReply', 'r')
676
        ->innerJoin('r.entry', 'e')
677
        ->leftJoin('e.user', 'u')
678
        ->where($qb->expr()->eq('e.game', ':game'));
679
680
        $qb->setParameter('game', $game);
681
682
        return $qb->getQuery();
683
    }
684
685
    public function getGameEntity()
686
    {
687
        return new \PlaygroundGame\Entity\Quiz;
688
    }
689
690
    /**
691
     * getQuizMapper
692
     *
693
     * @return QuizMapperInterface
694
     */
695
    public function getQuizMapper()
696
    {
697
        if (null === $this->quizMapper) {
698
            $this->quizMapper = $this->serviceLocator->get('playgroundgame_quiz_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->serviceLocator->g...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...
699
        }
700
701
        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 701 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizMapper of type PlaygroundGame\Service\QuizMapperInterface.
Loading history...
702
    }
703
704
    /**
705
     * setQuizMapper
706
     *
707
     * @param  QuizMapperInterface $quizMapper
708
     * @return Game
709
     */
710
    public function setQuizMapper(GameMapperInterface $quizMapper)
711
    {
712
        $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...
713
714
        return $this;
715
    }
716
717
    /**
718
     * getQuizQuestionMapper
719
     *
720
     * @return QuizQuestionMapperInterface
721
     */
722
    public function getQuizQuestionMapper()
723
    {
724
        if (null === $this->quizQuestionMapper) {
725
            $this->quizQuestionMapper = $this->serviceLocator->get('playgroundgame_quizquestion_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->serviceLocator->g...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...
726
        }
727
728
        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 728 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizQuestionMapper of type PlaygroundGame\Service\QuizQuestionMapperInterface.
Loading history...
729
    }
730
731
    /**
732
     * setQuizQuestionMapper
733
     *
734
     * @param  QuizQuestionMapperInterface $quizquestionMapper
735
     * @return Quiz
736
     */
737
    public function setQuizQuestionMapper($quizquestionMapper)
738
    {
739
        $this->quizQuestionMapper = $quizquestionMapper;
740
741
        return $this;
742
    }
743
744
    /**
745
     * setQuizAnswerMapper
746
     *
747
     * @param  QuizAnswerMapperInterface $quizAnswerMapper
748
     * @return Quiz
749
     */
750
    public function setQuizAnswerMapper($quizAnswerMapper)
751
    {
752
        $this->quizAnswerMapper = $quizAnswerMapper;
753
754
        return $this;
755
    }
756
757
    /**
758
     * getQuizAnswerMapper
759
     *
760
     * @return QuizAnswerMapperInterface
761
     */
762
    public function getQuizAnswerMapper()
763
    {
764
        if (null === $this->quizAnswerMapper) {
765
            $this->quizAnswerMapper = $this->serviceLocator->get('playgroundgame_quizanswer_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->serviceLocator->g...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...
766
        }
767
768
        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 768 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizAnswerMapper of type PlaygroundGame\Service\QuizAnswerMapperInterface.
Loading history...
769
    }
770
771
    /**
772
     * getQuizReplyMapper
773
     *
774
     * @return QuizReplyMapperInterface
775
     */
776
    public function getQuizReplyMapper()
777
    {
778
        if (null === $this->quizReplyMapper) {
779
            $this->quizReplyMapper = $this->serviceLocator->get('playgroundgame_quizreply_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->serviceLocator->g...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...
780
        }
781
782
        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 782 which is incompatible with the return type documented by PlaygroundGame\Service\Quiz::getQuizReplyMapper of type PlaygroundGame\Service\QuizReplyMapperInterface.
Loading history...
783
    }
784
785
    /**
786
     * setQuizReplyMapper
787
     *
788
     * @param  QuizReplyMapperInterface $quizreplyMapper
789
     * @return Quiz
790
     */
791
    public function setQuizReplyMapper($quizreplyMapper)
792
    {
793
        $this->quizReplyMapper = $quizreplyMapper;
794
795
        return $this;
796
    }
797
798
    /**
799
     * getQuizReplyAnswerMapper
800
     *
801
     * @return QuizReplyAnswerMapper
802
     */
803
    public function getQuizReplyAnswerMapper()
804
    {
805
        if (null === $this->quizReplyAnswerMapper) {
806
            $this->quizReplyAnswerMapper = $this->serviceLocator->get('playgroundgame_quizreplyanswer_mapper');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->serviceLocator->g...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...
807
        }
808
809
        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 809 which is incompatible with the return type documented by PlaygroundGame\Service\Q...etQuizReplyAnswerMapper of type PlaygroundGame\Service\QuizReplyAnswerMapper.
Loading history...
810
    }
811
812
    /**
813
     * setQuizReplyAnswerMapper
814
     *
815
     * @param  QuizReplyAnswerMapper $quizReplyAnswerMapper
816
     * @return Quiz
817
     */
818
    public function setQuizReplyAnswerMapper($quizReplyAnswerMapper)
819
    {
820
        $this->quizReplyAnswerMapper = $quizReplyAnswerMapper;
821
822
        return $this;
823
    }
824
}
825