Completed
Push — develop ( f8651f...893e32 )
by greg
02:30
created

Memory::createOrUpdate()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 41

Duplication

Lines 41
Ratio 100 %

Importance

Changes 0
Metric Value
dl 41
loc 41
rs 8.6417
c 0
b 0
f 0
cc 6
nc 5
nop 3
1
<?php
2
3
namespace PlaygroundGame\Service;
4
5
use Zend\Stdlib\ErrorHandler;
6
7
class Memory extends Game
8
{
9
    protected $memoryMapper;
10
    protected $memoryCardMapper;
11
    protected $memoryScoreMapper;
12
13 View Code Duplication
    public function getCardPath($card)
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...
14
    {
15
        $path = $this->getOptions()->getMediaPath().DIRECTORY_SEPARATOR;
16
        $path .= 'game'.$card->getGame()->getId().DIRECTORY_SEPARATOR;
17
        if (!is_dir($path)) {
18
            mkdir($path, 0777, true);
19
        }
20
        $path .= 'cards'.DIRECTORY_SEPARATOR;
21
        if (!is_dir($path)) {
22
            mkdir($path, 0777, true);
23
        }
24
25
        return $path;
26
    }
27
28 View Code Duplication
    public function getCardMediaUrl($card)
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...
29
    {
30
        $media_url = $this->getOptions()->getMediaUrl().'/';
31
        $media_url .= 'game'.$card->getGame()->getId().'/cards/';
32
33
        return $media_url;
34
    }
35
36
    /**
37
     *
38
     * saving a memory image if any
39
     *
40
     * @param  array $data
41
     * @param  string $formClass
42
     * @return \PlaygroundGame\Entity\Game
43
     */
44 View Code Duplication
    public function createOrUpdate(array $data, $game, $formClass)
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...
45
    {
46
        $game = parent::createOrUpdate($data, $game, $formClass);
47
48
        if ($game) {
49
            $path = $this->getOptions()->getMediaPath() . DIRECTORY_SEPARATOR;
50
            $media_url = $this->getOptions()->getMediaUrl() . '/';
51
52
            if (!empty($data['uploadBackImage']['tmp_name'])) {
53
                ErrorHandler::start();
54
                $data['uploadBackImage']['name'] = $this->fileNewname(
55
                    $path,
56
                    $game->getId() . "-" . $data['uploadBackImage']['name']
57
                );
58
                move_uploaded_file(
59
                    $data['uploadBackImage']['tmp_name'],
60
                    $path . $data['uploadBackImage']['name']
61
                );
62
                $game->setBackImage($media_url . $data['uploadBackImage']['name']);
63
                ErrorHandler::stop(true);
64
65
                $game = $this->getGameMapper()->update($game);
66
            }
67
68
            if (isset($data['deleteBackImage']) &&
69
                $data['deleteBackImage'] &&
70
                empty($data['uploadBackImage']['tmp_name'])
71
            ) {
72
                ErrorHandler::start();
73
                $image = $game->getBackImage();
74
                $image = str_replace($media_url, '', $image);
75
                unlink($path .$image);
76
                $game->setBackImage(null);
77
                ErrorHandler::stop(true);
78
79
                $game = $this->getGameMapper()->update($game);
80
            }
81
        }
82
83
        return $game;
84
    }
85
86
    /**
87
     * @param  array $data
88
     * @return \PlaygroundGame\Entity\Game
89
     */
90
    public function updateCard(array $data, $card)
91
    {
92
        $form        = $this->serviceLocator->get('playgroundgame_memorycard_form');
93
        $memory = $this->getGameMapper()->findById($data['memory_id']);
94
        $card->setGame($memory);
95
        $path      = $this->getCardPath($card);
96
        $media_url = $this->getCardMediaUrl($card);
97
98
        $form->bind($card);
99
        $form->setData($data);
100
101
        if (!$form->isValid()) {
102
            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\Memory::updateCard 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...
103
        }
104 View Code Duplication
        if (!empty($data['upload_image']['tmp_name'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
105
            ErrorHandler::start();
106
            $data['upload_image']['name'] = $this->fileNewname(
107
                $path,
108
                $card->getId()."-".$data['upload_image']['name']
109
            );
110
            move_uploaded_file($data['upload_image']['tmp_name'], $path.$data['upload_image']['name']);
111
            $card->setImage($media_url.$data['upload_image']['name']);
112
            ErrorHandler::stop(true);
113
        }
114
115
        $this->getMemoryCardMapper()->update($card);
116
117
        return $card;
118
    }
119
120
    public function memoryScore($game, $user, array $data)
121
    {
122
        $result = false;
123
        $entry = $this->findLastActiveEntry($game, $user);
124
125
        if (!$entry) {
126
            return $result;
127
        }
128
        $score = $this->getMemoryScoreMapper()->findOneBy(array('entry' => $entry));
129
130
        if (! $score) {
131
            $score = new \PlaygroundGame\Entity\MemoryScore();
132
            $score->setEntry($entry);
0 ignored issues
show
Documentation introduced by
$entry is of type boolean, but the function expects a object<PlaygroundGame\En...roundGame\Entity\Entry>.

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...
133
            $score->setAttempts($data['attempts']);
134
            $score->setMistakes($data['mistakes']);
135
            $score->setDuration($data['duration']);
136
            $score->setTotalCards(count($game->getCards()));
137
            $score = $this->getMemoryScoreMapper()->insert($score);
138
        } else {
139
            $score->setAttempts($data['attempts']);
140
            $score->setMistakes($data['mistakes']);
141
            $score->setDuration($data['duration']);
142
            $score->setTotalCards(count($game->getCards()));
143
            $this->getMemoryScoreMapper()->update($score);
144
        }
145
        
146
        $entry->setActive(0);
0 ignored issues
show
Bug introduced by
The method setActive cannot be called on $entry (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
147
        $entry = $this->isMemoryWinner($game, $user, $score, $entry);
0 ignored issues
show
Documentation introduced by
$entry is of type boolean, but the function expects a object<PlaygroundUser\Entity\Entry>.

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...
148
        $this->getEntryMapper()->update($entry);
149
150
        $this->getEventManager()->trigger(
151
            __FUNCTION__ .'.post',
152
            $this,
153
            array('user' => $user, 'game' => $game, 'entry' => $entry, 'score' => $score)
154
        );
155
156
        return $card;
0 ignored issues
show
Bug introduced by
The variable $card does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
157
    }
158
159
    /**
160
     * return entry after checking victory conditions.
161
     *
162
     * @param \PlaygroundGame\Entity\Game $game
163
     * @param \PlaygroundUser\Entity\User $user
164
     * @param \PlaygroundUser\Entity\MemoryScore $score
165
     * @param \PlaygroundUser\Entity\Entry $entry
166
     *
167
     * @return \PlaygroundUser\Entity\Entry $entry
168
     */
169
    public function isMemoryWinner($game, $user, $score, $entry)
170
    {
171
        $victoryCondition = $game->getVictoryConditions()/100;
172
        $scoreRatio = ($score->getAttempts() - $score->getMistakes()) / $score->getAttempts();
173
        if ($scoreRatio >= $victoryCondition) {
174
            $entry->setWinner(true);
175
        }
176
177
        $this->getEventManager()->trigger(
178
            __FUNCTION__ . '.post',
179
            $this,
180
            [
181
                'user'  => $user,
182
                'game'  => $game,
183
                'entry' => $entry,
184
                'score' => $score,
185
            ]
186
        );
187
188
        return $entry;
189
    }
190
191
    public function getMemoryMapper()
192
    {
193
        if (null === $this->memoryMapper) {
194
            $this->memoryMapper = $this->serviceLocator->get('playgroundgame_memory_mapper');
195
        }
196
197
        return $this->memoryMapper;
198
    }
199
200
    public function getMemoryCardMapper()
201
    {
202
        if (null === $this->memoryCardMapper) {
203
            $this->memoryCardMapper = $this->serviceLocator->get('playgroundgame_memory_card_mapper');
204
        }
205
206
        return $this->memoryCardMapper;
207
    }
208
209
    public function getMemoryScoreMapper()
210
    {
211
        if (null === $this->memoryScoreMapper) {
212
            $this->memoryScoreMapper = $this->serviceLocator->get('playgroundgame_memory_score_mapper');
213
        }
214
215
        return $this->memoryScoreMapper;
216
    }
217
}
218