Completed
Pull Request — master (#249)
by greg
04:18
created

GameController::downloadAction()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 32
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 3 Features 0
Metric Value
c 6
b 3
f 0
dl 0
loc 32
rs 8.8571
cc 2
eloc 22
nc 2
nop 0
1
<?php
2
3
namespace PlaygroundGame\Controller\Admin;
4
5
use PlaygroundGame\Service\Game as AdminGameService;
6
use Zend\Mvc\Controller\AbstractActionController;
7
use PlaygroundGame\Options\ModuleOptions;
8
use Zend\Paginator\Paginator;
9
use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator as DoctrineAdapter;
10
use PlaygroundCore\ORM\Pagination\LargeTablePaginator;
11
use Doctrine\ORM\Tools\Pagination\Paginator as ORMPaginator;
12
use Zend\Stdlib\ErrorHandler;
13
14
class GameController extends AbstractActionController
15
{
16
    protected $options;
17
18
    /**
19
     * @var GameService
20
     */
21
    protected $adminGameService;
22
23
    public function listAction()
24
    {
25
        $filter    = $this->getEvent()->getRouteMatch()->getParam('filter');
26
        $type    = $this->getEvent()->getRouteMatch()->getParam('type');
27
28
        $service    = $this->getAdminGameService();
29
        $adapter = new DoctrineAdapter(new ORMPaginator($service->getQueryGamesOrderBy($type, $filter)));
30
        $paginator = new Paginator($adapter);
31
        $paginator->setItemCountPerPage(25);
32
        $paginator->setCurrentPageNumber($this->getEvent()->getRouteMatch()->getParam('p'));
33
34
        foreach ($paginator as $game) {
35
            $game->entry = $service->getEntryMapper()->countByGame($game);
36
        }
37
38
        return array(
39
            'games'    => $paginator,
40
            'type'        => $type,
41
            'filter'    => $filter,
42
        );
43
    }
44
45
    public function entryAction()
46
    {
47
        $gameId         = $this->getEvent()->getRouteMatch()->getParam('gameId');
48
        if (!$gameId) {
49
            return $this->redirect()->toRoute('admin/playgroundgame/list');
50
        }
51
52
        $game = $this->getAdminGameService()->getGameMapper()->findById($gameId);
53
        $header = $this->getAdminGameService()->getEntriesHeader($game);
0 ignored issues
show
Unused Code introduced by
$header 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...
54
55
        $adapter = new DoctrineAdapter(
56
            new LargeTablePaginator(
57
                $this->getAdminGameService()->getEntriesQuery($game)
58
            )
59
        );
60
        $paginator = new Paginator($adapter);
61
        $paginator->setItemCountPerPage(10);
62
        $paginator->setCurrentPageNumber($this->getEvent()->getRouteMatch()->getParam('p'));
63
64
        $header = $this->getAdminGameService()->getEntriesHeader($game);
65
        $entries = $this->getAdminGameService()->getGameEntries($header, $paginator, $game);
66
67
        return array(
68
            'paginator' => $paginator,
69
            'entries' => $entries,
70
            'header' => $header,
71
            'game' => $game,
72
            'gameId' => $gameId
73
        );
74
    }
75
76
    public function downloadAction()
77
    {
78
        $gameId = $this->getEvent()->getRouteMatch()->getParam('gameId');
79
        if (!$gameId) {
80
            return $this->redirect()->toRoute('admin/playgroundgame/list');
81
        }
82
83
        $game = $this->getAdminGameService()->getGameMapper()->findById($gameId);
84
        $header = $this->getAdminGameService()->getEntriesHeader($game);
85
        $query = $this->getAdminGameService()->getEntriesQuery($game);
86
87
        $content = "\xEF\xBB\xBF"; // UTF-8 BOM
88
        $content .= $this->getAdminGameService()->getCSV(
89
            $this->getAdminGameService()->getGameEntries(
90
                $header,
91
                $query->getResult(),
92
                $game
93
            )
94
        );
95
96
        $response = $this->getResponse();
97
        $headers = $response->getHeaders();
98
        $headers->addHeaderLine('Content-Encoding: UTF-8');
99
        $headers->addHeaderLine('Content-Type', 'text/csv; charset=UTF-8');
100
        $headers->addHeaderLine('Content-Disposition', "attachment; filename=\"entry.csv\"");
101
        $headers->addHeaderLine('Accept-Ranges', 'bytes');
102
        $headers->addHeaderLine('Content-Length', strlen($content));
103
104
        $response->setContent($content);
105
106
        return $response;
107
    }
108
109
    // Only used for Quiz and Lottery
110
    public function drawAction()
111
    {
112
        // magically create $content as a string containing CSV data
113
        $gameId         = $this->getEvent()->getRouteMatch()->getParam('gameId');
114
        if (!$gameId) {
115
            return $this->redirect()->toRoute('admin/playgroundgame/list');
116
        }
117
        $game           = $this->getAdminGameService()->getGameMapper()->findById($gameId);
118
119
        $winningEntries = $this->getAdminGameService()->draw($game);
120
121
        $content        = "\xEF\xBB\xBF"; // UTF-8 BOM
122
        $content       .= "ID;Pseudo;Nom;Prenom;E-mail;Etat\n";
123
124
        foreach ($winningEntries as $e) {
125
            $etat = 'gagnant';
126
127
            $content   .= $e->getUser()->getId()
128
            . ";" . $e->getUser()->getUsername()
129
            . ";" . $e->getUser()->getLastname()
130
            . ";" . $e->getUser()->getFirstname()
131
            . ";" . $e->getUser()->getEmail()
132
            . ";" . $etat
133
            ."\n";
134
        }
135
136
        $response = $this->getResponse();
137
        $headers = $response->getHeaders();
138
        $headers->addHeaderLine('Content-Encoding: UTF-8');
139
        $headers->addHeaderLine('Content-Type', 'text/csv; charset=UTF-8');
140
        $headers->addHeaderLine('Content-Disposition', "attachment; filename=\"gagnants.csv\"");
141
        $headers->addHeaderLine('Accept-Ranges', 'bytes');
142
        $headers->addHeaderLine('Content-Length', strlen($content));
143
144
        $response->setContent($content);
145
146
        return $response;
147
    }
148
    
149
    /**
150
     * This method serialize a game an export it as a txt file
151
     * @return \Zend\Stdlib\ResponseInterface
152
     */
153
    public function exportAction()
154
    {
155
        // magically create $content as a string containing CSV data
156
        $gameId  = $this->getEvent()->getRouteMatch()->getParam('gameId');
157
        $game    = $this->getAdminGameService()->getGameMapper()->findById($gameId);
158
        $content = serialize($game);
159
160
        $response = $this->getResponse();
161
        $headers = $response->getHeaders();
162
        $headers->addHeaderLine('Content-Encoding: UTF-8');
163
        $headers->addHeaderLine('Content-Type', 'text/plain; charset=UTF-8');
164
        $headers->addHeaderLine('Content-Disposition', "attachment; filename=\"". $game->getIdentifier() .".txt\"");
165
        $headers->addHeaderLine('Accept-Ranges', 'bytes');
166
        $headers->addHeaderLine('Content-Length', strlen($content));
167
    
168
        $response->setContent($content);
169
    
170
        return $response;
171
    }
172
    
173
    /**
174
     * This method take an uploaded txt file containing a serialized game
175
     * and persist it in the database
176
     * @return unknown
177
     */
178
    public function importAction()
179
    {
180
        $form = $this->getServiceLocator()->get('playgroundgame_import_form');
181
        $form->setAttribute('action', $this->url()->fromRoute('admin/playgroundgame/import'));
182
        $form->setAttribute('method', 'post');
183
        
184
        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.

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...
185
            $data = array_replace_recursive(
186
                $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.

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...
187
                $this->getRequest()->getFiles()->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 getFiles() does only exist in the following implementations of said interface: Zend\Http\PhpEnvironment\Request, Zend\Http\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...
188
            );
189
            
190
            if (! empty($data['import_file']['tmp_name'])) {
191
                ErrorHandler::start();
192
                $game = unserialize(file_get_contents($data['import_file']['tmp_name']));
193
                ErrorHandler::stop(true);
194
            }
195
            $game->setId(null);
0 ignored issues
show
Bug introduced by
The variable $game 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...
196
            if ($data['slug']) {
197
                $game->setIdentifier($data['slug']);
198
            }
199
            
200
            $duplicate = $this->getAdminGameService()->getGameMapper()->findByIdentifier($game->getIdentifier());
201
            if (!$duplicate) {
202
                $this->getAdminGameService()->getGameMapper()->insert($game);
203
                return $this->redirect()->toRoute('admin/playgroundgame/list');
204
            }
205
        }
206
        
207
        return array(
208
            'form' => $form,
209
        );
210
    }
211
212
    public function removeAction()
213
    {
214
        $service = $this->getAdminGameService();
215
        $gameId = $this->getEvent()->getRouteMatch()->getParam('gameId');
216
        if (!$gameId) {
217
            return $this->redirect()->toRoute('admin/playgroundgame/list');
218
        }
219
220
        $game = $service->getGameMapper()->findById($gameId);
221
        if ($game) {
222
            try {
223
                $service->getGameMapper()->remove($game);
224
                $this->flashMessenger()->setNamespace('playgroundgame')->addMessage('The game has been edited');
225
            } catch (\Doctrine\DBAL\DBALException $e) {
226
                $this->flashMessenger()->setNamespace('playgroundgame')->addMessage(
227
                    'Il y a déjà eu des participants à ce jeu. Vous ne pouvez plus le supprimer'
228
                );
229
            }
230
        }
231
232
        return $this->redirect()->toRoute('admin/playgroundgame/list');
233
    }
234
235
    public function setActiveAction()
236
    {
237
        $service = $this->getAdminGameService();
238
        $gameId = (int)$this->getEvent()->getRouteMatch()->getParam('gameId');
239
        if (!$gameId) {
240
            return $this->redirect()->toRoute('admin/playgroundgame/list');
241
        }
242
243
        $game = $service->getGameMapper()->findById($gameId);
244
        $game->setActive(!$game->getActive());
245
        $service->getGameMapper()->update($game);
246
247
        return $this->redirect()->toRoute('admin/playgroundgame/list');
248
    }
249
250
    public function formAction()
251
    {
252
        $service = $this->getAdminGameService();
253
        $gameId = $this->getEvent()->getRouteMatch()->getParam('gameId');
254
        if (!$gameId) {
255
            return $this->redirect()->toRoute('admin/playgroundgame/list');
256
        }
257
        $game = $service->getGameMapper()->findById($gameId);
258
        $form = $service->getPlayerFormMapper()->findOneBy(array('game' => $game));
259
260
        // I use the wonderful Form Generator to create the Post & Vote form
261
        $this->forward()->dispatch(
262
            'PlaygroundCore\Controller\Formgen',
263
            array(
264
                'controller' => 'PlaygroundCore\Controller\Formgen',
265
                'action' => 'create'
266
            )
267
        );
268
269
        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.

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...
270
            $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.

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...
271
            $form = $service->createForm($data, $game, $form);
272
            if ($form) {
273
                $this->flashMessenger()->setNamespace('playgroundgame')->addMessage('The form was created');
274
            }
275
        }
276
        $formTemplate='';
277
        if ($form) {
278
            $formTemplate = $form->getFormTemplate();
279
        }
280
281
        return array(
282
            'form' => $form,
283
            'formTemplate' => $formTemplate,
284
            'gameId' => $gameId,
285
            'game' => $game,
286
        );
287
    }
288
289
    public function setOptions(ModuleOptions $options)
290
    {
291
        $this->options = $options;
292
293
        return $this;
294
    }
295
296
    public function getOptions()
297
    {
298
        if (!$this->options instanceof ModuleOptions) {
299
            $this->setOptions($this->getServiceLocator()->get('playgroundgame_module_options'));
0 ignored issues
show
Documentation introduced by
$this->getServiceLocator...ndgame_module_options') is of type object|array, but the function expects a object<PlaygroundGame\Options\ModuleOptions>.

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...
300
        }
301
302
        return $this->options;
303
    }
304
305
    public function getAdminGameService()
306
    {
307
        if (!$this->adminGameService) {
308
            $this->adminGameService = $this->getServiceLocator()->get('playgroundgame_game_service');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceLocator...oundgame_game_service') can also be of type array. However, the property $adminGameService is declared as type object<PlaygroundGame\Co...ller\Admin\GameService>. 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...
309
        }
310
311
        return $this->adminGameService;
312
    }
313
314
    public function setAdminGameService(AdminGameService $adminGameService)
315
    {
316
        $this->adminGameService = $adminGameService;
0 ignored issues
show
Documentation Bug introduced by
It seems like $adminGameService of type object<PlaygroundGame\Service\Game> is incompatible with the declared type object<PlaygroundGame\Co...ller\Admin\GameService> of property $adminGameService.

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...
317
318
        return $this;
319
    }
320
}
321