Completed
Pull Request — master (#264)
by greg
02:58
created

InstantWin::getGameEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace PlaygroundGame\Service;
4
5
use Zend\ServiceManager\ServiceManagerAwareInterface;
6
use Zend\Stdlib\ErrorHandler;
7
8
class InstantWin extends Game implements ServiceManagerAwareInterface
9
{
10
    /**
11
     * @var InstantWinOccurrenceMapperInterface
12
     */
13
    protected $instantWinOccurrenceMapper;
14
15
    protected $prizeMapper;
16
17
    /**
18
     *
19
     * saving an instantwin image if any
20
     *
21
     * @param  array                  $data
22
     * @param  string                 $entity
23
     * @param  string                 $formClass
24
     * @return \PlaygroundGame\Entity\Game
25
     */
26
    public function create(array $data, $entity, $formClass)
27
    {
28
        $game = parent::create($data, $entity, $formClass);
0 ignored issues
show
Bug introduced by
The method create() does not exist on PlaygroundGame\Service\Game. Did you maybe mean createOrUpdate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
29
        if ($game) {
30
            if (!empty($data['uploadScratchcardImage']['tmp_name'])) {
31
                $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
32
                $media_url = $this->getOptions()->getMediaUrl() . '/';
33
34
                ErrorHandler::start();
35
                $data['uploadScratchcardImage']['name'] = $this->fileNewname(
36
                    $path,
37
                    $game->getId() . "-" . $data['uploadScratchcardImage']['name']
38
                );
39
                move_uploaded_file(
40
                    $data['uploadScratchcardImage']['tmp_name'],
41
                    $path . $data['uploadScratchcardImage']['name']
42
                );
43
                $game->setScratchcardImage($media_url . $data['uploadScratchcardImage']['name']);
44
                ErrorHandler::stop(true);
45
46
                $game = $this->getGameMapper()->update($game);
47
            }
48
49
            if ($game->getOccurrenceNumber() && $game->getScheduleOccurrenceAuto()) {
50
                $this->scheduleOccurrences($game, $data);
51
            }
52
        }
53
54
        return $game;
55
    }
56
57
    /**
58
     *
59
     * saving an instantwin image if any
60
     *
61
     * @param  array                  $data
62
     * @param  string                 $formClass
63
     * @return \PlaygroundGame\Entity\Game
64
     */
65
    public function edit(array $data, $game, $formClass)
66
    {
67
        $game = parent::edit($data, $game, $formClass);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PlaygroundGame\Service\Game as the method edit() does only exist in the following sub-classes of PlaygroundGame\Service\Game: PlaygroundGame\Service\InstantWin. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
68
69
        if ($game) {
70
            $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
71
            $media_url = $this->getOptions()->getMediaUrl() . '/';
72
73
            if (!empty($data['uploadScratchcardImage']['tmp_name'])) {
74
                ErrorHandler::start();
75
                $data['uploadScratchcardImage']['name'] = $this->fileNewname(
76
                    $path,
77
                    $game->getId() . "-" . $data['uploadScratchcardImage']['name']
78
                );
79
                move_uploaded_file(
80
                    $data['uploadScratchcardImage']['tmp_name'],
81
                    $path . $data['uploadScratchcardImage']['name']
82
                );
83
                $game->setScratchcardImage($media_url . $data['uploadScratchcardImage']['name']);
84
                ErrorHandler::stop(true);
85
86
                $game = $this->getGameMapper()->update($game);
87
            }
88
89 View Code Duplication
            if (isset($data['deleteScratchcardImage']) &&
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...
90
                $data['deleteScratchcardImage'] &&
91
                empty($data['uploadScratchcardImage']['tmp_name'])
92
            ) {
93
                ErrorHandler::start();
94
                $image = $game->getScratchcardImage();
95
                $image = str_replace($media_url, '', $image);
96
                unlink($path .$image);
97
                $game->setScratchcardImage(null);
98
                ErrorHandler::stop(true);
99
            }
100
101
            if ($game->getOccurrenceNumber() && $game->getScheduleOccurrenceAuto()) {
102
                $this->scheduleOccurrences($game, $data);
103
            }
104
        }
105
106
        return $game;
107
    }
108
109
    /**
110
     * We can create Instant win occurrences dynamically
111
     *
112
     *
113
     * @param  array                  $data
114
     * @return boolean|null
115
     */
116
    public function scheduleOccurrences($game, array $data)
117
    {
118
        // It will be quite long to create these occurrences !
119
        set_time_limit(0);
120
        if ($game->getOccurrenceType() === 'code') {
121
            return $this->scheduleCodeOccurrences($game, $data);
122
        } elseif ($game->getOccurrenceType() === 'datetime') {
123
            return $this->scheduleDateOccurrences($game);
124
        }
125
    }
126
127
    public function scheduleCodeOccurrences($game, $data)
128
    {
129
        $available_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-';
130
        $last_character_index = strlen($available_characters)-1;
131
        if (!$game->getWinningOccurrenceNumber()) {
132
            $game->setWinningOccurrenceNumber($game->getOccurrenceNumber());
133
        }
134
        if (empty($data['occurrenceValueSize'])) {
135
            $data['occurrenceValueSize'] = 8;
136
        }
137
        $created = 0;
138
        $numOccurrences = $game->getOccurrenceNumber();
139
        
140
        for ($i=0; $i < $numOccurrences; $i++) {
141
            $code = '';
142
            while (strlen($code)<$data['occurrenceValueSize']) {
143
                $code .= $available_characters[rand(0, $last_character_index)];
144
            }
145
            $occurrence = new \PlaygroundGame\Entity\InstantWinOccurrence();
146
            $occurrence->setInstantwin($game);
147
            $occurrence->setValue($code);
148
            $occurrence->setActive(1);
149
            $occurrence->setWinning($created < $game->getWinningOccurrenceNumber());
150
            if ($this->getInstantWinOccurrenceMapper()->insert($occurrence)) {
151
                $created++;
152
            }
153
        }
154
        return true;
155
    }
156
157
    public function createRandomOccurrences($game, $beginning, $end, $quantity)
158
    {
159
        for ($i=1; $i<=$quantity; $i++) {
160
            $randomDate = $this->getRandomDate($beginning->format('U'), $end->format('U'));
161
            $randomDate = \DateTime::createFromFormat('Y-m-d H:i:s', $randomDate);
162
            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
163
            $occurrence->setInstantwin($game);
164
            $occurrence->setValue($randomDate->format('Y-m-d H:i:s'));
165
            $occurrence->setActive(1);
166
167
            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
168
        }
169
    }
170
171
    public function scheduleDateOccurrences($game)
172
    {
173
        $f = $game->getOccurrenceDrawFrequency();
174
        $today    = new \DateTime("now");
175
        $end      = new \DateTime("now");
176
        $interval = 'P10D';
177
        if ($game->getStartDate() && $game->getStartDate() > $today) {
178
            $beginning = $game->getStartDate();
179
        } else {
180
            $beginning = $today;
181
        }
182
183
        if ($game->getEndDate()) {
184
            $end = $game->getEndDate();
185
        } else {
186
            $end->add(new \DateInterval($interval));
187
        }
188
189
        // Summertimes timezone management
190
        $timezone = $today->getTimezone();
191
        $transitions = $timezone->getTransitions($beginning->getTimestamp(), $end->getTimestamp());
192
193
        // There is a time transition between these datetimes()
194
        if (count($transitions) == 2) {
195
            $shift = $transitions[0]['offset'] - $transitions[1]['offset'];
196
            if ($shift > 0) {
197
                $end->sub(new \DateInterval('PT'.abs($shift).'S'));
198
            } else {
199
                $end->add(new \DateInterval('PT'.abs($shift).'S'));
200
            }
201
        }
202
203
        // DateInterval takes the day @ 00:00 to calculate the difference between the dates, so 1 day is always missing
204
        // as we consider the last day @ 23:59:59 in Playground :)
205
        if ($end->format('His') == 0) {
206
            $end->add(new \DateInterval('P1D'));
207
        }
208
209
        $dateInterval = (int)(($end->getTimestamp() - $beginning->getTimestamp())/60);
210
211
        // Je recherche tous les IG non gagnés
212
        $occurrences = $this->getInstantWinOccurrenceMapper()->findBy(array('instantwin' => $game));
213
        $nbExistingOccurrences = count($occurrences);
214
        $nbOccurencesToCreate = 0;
215
216
        switch ($f) {
217
            case null:
218
            case 'game':
219
                $nbOccurencesToCreate = $game->getOccurrenceNumber() - $nbExistingOccurrences;
220
                if ($nbOccurencesToCreate > 0) {
221
                    $this->createRandomOccurrences($game, $beginning, $end, $nbOccurencesToCreate);
222
                }
223
224
                break;
225 View Code Duplication
            case 'hour':
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...
226
                $nbInterval = (int) ($dateInterval/60);
227
228
                // If a hour don't last 60min, I consider it as a hour anyway.
229
                if ($dateInterval%60 > 0) {
230
                    ++$nbInterval;
231
                }
232
                if ($nbInterval > 0) {
233
                    $nbOccurencesToCreate = $game->getOccurrenceNumber() - floor($nbExistingOccurrences/$nbInterval);
234
                }
235
236
                $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y H:i:s'));
237
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y H'). ':59:59');
238
                
239
                if ($nbOccurencesToCreate > 0) {
240
                    for ($d=1; $d<=$nbInterval; $d++) {
241
                        $this->createRandomOccurrences(
242
                            $game,
243
                            $beginningDrawDate,
244
                            $endDrawDate,
245
                            $nbOccurencesToCreate
246
                        );
247
                        $beginningDrawDate = \DateTime::createFromFormat(
248
                            'm/d/Y H:i:s',
249
                            $beginningDrawDate->format('m/d/Y H'). ':00:00'
250
                        );
251
                        $beginningDrawDate->add(new \DateInterval('PT1H'));
252
                        $endDrawDate->add(new \DateInterval('PT1H'));
253
                    }
254
                }
255
256
                break;
257 View Code Duplication
            case 'day':
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...
258
                $nbInterval = (int) ($dateInterval/(60*24));
259
260
                // Prise en compte des changements d'horaires
261
                // If a day don't last 24h, I consider it as a day anyway
262
263
                if ($dateInterval%(60*24) > 0) {
264
                    ++$nbInterval;
265
                }
266
267
                if ($nbInterval > 0) {
268
                    $nbOccurencesToCreate = $game->getOccurrenceNumber() - floor($nbExistingOccurrences/$nbInterval);
269
                }
270
271
                $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y H:i:s'));
272
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 23:59:59');
273
                
274
                if ($nbOccurencesToCreate > 0) {
275
                    for ($d=1; $d<=$nbInterval; $d++) {
276
                        $this->createRandomOccurrences(
277
                            $game,
278
                            $beginningDrawDate,
279
                            $endDrawDate,
280
                            $nbOccurencesToCreate
281
                        );
282
                        // As the first beginning date was not @ midnight,
283
                        // I recreate the beginning date
284
                        $beginningDrawDate = \DateTime::createFromFormat(
285
                            'm/d/Y H:i:s',
286
                            $beginningDrawDate->format('m/d/Y'). ' 00:00:00'
287
                        );
288
                        $beginningDrawDate->add(new \DateInterval('P1D'));
289
                        $endDrawDate->add(new \DateInterval('P1D'));
290
                    }
291
                }
292
293
                break;
294 View Code Duplication
            case 'week':
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...
295
                $nbOccurencesToCreate = $game->getOccurrenceNumber() - $nbExistingOccurrences;
296
                $nbWeeksInterval = (int) ($dateInterval/(60*24*7));
297
                // If a week don't last 7d, I consider it as a week anyway.
298
                if ($dateInterval%(60*24*7) > 0) {
299
                    ++$nbWeeksInterval;
300
                }
301
                $beginningDrawDate = \DateTime::createFromFormat(
302
                    'm/d/Y H:i:s',
303
                    $beginning->format('m/d/Y'). ' 00:00:00'
304
                );
305
                $endDrawDate = \DateTime::createFromFormat(
306
                    'm/d/Y H:i:s',
307
                    $beginning->format('m/d/Y'). ' 23:59:59'
308
                );
309
                $endDrawDate->add(new \DateInterval('P6D'));
310
                if ($endDrawDate > $end) {
311
                    $endDrawDate = $end;
312
                }
313
314
                if ($nbOccurencesToCreate > 0) {
315
                    for ($d=1; $d<=$nbWeeksInterval; $d++) {
316
                        $this->createRandomOccurrences(
317
                            $game,
318
                            $beginningDrawDate,
319
                            $endDrawDate,
320
                            $nbOccurencesToCreate
321
                        );
322
                        $beginningDrawDate->add(new \DateInterval('P1W'));
323
                        $endDrawDate->add(new \DateInterval('P1W'));
324
                        if ($endDrawDate > $end) {
325
                            $endDrawDate = $end;
326
                        }
327
                    }
328
                }
329
330
                break;
331 View Code Duplication
            case 'month':
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...
332
                $nbOccurencesToCreate = $game->getOccurrenceNumber() - $nbExistingOccurrences;
333
                $nbMonthsInterval = (int) ($dateInterval/(60*24*30));
334
                // If a week don't last 30d, I consider it as a month anyway.
335
                if ($dateInterval%(60*24*30) > 0) {
336
                    ++$nbMonthsInterval;
337
                }
338
                $beginningDrawDate = \DateTime::createFromFormat(
339
                    'm/d/Y H:i:s',
340
                    $beginning->format('m/d/Y'). ' 00:00:00'
341
                );
342
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 23:59:59');
343
                $endDrawDate->add(new \DateInterval('P1M'));
344
                $endDrawDate->sub(new \DateInterval('P1D'));
345
                if ($endDrawDate > $end) {
346
                    $endDrawDate = $end;
347
                }
348
349
                if ($nbOccurencesToCreate > 0) {
350
                    for ($d=1; $d<=$nbMonthsInterval; $d++) {
351
                        $this->createRandomOccurrences(
352
                            $game,
353
                            $beginningDrawDate,
354
                            $endDrawDate,
355
                            $nbOccurencesToCreate
356
                        );
357
                        $beginningDrawDate->add(new \DateInterval('P1M'));
358
                        $endDrawDate->add(new \DateInterval('P1M'));
359
                        if ($endDrawDate > $end) {
360
                            $endDrawDate = $end;
361
                        }
362
                    }
363
                }
364
365
                break;
366
        }
367
368
        return true;
369
    }
370
371
    public function getRandomDate($min_date, $max_date)
372
    {
373
        $rand_epoch = rand($min_date, $max_date);
374
375
        return date('Y-m-d H:i:s', $rand_epoch);
376
    }
377
378
    /**
379
     * @param string $fileName
380
     */
381
    public function getOccurencesFromCSV($fileName)
382
    {
383
        if (file_exists($fileName)) {
384
            $csvFile = fopen($fileName, 'r');
385
            if ($csvFile) {
386
                while (!feof($csvFile)) {
387
                    $csvContent[] = fgetcsv($csvFile);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$csvContent was never initialized. Although not strictly required by PHP, it is generally a good practice to add $csvContent = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
388
                }
389
                fclose($csvFile);
390
                return $csvContent;
0 ignored issues
show
Bug introduced by
The variable $csvContent 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...
391
            }
392
        }
393
        return false;
394
    }
395
396
    public function setOccurencesToCSV($game)
397
    {
398
        $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
399
        $fileName = $path.'occurences-'.$game->getId().'.csv';
400
        $csvFile = fopen($fileName, 'w');
401
        if ($csvFile) {
402
            $occurrences = $this->getInstantWinOccurrenceMapper()->findByGameId($game);
403
            foreach ($occurrences as $occurrence) {
404
                fputcsv($csvFile, array($occurrence->getValue(), $occurrence->getWinning()));
405
            }
406
            fclose($csvFile);
407
            return $fileName;
408
        }
409
        return false;
410
    }
411
412
    public function importOccurrences($data)
413
    {
414
        if (!empty($data['file']['tmp_name'])) {
415
            $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
416
            $real_media_path = realpath($path) . DIRECTORY_SEPARATOR;
417
418
            // upload the csv file
419
            ErrorHandler::start();
420
            $data['file']['name'] = $this->fileNewname($path, $data['instant_win_id'] . "-" . $data['file']['name']);
421
            move_uploaded_file($data['file']['tmp_name'], $path . $data['file']['name']);
422
            ErrorHandler::stop(true);
423
            $csv_content = $this->getOccurencesFromCSV($real_media_path.$data['file']['name']);
424
            if ($csv_content) {
425
                $created = 0;
426
                foreach ($csv_content as $line) {
427
                    if ($line) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $line of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
428
                        $occurrence = $this->updateOccurrence(array(
429
                            'id' => '',
430
                            'instant_win_id' => $data['instant_win_id'],
431
                            'value' => $line[0],
432
                            'active' => $data['active'],
433
                            'winning' => ((bool) $line[1]) ? 1 : 0,
434
                            'prize_id' => $data['prize'],
435
                        ), null);
436
                        if ($occurrence) {
437
                            $created++;
438
                        }
439
                    }
440
                }
441
                // remove the csv file from folder
442
                unlink($real_media_path.$data['file']['name']);
443
                return $created;
444
            }
445
        }
446
        return false;
447
    }
448
449
    /**
450
     *
451
     *
452
     * @param  array                  $data
453
     * @return \PlaygroundGame\Entity\Game
454
     */
455
    public function updateOccurrence(array $data, $occurrence_id = null)
456
    {
457
        if (!$occurrence_id) {
458
            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
459
        } else {
460
            $occurrence = $this->getInstantWinOccurrenceMapper()->findById($occurrence_id);
461
        }
462
        $form  = $this->getServiceManager()->get('playgroundgame_instantwinoccurrence_form');
463
        $form->bind($occurrence);
464
465
        $form->setData($data);
466
467
        $instantwin = $this->getGameMapper()->findById($data['instant_win_id']);
468
        $prize = null;
469
        if (isset($data['prize'])) {
470
            $prize = $this->getPrizeMapper()->findById($data['prize']);
471
        }
472
473
        if (!$form->isValid()) {
474
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PlaygroundGame\Service\I...ntWin::updateOccurrence of type PlaygroundGame\Entity\Game.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
475
        }
476
477
        $occurrence->setInstantWin($instantwin);
478
        $occurrence->setPrize($prize);
479
        $occurrence->populate($data);
480
481
        if ($occurrence_id) {
482
            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
483
        } else {
484
            $this->getInstantWinOccurrenceMapper()->update($occurrence);
485
        }
486
487
        return $occurrence;
488
    }
489
490
    /**
491
     * return true if the player has won. False otherwise.
492
     *
493
     * @param \PlaygroundGame\Entity\Game $game
494
     * @param \PlaygroundUser\Entity\UserInterface $user
495
     *
496
     * @return boolean
497
     */
498
    public function isInstantWinner($game, $user, $value = null)
499
    {
500
        $occurrenceMapper = $this->getInstantWinOccurrenceMapper();
501
502
        if ($game->getOccurrenceType()=='datetime') {
503
            $entry = $this->findLastActiveEntry($game, $user);
504
505
            // si date après date de gain et date de gain encore active alors desactive date de gain, et winner !
506
            $occurrence = $occurrenceMapper->checkDateOccurrenceByGameId($game);
507
        } elseif ($game->getOccurrenceType()=='code') {
508
            $occurrence = $occurrenceMapper->checkCodeOccurrenceByGameId($game, $value);
509
            if (!$occurrence) {
510
                return false;
511
            }
512
            $entry = $this->play($game, $user);
513
        }
514
515
        if (!$entry) {
0 ignored issues
show
Bug introduced by
The variable $entry 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...
516
            return false;
517
        }
518
        return $this->setOccurrenceEntry($game, $user, $entry, $occurrence);
0 ignored issues
show
Bug introduced by
The variable $occurrence 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...
519
    }
520
521
    /**
522
     * @param \PlaygroundGame\Entity\Game $game
523
     * @param \PlaygroundUser\Entity\UserInterface $user
524
     */
525
    public function setOccurrenceEntry($game, $user, $entry, $occurrence = null)
526
    {
527
        $entryMapper = $this->getEntryMapper();
528
        $occurrenceMapper = $this->getInstantWinOccurrenceMapper();
529
530
        $entry->setActive(0);
531
        if ($occurrence) {
532
            $occurrence->setEntry($entry);
533
            $occurrence->setUser($user);
534
            $occurrence->setActive(0);
535
            $occurrence = $occurrenceMapper->update($occurrence);
536
            if ($occurrence->getWinning()) {
537
                $entry->setWinner(true);
538
            } else {
539
                $entry->setPoints(0);
540
                $entry->setWinner(false);
541
            }
542
        } else {
543
            $entry->setPoints(0);
544
            $entry->setWinner(false);
545
        }
546
        $entry = $entryMapper->update($entry);
547
        $this->getEventManager()->trigger(
548
            'complete_instantwin.post',
549
            $this,
550
            array('user' => $user, 'game' => $game, 'entry' => $entry)
551
        );
552
553
        return $occurrence;
554
    }
555
556
    public function getEntriesHeader($game)
557
    {
558
        $header = parent::getEntriesHeader($game);
559
        $header['value'] = 1;
560
        $header['prize'] = 1;
561
562
        return $header;
563
    }
564
565
    /**
566
    * getGameEntries : All entries of a game
567
    *
568
    * @return Array of PlaygroundGame\Entity\Game
569
    */
570
    public function getGameEntries($header, $entries, $game)
571
    {
572
        
573
        $results = array();
574
575
        foreach ($entries as $k => $entry) {
576
            $entryData = json_decode($entry['playerData'], true);
577
            $winner = $entry['winner'];
578
579 View Code Duplication
            foreach ($header as $key => $v) {
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...
580
                if (isset($entryData[$key]) && $key !=='id') {
581
                    $results[$k][$key] = (is_array($entryData[$key]))?implode(', ', $entryData[$key]):$entryData[$key];
582
                } elseif (array_key_exists($key, $entry)) {
583
                    $results[$k][$key] = ($entry[$key] instanceof \DateTime)?
584
                        $entry[$key]->format('Y-m-d'):
585
                        $entry[$key];
586
                } else {
587
                    $results[$k][$key] = '';
588
                }
589
            }
590
            // If the occurrenceType is code, this will be triggered for every entry. To be improved.
591
            if ($game->getOccurrenceType() === 'code' || ($game->getOccurrenceType() === 'datetime' && $winner)) {
592
                $entry = $this->getEntryMapper()->findById($entry['id']);
593
                $occurrence = $this->getInstantWinOccurrenceMapper()->findByEntry($entry);
594
                $results[$k]['value'] = $occurrence->getValue();
595
                if ($occurrence->getPrize()) {
596
                    $results[$k]['prize'] = $occurrence->getPrize()->getTitle();
597
                }
598
            }
599
        }
600
601
        return $results;
602
    }
603
604
    public function getGameEntity()
605
    {
606
        return new \PlaygroundGame\Entity\InstantWin;
607
    }
608
609
    /**
610
     * getInstantWinOccurrenceMapper
611
     *
612
     * @return InstantWinOccurrenceMapperInterface
613
     */
614
    public function getInstantWinOccurrenceMapper()
615
    {
616
        if (null === $this->instantWinOccurrenceMapper) {
617
            $this->instantWinOccurrenceMapper = $this->getServiceManager()->get(
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getServiceManager...twinoccurrence_mapper') can also be of type array. However, the property $instantWinOccurrenceMapper is declared as type object<PlaygroundGame\Se...urrenceMapperInterface>. 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...
618
                'playgroundgame_instantwinoccurrence_mapper'
619
            );
620
        }
621
622
        return $this->instantWinOccurrenceMapper;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->instantWinOccurrenceMapper; of type object|array adds the type array to the return on line 622 which is incompatible with the return type documented by PlaygroundGame\Service\I...tantWinOccurrenceMapper of type PlaygroundGame\Service\I...currenceMapperInterface.
Loading history...
623
    }
624
625
    /**
626
     * setInstantWinOccurrenceMapper
627
     *
628
     * @return InstantWin
629
     */
630
    public function setInstantWinOccurrenceMapper($instantWinOccurrenceMapper)
631
    {
632
        $this->instantWinOccurrenceMapper = $instantWinOccurrenceMapper;
633
634
        return $this;
635
    }
636
637
    /**
638
     * getPrizeMapper
639
     *
640
     * @return PrizeMapperInterface
641
     */
642 View Code Duplication
    public function getPrizeMapper()
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...
643
    {
644
        if (null === $this->prizeMapper) {
645
            $this->prizeMapper = $this->getServiceManager()->get('playgroundgame_prize_mapper');
646
        }
647
648
        return $this->prizeMapper;
649
    }
650
651
    /**
652
     * setInstantWinOccurrenceMapper
653
     *
654
     * @param  PrizeMapperInterface $prizeMapper
655
     * @return InstantWin
656
     */
657
    public function setPrizeMapper($prizeMapper)
658
    {
659
        $this->prizeMapper = $prizeMapper;
660
661
        return $this;
662
    }
663
}
664