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

InstantWin::setOccurrenceEntry()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
rs 8.8571
cc 3
eloc 20
nc 3
nop 4
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);
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($path, $game->getId() . "-" . $data['uploadScratchcardImage']['name']);
36
                move_uploaded_file($data['uploadScratchcardImage']['tmp_name'], $path . $data['uploadScratchcardImage']['name']);
37
                $game->setScratchcardImage($media_url . $data['uploadScratchcardImage']['name']);
38
                ErrorHandler::stop(true);
39
40
                $game = $this->getGameMapper()->update($game);
41
            }
42
43
            if ($game->getOccurrenceNumber() && $game->getScheduleOccurrenceAuto()) {
44
                $this->scheduleOccurrences($game, $data);
45
            }
46
        }
47
48
        return $game;
49
    }
50
51
    /**
52
     *
53
     * saving an instantwin image if any
54
     *
55
     * @param  array                  $data
56
     * @param  string                 $formClass
57
     * @return \PlaygroundGame\Entity\Game
58
     */
59
    public function edit(array $data, $game, $formClass)
60
    {
61
        $game = parent::edit($data, $game, $formClass);
62
63
        if ($game) {
64
            $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
65
            $media_url = $this->getOptions()->getMediaUrl() . '/';
66
67
            if (!empty($data['uploadScratchcardImage']['tmp_name'])) {
68
                ErrorHandler::start();
69
                $data['uploadScratchcardImage']['name'] = $this->fileNewname($path, $game->getId() . "-" . $data['uploadScratchcardImage']['name']);
70
                move_uploaded_file($data['uploadScratchcardImage']['tmp_name'], $path . $data['uploadScratchcardImage']['name']);
71
                $game->setScratchcardImage($media_url . $data['uploadScratchcardImage']['name']);
72
                ErrorHandler::stop(true);
73
74
                $game = $this->getGameMapper()->update($game);
75
            }
76
77 View Code Duplication
            if (isset($data['deleteScratchcardImage']) && $data['deleteScratchcardImage'] && empty($data['uploadScratchcardImage']['tmp_name'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
78
                ErrorHandler::start();
79
                $image = $game->getScratchcardImage();
80
                $image = str_replace($media_url, '', $image);
81
                unlink($path .$image);
82
                $game->setScratchcardImage(null);
83
                ErrorHandler::stop(true);
84
            }
85
86
            if ($game->getOccurrenceNumber() && $game->getScheduleOccurrenceAuto()) {
87
                $this->scheduleOccurrences($game, $data);
88
            }
89
        }
90
91
        return $game;
92
    }
93
94
    /**
95
     * We can create Instant win occurrences dynamically
96
     *
97
     *
98
     * @param  array                  $data
99
     * @return boolean|null
100
     */
101
    public function scheduleOccurrences($game, array $data)
102
    {
103
        // It will be quite long to create these occurrences !
104
        set_time_limit(0);
105
        if ($game->getOccurrenceType() === 'code') {
106
            return $this->scheduleCodeOccurrences($game, $data);
107
        } elseif ($game->getOccurrenceType() === 'datetime') {
108
            return $this->scheduleDateOccurrences($game);
109
        }
110
    }
111
112
    public function scheduleCodeOccurrences($game, $data)
113
    {
114
        $available_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-';
115
        $last_character_index = strlen($available_characters)-1;
116
        if (!$game->getWinningOccurrenceNumber()) {
117
            $game->setWinningOccurrenceNumber($game->getOccurrenceNumber());
118
        }
119
        if (empty($data['occurrenceValueSize'])) {
120
            $data['occurrenceValueSize'] = 8;
121
        }
122
        $created = 0;
123
        $numOccurrences = $game->getOccurrenceNumber();
124
        
125
        for ($i=0; $i < $numOccurrences; $i++) {
126
            $code = '';
127
            while (strlen($code)<$data['occurrenceValueSize']) {
128
                $code .= $available_characters[rand(0, $last_character_index)];
129
            }
130
            $occurrence = new \PlaygroundGame\Entity\InstantWinOccurrence();
131
            $occurrence->setInstantwin($game);
132
            $occurrence->setValue($code);
133
            $occurrence->setActive(1);
134
            $occurrence->setWinning($created < $game->getWinningOccurrenceNumber());
135
            if ($this->getInstantWinOccurrenceMapper()->insert($occurrence)) {
136
                $created++;
137
            }
138
        }
139
        return true;
140
    }
141
142
    public function scheduleDateOccurrences($game)
143
    {
144
        $f = $game->getOccurrenceDrawFrequency();
145
        $today    = new \DateTime("now");
146
        $end      = new \DateTime("now");
147
        $interval = 'P10D';
148
        if ($game->getStartDate() && $game->getStartDate() > $today) {
149
            $beginning = $game->getStartDate();
150
        } else {
151
            $beginning = $today;
152
        }
153
154
        if ($game->getEndDate()) {
155
            $end = $game->getEndDate();
156
        } else {
157
            $end->add(new \DateInterval($interval));
158
        }
159
160
        // Summertimes timezone management
161
        $timezone = $today->getTimezone();
162
        $transitions = $timezone->getTransitions($beginning->getTimestamp(), $end->getTimestamp());
163
164
        // There is a time transition between these datetimes()
165
        if (count($transitions) == 2) {
166
            $shift = $transitions[0]['offset'] - $transitions[1]['offset'];
167
            if ($shift > 0) {
168
                $end->sub(new \DateInterval('PT'.abs($shift).'S'));
169
            } else {
170
                $end->add(new \DateInterval('PT'.abs($shift).'S'));
171
            }
172
        }
173
174
        // DateInterval takes the day @ 00:00 to calculate the difference between the dates, so 1 day is always missing
175
        // as we consider the last day @ 23:59:59 in Playground :)
176
        if ($end->format('His') == 0) {
177
            $end->add(new \DateInterval('P1D'));
178
        }
179
180
        $dateInterval = (int)(($end->getTimestamp() - $beginning->getTimestamp())/60);
181
182
        switch ($f) {
183
            case null:
184
            case 'game':
185
                // Je recherche tous les IG non gagnés
186
                $occurrences = $this->getInstantWinOccurrenceMapper()->findBy(array('instantwin' => $game));
187
                $nbOccurencesToCreate = $game->getOccurrenceNumber() - count($occurrences);
188
                if ($nbOccurencesToCreate > 0) {
189
                    for ($i=1; $i<=$nbOccurencesToCreate; $i++) {
190
                        $randomDate = $this->getRandomDate($beginning->format('U'), $end->format('U'));
191
                        $randomDate = \DateTime::createFromFormat('Y-m-d H:i:s', $randomDate);
192
                        $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
193
                        $occurrence->setInstantwin($game);
194
                        $occurrence->setValue($randomDate->format('Y-m-d H:i:s'));
195
                        $occurrence->setActive(1);
196
197
                        $this->getInstantWinOccurrenceMapper()->insert($occurrence);
198
                    }
199
                }
200
201
                break;
202 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...
203
                $occurrences = $this->getInstantWinOccurrenceMapper()->findBy(array('instantwin' => $game));
204
                $nbExistingOccurrences = count($occurrences);
205
                $nbOccurencesToCreate = 0;
206
                $nbInterval = (int) ($dateInterval/60);
207
208
                // If a hour don't last 60min, I consider it as a hour anyway.
209
                if ($dateInterval%60 > 0) {
210
                    ++$nbInterval;
211
                }
212
                if ($nbInterval > 0) {
213
                    $nbOccurencesToCreate = $game->getOccurrenceNumber() - floor($nbExistingOccurrences/$nbInterval);
214
                }
215
216
                $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y H:i:s'));
217
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y H'). ':59:59');
218
219
                if ($nbOccurencesToCreate > 0) {
220
                    for ($d=1; $d<=$nbInterval; $d++) {
221
                        for ($i=1; $i<=$nbOccurencesToCreate; $i++) {
222
                            $randomDate = $this->getRandomDate($beginningDrawDate->format('U'), $endDrawDate->format('U'));
223
                            $randomDate = \DateTime::createFromFormat('Y-m-d H:i:s', $randomDate);
224
                            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
225
                            $occurrence->setInstantwin($game);
226
227
                            $occurrence->setValue($randomDate->format('Y-m-d H:i:s'));
228
                            $occurrence->setActive(1);
229
230
                            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
231
                        }
232
                        $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginningDrawDate->format('m/d/Y H'). ':00:00');
233
                        $beginningDrawDate->add(new \DateInterval('PT1H'));
234
                        $endDrawDate->add(new \DateInterval('PT1H'));
235
                    }
236
                }
237
238
                break;
239 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...
240
                $occurrences = $this->getInstantWinOccurrenceMapper()->findBy(array('instantwin' => $game));
241
                $nbExistingOccurrences = count($occurrences);
242
                $nbOccurencesToCreate = 0;
243
                $nbInterval = (int) ($dateInterval/(60*24));
244
245
                // Prise en compte des changements d'horaires
246
                // If a day don't last 24h, I consider it as a day anyway
247
248
                if ($dateInterval%(60*24) > 0) {
249
                    ++$nbInterval;
250
                }
251
252
                if ($nbInterval > 0) {
253
                    $nbOccurencesToCreate = $game->getOccurrenceNumber() - floor($nbExistingOccurrences/$nbInterval);
254
                }
255
256
                $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y H:i:s'));
257
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 23:59:59');
258
                if ($nbOccurencesToCreate > 0) {
259
                    for ($d=1; $d<=$nbInterval; $d++) {
260
                        for ($i=1; $i<=$nbOccurencesToCreate; $i++) {
261
                            $randomDate = $this->getRandomDate($beginningDrawDate->format('U'), $endDrawDate->format('U'));
262
                            $randomDate = \DateTime::createFromFormat('Y-m-d H:i:s', $randomDate);
263
                            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
264
                            $occurrence->setInstantwin($game);
265
                            $occurrence->setValue($randomDate->format('Y-m-d H:i:s'));
266
                            $occurrence->setActive(1);
267
268
                            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
269
                        }
270
                        // As the first beginning date was not @ midnight,
271
                        // I recreate the beginning date
272
                        $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginningDrawDate->format('m/d/Y'). ' 00:00:00');
273
                        $beginningDrawDate->add(new \DateInterval('P1D'));
274
                        $endDrawDate->add(new \DateInterval('P1D'));
275
                    }
276
                }
277
278
                break;
279 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...
280
                // Rechercher tous les IG non gagnés pour chaque jour puis soustrais à ceux à créer
281
                $occurences = $this->getInstantWinOccurrenceMapper()->findBy(array('instantwin' => $game));
282
                $nbOccurencesToCreate = $game->getOccurrenceNumber() - count($occurences);
283
                $nbWeeksInterval = (int) ($dateInterval/(60*24*7));
284
                // If a week don't last 7d, I consider it as a week anyway.
285
                if ($dateInterval%(60*24*7) > 0) {
286
                    ++$nbWeeksInterval;
287
                }
288
                $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 00:00:00');
289
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 23:59:59');
290
                $endDrawDate->add(new \DateInterval('P6D'));
291
                if ($endDrawDate > $end) {
292
                    $endDrawDate = $end;
293
                }
294
295
                if ($nbOccurencesToCreate > 0) {
296
                    for ($d=1; $d<=$nbWeeksInterval; $d++) {
297
                        for ($i=1; $i<=$nbOccurencesToCreate; $i++) {
298
                            $randomDate = $this->getRandomDate($beginningDrawDate->format('U'), $endDrawDate->format('U'));
299
                            $randomDate = \DateTime::createFromFormat('Y-m-d H:i:s', $randomDate);
300
                            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
301
                            $occurrence->setInstantwin($game);
302
                            $occurrence->setValue($randomDate->format('Y-m-d H:i:s'));
303
                            $occurrence->setActive(1);
304
305
                            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
306
                        }
307
                        $beginningDrawDate->add(new \DateInterval('P1W'));
308
                        $endDrawDate->add(new \DateInterval('P1W'));
309
                        if ($endDrawDate > $end) {
310
                            $endDrawDate = $end;
311
                        }
312
                    }
313
                }
314
315
                break;
316 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...
317
                $occurences = $this->getInstantWinOccurrenceMapper()->findBy(array('instantwin' => $game));
318
                $nbOccurencesToCreate = $game->getOccurrenceNumber() - count($occurences);
319
                $nbMonthsInterval = (int) ($dateInterval/(60*24*30));
320
                // If a week don't last 30d, I consider it as a month anyway.
321
                if ($dateInterval%(60*24*30) > 0) {
322
                    ++$nbMonthsInterval;
323
                }
324
                $beginningDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 00:00:00');
325
                $endDrawDate = \DateTime::createFromFormat('m/d/Y H:i:s', $beginning->format('m/d/Y'). ' 23:59:59');
326
                $endDrawDate->add(new \DateInterval('P1M'));
327
                $endDrawDate->sub(new \DateInterval('P1D'));
328
                if ($endDrawDate > $end) {
329
                    $endDrawDate = $end;
330
                }
331
332
                if ($nbOccurencesToCreate > 0) {
333
                    for ($d=1; $d<=$nbMonthsInterval; $d++) {
334
                        for ($i=1; $i<=$nbOccurencesToCreate; $i++) {
335
                            $randomDate = $this->getRandomDate($beginningDrawDate->format('U'), $endDrawDate->format('U'));
336
                            $randomDate = \DateTime::createFromFormat('Y-m-d H:i:s', $randomDate);
337
                            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
338
                            $occurrence->setInstantwin($game);
339
                            $occurrence->setValue($randomDate->format('Y-m-d H:i:s'));
340
                            $occurrence->setActive(1);
341
342
                            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
343
                        }
344
                        $beginningDrawDate->add(new \DateInterval('P1M'));
345
                        $endDrawDate->add(new \DateInterval('P1M'));
346
                        if ($endDrawDate > $end) {
347
                            $endDrawDate = $end;
348
                        }
349
                    }
350
                }
351
352
                break;
353
        }
354
355
        return true;
356
    }
357
358
    public function getRandomDate($min_date, $max_date)
359
    {
360
        $rand_epoch = rand($min_date, $max_date);
361
362
        return date('Y-m-d H:i:s', $rand_epoch);
363
    }
364
365
    /**
366
     * @param string $fileName
367
     */
368
    public function getOccurencesFromCSV($fileName)
369
    {
370
        if (file_exists($fileName)) {
371
            $csvFile = fopen($fileName, 'r');
372
            if ($csvFile) {
373
                while (!feof($csvFile)) {
374
                    $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...
375
                }
376
                fclose($csvFile);
377
                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...
378
            }
379
        }
380
        return false;
381
    }
382
383
    public function setOccurencesToCSV($game)
384
    {
385
        $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
386
        $fileName = $path.'occurences-'.$game->getId().'.csv';
387
        $csvFile = fopen($fileName, 'w');
388
        if ($csvFile) {
389
            $occurrences = $this->getInstantWinOccurrenceMapper()->findByGameId($game);
390
            foreach ($occurrences as $occurrence) {
391
                fputcsv($csvFile, array($occurrence->getValue(), $occurrence->getWinning()));
392
            }
393
            fclose($csvFile);
394
            return $fileName;
395
        }
396
        return false;
397
    }
398
399
    public function importOccurrences($data)
400
    {
401
        if (!empty($data['file']['tmp_name'])) {
402
            $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
403
            $real_media_path = realpath($path) . DIRECTORY_SEPARATOR;
404
405
            // upload the csv file
406
            ErrorHandler::start();
407
            $data['file']['name'] = $this->fileNewname($path, $data['instant_win_id'] . "-" . $data['file']['name']);
408
            move_uploaded_file($data['file']['tmp_name'], $path . $data['file']['name']);
409
            ErrorHandler::stop(true);
410
            $csv_content = $this->getOccurencesFromCSV($real_media_path.$data['file']['name']);
411
            if ($csv_content) {
412
                $created = 0;
413
                foreach ($csv_content as $line) {
414
                    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...
415
                        $occurrence = $this->updateOccurrence(array(
416
                            'id' => '',
417
                            'instant_win_id' => $data['instant_win_id'],
418
                            'value' => $line[0],
419
                            'active' => $data['active'],
420
                            'winning' => ((bool) $line[1]) ? 1 : 0,
421
                            'prize_id' => $data['prize'],
422
                        ), null);
423
                        if ($occurrence) {
424
                            $created++;
425
                        }
426
                    }
427
                }
428
                // remove the csv file from folder
429
                unlink($real_media_path.$data['file']['name']);
430
                return $created;
431
            }
432
        }
433
        return false;
434
    }
435
436
    /**
437
     *
438
     *
439
     * @param  array                  $data
440
     * @return \PlaygroundGame\Entity\Game
441
     */
442
    public function updateOccurrence(array $data, $occurrence_id = null)
443
    {
444
        if (!$occurrence_id) {
445
            $occurrence  = new \PlaygroundGame\Entity\InstantWinOccurrence();
446
        } else {
447
            $occurrence = $this->getInstantWinOccurrenceMapper()->findById($occurrence_id);
448
        }
449
        $form  = $this->getServiceManager()->get('playgroundgame_instantwinoccurrence_form');
450
        $form->bind($occurrence);
451
452
        $form->setData($data);
453
454
        $instantwin = $this->getGameMapper()->findById($data['instant_win_id']);
455
        $prize = null;
456
        if (isset($data['prize'])) {
457
            $prize = $this->getPrizeMapper()->findById($data['prize']);
458
        }
459
460
        if (!$form->isValid()) {
461
            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...
462
        }
463
464
        $occurrence->setInstantWin($instantwin);
465
        $occurrence->setPrize($prize);
466
        $occurrence->populate($data);
467
468
        if ($occurrence_id) {
469
            $this->getInstantWinOccurrenceMapper()->insert($occurrence);
470
        } else {
471
            $this->getInstantWinOccurrenceMapper()->update($occurrence);
472
        }
473
474
        return $occurrence;
475
    }
476
477
    /**
478
     * return true if the player has won. False otherwise.
479
     *
480
     * @param \PlaygroundGame\Entity\Game $game
481
     * @param \PlaygroundUser\Entity\UserInterface $user
482
     *
483
     * @return boolean
484
     */
485
    public function isInstantWinner($game, $user, $value = null)
486
    {
487
        $occurrenceMapper = $this->getInstantWinOccurrenceMapper();
488
489
        if ($game->getOccurrenceType()=='datetime') {
490
            $entry = $this->findLastActiveEntry($game, $user);
491
492
            // si date après date de gain et date de gain encore active alors desactive date de gain, et winner !
493
            $occurrence = $occurrenceMapper->checkDateOccurrenceByGameId($game);
494
        } elseif ($game->getOccurrenceType()=='code') {
495
            $occurrence = $occurrenceMapper->checkCodeOccurrenceByGameId($game, $value);
496
            if (!$occurrence) {
497
                return false;
498
            }
499
            $entry = $this->play($game, $user);
500
        }
501
502
        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...
503
            return false;
504
        }
505
        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...
506
    }
507
508
    /**
509
     * @param \PlaygroundGame\Entity\Game $game
510
     * @param \PlaygroundUser\Entity\UserInterface $user
511
     */
512
    public function setOccurrenceEntry($game, $user, $entry, $occurrence = null)
513
    {
514
        $entryMapper = $this->getEntryMapper();
515
        $occurrenceMapper = $this->getInstantWinOccurrenceMapper();
516
517
        $entry->setActive(0);
518
        if ($occurrence) {
519
            $occurrence->setEntry($entry);
520
            $occurrence->setUser($user);
521
            $occurrence->setActive(0);
522
            $occurrence = $occurrenceMapper->update($occurrence);
523
            if ($occurrence->getWinning()) {
524
                $entry->setWinner(true);
525
            } else {
526
                $entry->setPoints(0);
527
                $entry->setWinner(false);
528
            }
529
        } else {
530
            $entry->setPoints(0);
531
            $entry->setWinner(false);
532
        }
533
        $entry = $entryMapper->update($entry);
534
        $this->getEventManager()->trigger('complete_instantwin.post', $this, array('user' => $user, 'game' => $game, 'entry' => $entry));
535
536
        return $occurrence;
537
    }
538
539
    public function getEntriesHeader($game)
540
    {
541
        $header = parent::getEntriesHeader($game);
542
        $header['value'] = 1;
543
        $header['prize'] = 1;
544
545
        return $header;
546
    }
547
548
    /**
549
    * getGameEntries : All entries of a game
550
    *
551
    * @return Array of PlaygroundGame\Entity\Game
552
    */
553
    public function getGameEntries($header, $entries, $game)
554
    {
555
        
556
        $results = array();
557
558
        foreach ($entries as $k => $entry) {
559
            $entryData = json_decode($entry['playerData'], true);
560
            $winner = $entry['winner'];
561
562 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...
563
                if (isset($entryData[$key]) && $key !=='id') {
564
                    $results[$k][$key] = (is_array($entryData[$key]))?implode(', ', $entryData[$key]):$entryData[$key];
565
                } elseif (array_key_exists($key, $entry)) {
566
                    $results[$k][$key] = ($entry[$key] instanceof \DateTime)?$entry[$key]->format('Y-m-d'):$entry[$key];
567
                } else {
568
                    $results[$k][$key] = '';
569
                }
570
            }
571
            // If the occurrenceType is code, this will be triggered for every entry. To be improved.
572
            if ($game->getOccurrenceType() === 'code' || ($game->getOccurrenceType() === 'datetime' && $winner)) {
573
                $entry = $this->getEntryMapper()->findById($entry['id']);
574
                $occurrence = $this->getInstantWinOccurrenceMapper()->findByEntry($entry);
575
                $results[$k]['value'] = $occurrence->getValue();
576
                if ($occurrence->getPrize()) {
577
                    $results[$k]['prize'] = $occurrence->getPrize()->getTitle();
578
                }
579
            }
580
        }
581
582
        return $results;
583
    }
584
585
    public function getGameEntity()
586
    {
587
        return new \PlaygroundGame\Entity\InstantWin;
588
    }
589
590
    /**
591
     * getInstantWinOccurrenceMapper
592
     *
593
     * @return InstantWinOccurrenceMapperInterface
594
     */
595
    public function getInstantWinOccurrenceMapper()
596
    {
597
        if (null === $this->instantWinOccurrenceMapper) {
598
            $this->instantWinOccurrenceMapper = $this->getServiceManager()->get('playgroundgame_instantwinoccurrence_mapper');
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...
599
        }
600
601
        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 601 which is incompatible with the return type documented by PlaygroundGame\Service\I...tantWinOccurrenceMapper of type PlaygroundGame\Service\I...currenceMapperInterface.
Loading history...
602
    }
603
604
    /**
605
     * setInstantWinOccurrenceMapper
606
     *
607
     * @return InstantWin
608
     */
609
    public function setInstantWinOccurrenceMapper($instantWinOccurrenceMapper)
610
    {
611
        $this->instantWinOccurrenceMapper = $instantWinOccurrenceMapper;
612
613
        return $this;
614
    }
615
616
    /**
617
     * getPrizeMapper
618
     *
619
     * @return PrizeMapperInterface
620
     */
621 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...
622
    {
623
        if (null === $this->prizeMapper) {
624
            $this->prizeMapper = $this->getServiceManager()->get('playgroundgame_prize_mapper');
625
        }
626
627
        return $this->prizeMapper;
628
    }
629
630
    /**
631
     * setInstantWinOccurrenceMapper
632
     *
633
     * @param  PrizeMapperInterface $prizeMapper
634
     * @return InstantWin
635
     */
636
    public function setPrizeMapper($prizeMapper)
637
    {
638
        $this->prizeMapper = $prizeMapper;
639
640
        return $this;
641
    }
642
}
643