QuizController   F
last analyzed

Complexity

Total Complexity 96

Size/Duplication

Total Lines 557
Duplicated Lines 25.49 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

Changes 0
Metric Value
wmc 96
lcom 1
cbo 15
dl 142
loc 557
rs 2
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A fbshareAction() 21 21 4
A fbrequestAction() 20 20 4
A tweetAction() 20 20 4
A googleAction() 20 20 4
A getGameService() 0 8 2
F playAction() 46 306 55
F resultAction() 15 142 22

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like QuizController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use QuizController, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace PlaygroundGame\Controller\Frontend;
3
4
use Zend\Form\Element;
5
use Zend\Form\Fieldset;
6
use Zend\Form\Form;
7
use Zend\InputFilter\Factory as InputFactory;
8
use Zend\ServiceManager\ServiceLocatorInterface;
9
10
class QuizController extends GameController
11
{
12
    /**
13
     *
14
     * @var gameService
15
     */
16
    protected $gameService;
17
18
    public function __construct(ServiceLocatorInterface $locator)
19
    {
20
        parent::__construct($locator);
21
    }
22
23
    public function playAction()
24
    {
25
        // the quiz is done for the first time in this entry
26
        $firstTime = true;
27
        $playError = null;
28
        $entry = $this->getGameService()->play($this->game, $this->user, $playError);
29
        if (!$entry) {
30
            $reason = "";
0 ignored issues
show
Unused Code introduced by
$reason 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...
31
            if ($playError === -1) {
32
                // the user has already taken part to this game and the participation limit has been reached
33
                $this->flashMessenger()->addMessage('Vous avez déjà participé');
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
34
                $reason = '?playLimitReached=1';
35
                $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
36
                    $this->game->getClassType().'/result',
37
                    array(
38
                        'id' => $this->game->getIdentifier(),
39
                    )
40
                ) .$reason;
41
            } elseif ($playError === -2) {
42
                // the user has not accepted the mandatory rules of the game
43
                $this->flashMessenger()->addMessage('Vous devez accepter le réglement');
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
44
                $reason = '?NoOptin=1';
45
                $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
46
                    $this->game->getClassType(),
47
                    array(
48
                        'id' => $this->game->getIdentifier(),
49
                    )
50
                ) .$reason;
51
            } elseif ($playError === -3) {
52
                // the user has enough points to buy an entry to this game
53
                $this->flashMessenger()->addMessage("Vous ne pouvez pas acheter la partie");
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
54
                $reason = '?NotPaid=1';
55
                $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
56
                    $this->game->getClassType(),
57
                    array(
58
                        'id' => $this->game->getIdentifier(),
59
                    )
60
                ) .$reason;
61 View Code Duplication
            } else {
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...
62
                $this->flashMessenger()->addMessage("An error occurred. Please try again later");
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
63
                $reason = '?Error=1';
64
                $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
65
                    $this->game->getClassType(),
66
                    array(
67
                        'id' => $this->game->getIdentifier(),
68
                    )
69
                ) .$reason;
70
            }
71
72
            return $this->redirect()->toUrl($noEntryRedirect);
73
        }
74
75
        $reply = $this->getGameService()->getQuizReplyMapper()->getLastGameReply($entry);
76
        $userAnswers = array();
77
        if ($reply) {
78
            $firstTime = false;
79
            foreach ($reply->getAnswers() as $answer) {
80
                $userAnswers[$answer->getQuestionId()][$answer->getAnswerId()] = true;
81
                $userAnswers[$answer->getQuestionId()]['answer'] = $answer->getAnswer();
82
            }
83
        }
84
85
        $questions = $this->game->getQuestions();
86
        $totalQuestions = count($questions);
87
88
        $form = new Form();
89
90
        $inputFilter = new \Zend\InputFilter\InputFilter();
91
        $factory = new InputFactory();
92
93
        $i = 0;
94
        $j = 0;
95
        $elementData = array();
96
        $explanations = array();
97
        $data = $this->getRequest()->getPost()->toArray();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\Stdlib\RequestInterface as the method getPost() does only exist in the following implementations of said interface: Zend\Http\PhpEnvironment\Request, Zend\Http\Request, Zend\Psr7Bridge\Zend\Request.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
98
        $anticheat = array();
99
100
        foreach ($questions as $q) {
101
            if (($this->game->getQuestionGrouping() > 0 && $i % $this->game->getQuestionGrouping() === 0)
102
                || ($i === 0 && $this->game->getQuestionGrouping() === 0)
103
            ) {
104
                $fieldsetName = 'questionGroup' . ++ $j;
105
                $fieldset = new Fieldset($fieldsetName);
106
            }
107
108
            if ($this->getRequest()->isPost()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\Stdlib\RequestInterface as the method isPost() does only exist in the following implementations of said interface: Zend\Http\PhpEnvironment\Request, Zend\Http\Request, Zend\Psr7Bridge\Zend\Request.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
109
                $jsonData = json_decode($q->getJsonData(), true);
110
                // décalage de 2h avec  UTC
111
                $date = (isset($jsonData['stopdate'])) ? strtotime($jsonData['stopdate']) : false;
112
 
113
                if ($date) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $date of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
114
                    $now = time();
115
                    if ($now > $date) {
116
                        $anticheat[] = $q->getId();
117
                        continue;
118
                    }
119
                }
120
            }
121
122
            $name = 'q' . $q->getId();
123
            $fieldsetFilter = new \Zend\InputFilter\InputFilter();
124
            
125
            if ($q->getType() === 0) {
126
                $element = new Element\Radio($name);
127
                $values = array();
128
                $valuesSortedByPosition = array();
129
                $position = 0;
130
                foreach ($q->getAnswers() as $a) {
131
                    $status = (
132
                        isset($userAnswers[$q->getId()]) &&
133
                        isset($userAnswers[$q->getId()][$a->getId()])
134
                    )? true:false;
135
                    $pos = ($a->getPosition() == 0 && isset($values[$a->getPosition()])) ? $position : $a->getPosition();
136
                    $values[$pos] = array(
137
                        'id' => $a->getId(),
138
                        'position' => $pos,
139
                        'answer' => $a->getAnswer(),
140
                        'checked' => $status
141
                    );
142
                    $explanations[$a->getAnswer()] = $a->getExplanation();
143
                    ++$position;
144
                }
145
                ksort($values);
146
                foreach ($values as $key => $value) {
147
                    $valuesSortedByPosition[$value['id']] = $value['answer'];
148
                    if ($value['checked']) {
149
                        $element->setValue($value['id']);
150
                    }
151
                }
152
                $element->setValueOptions($valuesSortedByPosition);
153
                $element->setLabelOptions(array("disable_html_escape"=>true));
154
                $elementData[$q->getId()] = new Element\Hidden($name.'-data');
155
            } elseif ($q->getType() === 1) {
156
                $element = new Element\MultiCheckbox($name);
157
                $values = array();
158
                $valuesSortedByPosition = array();
159
                foreach ($q->getAnswers() as $a) {
160
                    $values[$a->getId()] = array(
161
                        'id' => $a->getId(),
162
                        'position' => $a->getPosition(),
163
                        'answer' => $a->getAnswer(),
164
                    );
165
                    $explanations[$a->getAnswer()] = $a->getExplanation();
166
                    $elementData[$a->getId()] = new Element\Hidden($name.'-'.$a->getId().'-data');
167
                }
168
169
                foreach ($values as $key => $value) {
170
                    $valuesSortedByPosition[$value['id']] = $value['answer'];
171
                }
172
173
                $element->setValueOptions($valuesSortedByPosition);
174
                $element->setLabelOptions(array("disable_html_escape"=>true));
175
            } elseif ($q->getType() == 2) {
176
                $element = new Element\Textarea($name);
177
                if (isset($userAnswers[$q->getId()])) {
178
                    $element->setValue($userAnswers[$q->getId()]['answer']);
179
                }
180
                $elementData[$q->getId()] = new Element\Hidden($name.'-data');
181
            }
182
183
            $element->setLabel($q->getQuestion());
0 ignored issues
show
Bug introduced by
The variable $element 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...
184
            $fieldset->add($element);
0 ignored issues
show
Bug introduced by
The variable $fieldset 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...
185
            if (is_array($elementData)) {
186
                foreach ($elementData as $id => $e) {
187
                    $fieldset->add($e);
188
                }
189
            } else {
190
                $fieldset->add($elementData);
191
            }
192
193
            $fieldsetFilter->add(
194
                $factory->createInput(
195
                    [
196
                        'name'     => $name,
197
                        'required' => true,
198
                        'validators' => [
199
                            [
200
                                'name' =>'NotEmpty',
201
                                'options' => [
202
                                    'messages' => [
203
                                        'isEmpty' => 'Merci de répondre à la question.',
204
                                    ],
205
                                ],
206
                            ],
207
                        ]
208
                    ]
209
                )
210
            );
211
212
            $i ++;
213
            if (($this->game->getQuestionGrouping() > 0 && $i % $this->game->getQuestionGrouping() == 0 && $i > 0)
214
                || $i == $totalQuestions
215
            ) {
216
                $form->add($fieldset);
217
                $inputFilter->add($fieldsetFilter, $fieldsetName);
0 ignored issues
show
Bug introduced by
The variable $fieldsetName 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...
218
            }
219
        }
220
221
        $form->setInputFilter($inputFilter);
222
223
        if ($this->getRequest()->isPost()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\Stdlib\RequestInterface as the method isPost() does only exist in the following implementations of said interface: Zend\Http\PhpEnvironment\Request, Zend\Http\Request, Zend\Psr7Bridge\Zend\Request.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
224
            foreach ($anticheat as $id) {
225
                $j = 0;
226
                $i = 0;
227
                foreach ($questions as $q) {
228
                    if (($this->game->getQuestionGrouping() > 0 && $i % $this->game->getQuestionGrouping() == 0) || ($i == 0 && $this->game->getQuestionGrouping() == 0)) {
229
                        $fieldsetName = 'questionGroup' . ++ $j;
230
                    }
231
                    if ($q->getId() == $id) {
232
                        unset($data[$fieldsetName]['q'.$q->getId()]);
233
                    }
234
                    $i++;
235
                }
236
            }
237
            $action = $this->params('action');
238
    
239
            // On POST, if the anonymousUser has not been created yet, I try to create it now
240
            // Maybe is there only one form for the quiz and the player data... I try...
241
            // And if the formPlayer data was included in the form, I remove it
242
            if (!$this->user && $this->game->getAnonymousAllowed() && $this->game->getAnonymousIdentifier()) {
243
                $session = new \Zend\Session\Container('anonymous_identifier');
244
                if (empty($session->offsetGet('anonymous_identifier'))) {
245
                    $controller = __NAMESPACE__ . '\\' . ucfirst($this->game->getClassType());
246
                    $registerUser  = $this->forward()->dispatch(
0 ignored issues
show
Unused Code introduced by
$registerUser 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...
247
                        $controller,
248
                        array(
249
                            'action' => 'register',
250
                            'id'     => $this->game->getIdentifier()
251
                        )
252
                    );
253
254
                    foreach ($data as $index => $el) {
255
                        if (! is_array($el)) {
256
                            unset($data[$index]);
257
                        }
258
                    }
259
                    $playError = null;
260
                    $entry = $this->getGameService()->play($this->game, $this->user, $playError);
261 View Code Duplication
                    if (!$entry) {
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...
262
                        $reason = "";
0 ignored issues
show
Unused Code introduced by
$reason 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...
263
                        if ($playError === -1) {
264
                            // the user has already taken part to this game and the participation limit has been reached
265
                            $this->flashMessenger()->addMessage('Vous avez déjà participé');
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
266
                            $reason = '?playLimitReached=1';
267
                            $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
268
                                $this->game->getClassType().'/result',
269
                                array(
270
                                    'id' => $this->game->getIdentifier(),
271
                                )
272
                            ) .$reason;
273
                        } elseif ($playError === -2) {
274
                            // the user has not accepted the mandatory rules of the game
275
                            $this->flashMessenger()->addMessage('Vous devez accepter le réglement');
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
276
                            $reason = '?NoOptin=1';
277
                            $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
278
                                $this->game->getClassType(),
279
                                array(
280
                                    'id' => $this->game->getIdentifier(),
281
                                )
282
                            ) .$reason;
283
                        } elseif ($playError === -3) {
284
                            // the user has enough points to buy an entry to this game
285
                            $this->flashMessenger()->addMessage("Vous ne pouvez pas acheter la partie");
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
286
                            $reason = '?NotPaid=1';
287
                            $noEntryRedirect = $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
288
                                $this->game->getClassType(),
289
                                array(
290
                                    'id' => $this->game->getIdentifier(),
291
                                )
292
                            ) .$reason;
293
                        }
294
295
                        return $this->redirect()->toUrl($noEntryRedirect);
0 ignored issues
show
Bug introduced by
The variable $noEntryRedirect 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...
296
                    }
297
                }
298
            }
299
300
            $form->setData($data);
301
302
            // Improve it : I don't validate the form in a timer quiz as no answer is mandatory
303
            if ($this->game->getTimer() || $form->isValid()) {
304
                unset($data['submitForm']);
305
                $entry = $this->getGameService()->createQuizReply($data, $this->game, $this->user);
0 ignored issues
show
Unused Code introduced by
$entry 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...
306
            }
307
            
308
            return $this->redirect()->toUrl(
309
                $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
310
                    $this->game->getClassType() . '/'. $this->game->nextStep($action),
311
                    array('id' => $this->game->getIdentifier())
312
                )
313
            );
314
        }
315
316
        $viewModel = $this->buildView($this->game);
317
        $viewModel->setVariables(
0 ignored issues
show
Bug introduced by
The method setVariables does only exist in Zend\View\Model\ViewModel, but not in Zend\Http\PhpEnvironment\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
318
            [
319
                'firstTime' => $firstTime,
320
                'questions' => $questions,
321
                'form'      => $form,
322
                'explanations' => $explanations,
323
                'flashMessages' => $this->flashMessenger()->getMessages(),
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
324
            ]
325
        );
326
327
        return $viewModel;
328
    }
329
330
    public function resultAction()
331
    {
332
        $playLimitReached = false;
333
        if ($this->getRequest()->getQuery()->get('playLimitReached')) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\Stdlib\RequestInterface as the method getQuery() does only exist in the following implementations of said interface: Zend\Http\PhpEnvironment\Request, Zend\Http\Request, Zend\Psr7Bridge\Zend\Request.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
334
            $playLimitReached = true;
335
        }
336
        $statusMail = null;
337
        $prediction = false;
338
        $userTimer = array();
339
340
        $lastEntry = $this->getGameService()->findLastEntry($this->game, $this->user);
341
        if (!$lastEntry) {
342
            return $this->redirect()->toUrl(
343
                $this->frontendUrl()->fromRoute(
0 ignored issues
show
Documentation Bug introduced by
The method frontendUrl does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
344
                    'quiz',
345
                    array('id' => $this->game->getIdentifier()),
346
                    array('force_canonical' => true)
347
                )
348
            );
349
        }
350
351
        // je compte les bonnes réponses et le ratio
352
        $maxCorrectAnswers = $this->game->getMaxCorrectAnswers();
353
        $winner = $lastEntry->getWinner();
354
        $reply = $this->getGameService()->getQuizReplyMapper()->getLastGameReply($lastEntry);
355
        $userCorrectAnswers = 0;
356
        $correctAnswers = array();
357
        $userAnswers = array();
358
359
        if ($reply !== null) {
360
            foreach ($reply->getAnswers() as $answer) {
361
                if ($answer->getCorrect()) {
362
                    $correctAnswers[$answer->getQuestionId()][$answer->getAnswerId()] = true;
363
                    ++$userCorrectAnswers;
364
                }
365
                $userAnswers[$answer->getQuestionId()][$answer->getAnswerId()] = true;
366
                $userAnswers[$answer->getQuestionId()]['answer'] = $answer->getAnswer();
367
            }
368
        }
369
370
        $ratioCorrectAnswers = 0;
0 ignored issues
show
Unused Code introduced by
$ratioCorrectAnswers 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...
371
        if ($maxCorrectAnswers > 0) {
372
            $ratioCorrectAnswers = ($userCorrectAnswers / $maxCorrectAnswers) * 100;
373
        } else {
374
            $ratioCorrectAnswers = 100;
375
        }
376
377
        if ($this->game->getTimer()) {
378
            $timer = $this->getGameService()->getEntryMapper()->findOneBy(
379
                array('game' => $this->game, 'user'=> $this->user)
380
            );
381
            $start = $timer->getCreatedAt()->format('U');
382
            $end = $timer->getUpdatedAt()->format('U');
383
            $userTimer = array(
384
               'ratio'  => $ratioCorrectAnswers,
385
               'timer'  => $end - $start,
386
            );
387
        }
388
389
        // The distribution of answers for each question
390
        $distribution = $this->getGameService()->getAnswersDistribution($this->game);
391
392
        // Je prépare le tableau des bonnes réponses trouvées et non trouvées
393
        $ga = array();
394
        $questions = $this->game->getQuestions();
395
        foreach ($questions as $q) {
396
            foreach ($q->getAnswers() as $a) {
397
                if ($a->getCorrect()) {
398
                    $ga[$q->getId()]['question'] = $q;
399
                    $ga[$q->getId()]['answers'][$a->getId()]['answer'] = $a->getAnswer();
400
                    $ga[$q->getId()]['answers'][$a->getId()]['explanation'] = $a->getExplanation();
401
                    $ga[$q->getId()]['answers'][$a->getId()]['userAnswer'] = isset($userAnswers[$q->getId()]) ?
402
                        $userAnswers[$q->getId()]['answer'] :
403
                        false;
404
405 View Code Duplication
                    if (isset($correctAnswers[$q->getId()]) && isset($correctAnswers[$q->getId()][$a->getId()])) {
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...
406
                        $ga[$q->getId()]['answers'][$a->getId()]['found'] = true;
407
                    } else {
408
                        $ga[$q->getId()]['answers'][$a->getId()]['found'] = false;
409
                    }
410
                    
411 View Code Duplication
                    if (isset($userAnswers[$q->getId()]) && isset($userAnswers[$q->getId()][$a->getId()])) {
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...
412
                        $ga[$q->getId()]['answers'][$a->getId()]['yourChoice'] = true;
413
                    } else {
414
                        $ga[$q->getId()]['answers'][$a->getId()]['yourChoice'] = false;
415
                    }
416
417
                    $ga[$q->getId()]['answers'][$a->getId()]['correctAnswers'] = true;
418
                } else {
419
                    $ga[$q->getId()]['question'] = $q;
420
                    $ga[$q->getId()]['answers'][$a->getId()]['answer'] = $a->getAnswer();
421
                    $ga[$q->getId()]['answers'][$a->getId()]['explanation'] = $a->getExplanation();
422
                    $ga[$q->getId()]['answers'][$a->getId()]['correctAnswers'] = false;
423
                    $ga[$q->getId()]['answers'][$a->getId()]['userAnswer'] = isset($userAnswers[$q->getId()]) ?
424
                        $userAnswers[$q->getId()]['answer'] :
425
                        false;
426
                    
427 View Code Duplication
                    if (isset($userAnswers[$q->getId()]) && isset($userAnswers[$q->getId()][$a->getId()])) {
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...
428
                        $ga[$q->getId()]['answers'][$a->getId()]['yourChoice'] = true;
429
                    } else {
430
                        $ga[$q->getId()]['answers'][$a->getId()]['yourChoice'] = false;
431
                    }
432
                }
433
            }
434
            // if only one question is a prediction, we can't determine if it's a winner or looser
435
            if ($q->getPrediction()) {
436
                $prediction = true;
437
            }
438
        }
439
440
        $form = $this->getServiceLocator()->get('playgroundgame_sharemail_form');
441
        $form->setAttribute('method', 'post');
442
443
        $viewModel = $this->buildView($this->game);
444
        
445
        // TODO: Change the way we know if the play step has been rejected
446
        $messages = $this->flashMessenger()->getMessages();
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
447
        if (!isset($messages[0]) || substr($messages[0], 0, 9) != 'Vous avez') {
448
            $this->getGameService()->sendMail($this->game, $this->user, $lastEntry);
449
        }
450
451
        $viewModel->setVariables(
0 ignored issues
show
Bug introduced by
The method setVariables does only exist in Zend\View\Model\ViewModel, but not in Zend\Http\PhpEnvironment\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
452
            [
453
                'entry'               => $lastEntry,
454
                'statusMail'          => $statusMail,
455
                'form'                => $form,
456
                'winner'              => $winner,
457
                'prediction'          => $prediction,
458
                'userCorrectAnswers'  => $userCorrectAnswers,
459
                'maxCorrectAnswers'   => $maxCorrectAnswers,
460
                'ratioCorrectAnswers' => $ratioCorrectAnswers,
461
                'gameCorrectAnswers'  => $ga,
462
                'userTimer'           => $userTimer,
463
                'userAnswers'         => $userAnswers,
464
                'flashMessages'       => $this->flashMessenger()->getMessages(),
0 ignored issues
show
Documentation Bug introduced by
The method flashMessenger does not exist on object<PlaygroundGame\Co...rontend\QuizController>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
465
                'playLimitReached'    => $playLimitReached,
466
                'distribution'        => $distribution,
467
            ]
468
        );
469
470
        return $viewModel;
471
    }
472
473 View Code Duplication
    public function fbshareAction()
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...
474
    {
475
        $result = parent::fbshareAction();
476
        $bonusEntry = false;
477
478
        if ($result->getVariable('success')) {
479
            // Improve this thing
480
            $lastEntry = $this->getGameService()->findLastInactiveEntry($this->game, $this->user);
481
            if ($lastEntry && $lastEntry->getWinner()) {
482
                $bonusEntry = $this->getGameService()->addAnotherChance($this->game, $this->user, 1);
483
            }
484
        }
485
486
        $response = $this->getResponse();
487
        $response->setContent(\Zend\Json\Json::encode(array(
488
                'success' => $result,
489
                'playBonus' => $bonusEntry
490
        )));
491
492
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $response; (Zend\Stdlib\ResponseInterface) is incompatible with the return type of the parent method PlaygroundGame\Controlle...ntroller::fbshareAction of type Zend\View\Model\JsonModel.

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...
493
    }
494
495 View Code Duplication
    public function fbrequestAction()
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...
496
    {
497
        $result = parent::fbrequestAction();
498
        $bonusEntry = false;
499
500
        if ($result->getVariable('success')) {
501
            $lastEntry = $this->getGameService()->findLastInactiveEntry($this->game, $this->user);
502
            if ($lastEntry && $lastEntry->getWinner()) {
503
                $bonusEntry = $this->getGameService()->addAnotherChance($this->game, $this->user, 1);
504
            }
505
        }
506
507
        $response = $this->getResponse();
508
        $response->setContent(\Zend\Json\Json::encode(array(
509
            'success' => $result,
510
            'playBonus' => $bonusEntry
511
        )));
512
513
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $response; (Zend\Stdlib\ResponseInterface) is incompatible with the return type of the parent method PlaygroundGame\Controlle...roller::fbrequestAction of type Zend\View\Model\JsonModel.

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...
514
    }
515
516 View Code Duplication
    public function tweetAction()
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...
517
    {
518
        $result = parent::tweetAction();
519
        $bonusEntry = false;
520
521
        if ($result->getVariable('success')) {
522
            $lastEntry = $this->getGameService()->findLastInactiveEntry($this->game, $this->user);
523
            if ($lastEntry && $lastEntry->getWinner()) {
524
                $bonusEntry = $this->getGameService()->addAnotherChance($this->game, $this->user, 1);
525
            }
526
        }
527
528
        $response = $this->getResponse();
529
        $response->setContent(\Zend\Json\Json::encode(array(
530
            'success' => $result,
531
            'playBonus' => $bonusEntry
532
        )));
533
534
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $response; (Zend\Stdlib\ResponseInterface) is incompatible with the return type of the parent method PlaygroundGame\Controlle...Controller::tweetAction of type Zend\View\Model\JsonModel.

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...
535
    }
536
537 View Code Duplication
    public function googleAction()
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...
538
    {
539
        $result = parent::googleAction();
540
        $bonusEntry = false;
541
542
        if ($result->getVariable('success')) {
543
            $lastEntry = $this->getGameService()->findLastInactiveEntry($this->game, $this->user);
544
            if ($lastEntry && $lastEntry->getWinner()) {
545
                $bonusEntry = $this->getGameService()->addAnotherChance($this->game, $this->user, 1);
546
            }
547
        }
548
549
        $response = $this->getResponse();
550
        $response->setContent(\Zend\Json\Json::encode(array(
551
            'success' => $result,
552
            'playBonus' => $bonusEntry
553
        )));
554
555
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $response; (Zend\Stdlib\ResponseInterface) is incompatible with the return type of the parent method PlaygroundGame\Controlle...ontroller::googleAction of type Zend\View\Model\JsonModel.

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...
556
    }
557
558
    public function getGameService()
559
    {
560
        if (! $this->gameService) {
561
            $this->gameService = $this->getServiceLocator()->get('playgroundgame_quiz_service');
562
        }
563
564
        return $this->gameService;
565
    }
566
}
567