Completed
Push — master ( a1d9ad...47055c )
by Vladimir
11:18
created

MatchController::validate()   D

Complexity

Conditions 10
Paths 15

Size

Total Lines 40
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 16.8468

Importance

Changes 0
Metric Value
dl 0
loc 40
ccs 13
cts 22
cp 0.5909
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 23
nc 15
nop 1
crap 16.8468

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
use Symfony\Component\Form\Form;
4
use Symfony\Component\Form\FormError;
5
use Symfony\Component\HttpFoundation\RedirectResponse;
6
use Symfony\Component\HttpFoundation\Request;
7
use Symfony\Component\HttpFoundation\StreamedResponse;
8
9
class MatchController extends CRUDController
10
{
11
    /**
12
     * Whether the last edited match has had its ELO changed, requiring an ELO
13
     * recalculation
14
     *
15
     * This is useful so that a confirmation form is shown, asking the user if
16
     * they want to recalculate ELOs
17
     *
18
     * @var bool
19
     */
20
    public $recalculateNeeded = false;
21
22
    public function listAction(Request $request, Player $me, Team $team = null, Player $player = null, $type = null)
23
    {
24
        /** @var MatchQueryBuilder $qb */
25
        $qb = self::getQueryBuilder();
26
        $currentPage = $this->getCurrentPage();
27
28
        if ($player) {
29
            $team = $player;
30
        }
31
32
        $query = $qb
33
            ->sortBy('time')->reverse()
34
            ->with($team, $type)
0 ignored issues
show
Bug introduced by
It seems like $team defined by parameter $team on line 22 can also be of type null; however, MatchQueryBuilder::with() does only seem to accept object<Team>|object<Player>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
35
            ->limit(50)->fromPage($currentPage)
36
        ;
37
38
        $matchType = $request->query->get('type', 'all');
39
40
        if (in_array($matchType, [Match::FUN, Match::OFFICIAL, Match::SPECIAL])) {
41
            $query->where('type')->is($matchType);
42
        }
43
44
        $matches = $query->getModels($fast = true);
45
46
        /** @var Match $match */
47
        foreach ($matches as $match) {
48
            // Don't show wrong labels for matches
49
            $match->getOriginalTimestamp()->setTimezone($me->getTimezone());
50
        }
51
52
        $matches = __::groupBy($matches, function ($match) {
53
            /** @var Match $match */
54
            $ts = $match->getOriginalTimestamp();
55
56 1
            if ($ts->year !== TimeDate::now()->year) {
57
                return $ts->format(TimeDate::DATE_FULL);
58 1
            }
59
60
            return $ts->format(TimeDate::DATE_MEDIUM);
61 1
        });
62
63
        return [
64 1
            'matchType'   => $type,
65 1
            'matches'     => $matches,
66 1
            'team'        => $team,
67 1
            'currentPage' => $currentPage,
68
            'totalPages'  => $qb->countPages(),
69
        ];
70
    }
71
72
    public function showAction(Match $match)
73
    {
74
        return array("match" => $match);
75 1
    }
76
77
    public function createAction(Player $me)
78
    {
79
        return $this->create($me, function (Match $match) use ($me) {
80 View Code Duplication
            if ($me->canEdit($match)
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...
81
                && $match->isOfficial()
82
                && (!$match->getTeamA()->isLastMatch($match)
83
                || !$match->getTeamB()->isLastMatch($match))
84
            ) {
85
                $url = Service::getGenerator()->generate('match_recalculate', array(
86
                    'match' => $match->getId(),
87
                ));
88
89
                return new RedirectResponse($url);
90
            }
91
        });
92
    }
93
94
    public function deleteAction(Player $me, Match $match)
95
    {
96
        return $this->delete($match, $me, function () use ($match, $me) {
97 View Code Duplication
            if ($match->getTeamA()->isLastMatch($match) && $match->getTeamB()->isLastMatch($match)) {
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...
98
                $match->resetTeamElos();
99
                $match->resetPlayerElos();
100
            } elseif ($me->canEdit($match)) {
101
                $url = Service::getGenerator()->generate('match_recalculate', array(
102
                    'match' => $match->getId(),
103
                ));
104
105
                return new RedirectResponse($url);
106
            }
107
        });
108
    }
109
110 View Code Duplication
    public function editAction(Player $me, Match $match)
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...
111
    {
112
        // TODO: Generating this response is unnecessary
113
        $response = $this->edit($match, $me, "match");
114
115
        if ($this->recalculateNeeded && $match->isOfficial()) {
116
            // Redirect to a confirmation form if we are assigning a new leader
117
            $url = Service::getGenerator()->generate('match_recalculate', array(
118
                'match' => $match->getId(),
119
            ));
120
121
            return new RedirectResponse($url);
122
        }
123
124
        return $response;
125
    }
126
127
    public function recalculateAction(Player $me, $match)
128
    {
129
        $match = Match::get($match); // get a match even if it's deleted
130
131
        if (!$me->canEdit($match)) {
132
            throw new ForbiddenException("You are not allowed to edit that match.");
133
        }
134
135
        if (!$match->isOfficial()) {
136
            throw new BadRequestException("You can't recalculate ELO history for a special match.");
137
        }
138
139
        return $this->showConfirmationForm(function () use ($match) {
140
            $response = new StreamedResponse();
141
            $response->headers->set('Content-Type', 'text/plain');
142
            $response->setCallback(function () use ($match) {
143
                $this->log(Match::recalculateMatchesSince($match));
144
            });
145
            $response->send();
146
        }, "Do you want to recalculate ELO history for all teams and matches after the specified match?",
147
            "ELO history recalculated",
148
            "Recalculate ELOs",
149
            function () use ($match) {
150
                if ($match->isDeleted()) {
151
                    return new RedirectResponse($match->getURL('list'));
152
                }
153
154
                return new RedirectResponse($match->getURL('show'));
155
            },
156
            "Match/recalculate.html.twig",
157
            $noButton = true
158
        );
159
    }
160
161
    /**
162 1
     * Echo a string and flush the buffers
163
     *
164 1
     * Useful for streamed AJAX responses
165
     *
166
     * @param string $string The string to echo
167 1
     */
168 1
    private function log($string)
169 1
    {
170 1
        echo $string;
171
        ob_flush();
172
        flush();
173
    }
174
175 1
    /**
176
     * {@inheritdoc}
177
     */
178 1
    protected function getMessages($type, $name = '')
179
    {
180
        $messages = parent::getMessages($type, $name);
181
182 1
        // Don't show the match info on the successful create/edit message
183 1
        foreach ($messages as &$action) {
184
            foreach ($action as &$status) {
185 1
                if (isset($status['named'])) {
186
                    $status['named'] = $status['unnamed'];
187
                }
188
            }
189 1
        }
190 1
191 1
        return $messages;
192
    }
193
194 1
    /**
195
     * @param Form $form
196 1
     */
197 1
    protected function validate($form)
198 1
    {
199 1
        // Make sure that two different teams participated in a match, i.e. a team
200
        // didn't match against itself
201 1
        $firstTeam  = $form->get('first_team')->get('team')->getData();
202 1
        $secondTeam = $form->get('second_team')->get('team')->getData();
203
204 1
        if (!$firstTeam || !$secondTeam) {
205
            return;
206 1
        }
207 1
208 1
        if ($firstTeam->isSameAs($secondTeam)) {
209
            $message = "You can't report a match where a team played against itself!";
210 1
            $form->addError(new FormError($message));
211 1
        }
212 1
213
        $matchType = $form->get('type')->getData();
214
215
        foreach (array('first_team', 'second_team') as $team) {
216
            $input = $form->get($team);
217 1
            $teamInput = $input->get('team');
218
            $teamParticipants = $input->get('participants');
219
220
            if ($matchType === Match::FUN) {
221
                if (!$teamInput->getData() instanceof ColorTeam) {
222
                    $message = "Please enter a team color for fun and special matches.";
223
                    $teamInput->addError(new FormError($message));
224
                }
225
            } elseif ($matchType === Match::OFFICIAL) {
226
                if ($teamInput->getData() instanceof ColorTeam) {
227
                    $participants = $teamParticipants->getData();
228
229
                    if (empty($participants)) {
230
                        $message = 'A player roster is necessary for a color team for a mixed official match.';
231
                        $teamInput->addError(new FormError($message));
232
                    }
233
                }
234
            }
235
        }
236
    }
237
238
    /**
239
     * @param Form $form
240
     * @param Match $match
241
     */
242
    protected function validateEdit($form, $match)
243
    {
244
        if ($match->isOfficial() && $form->get('type')->getData() !== Match::OFFICIAL) {
245
            $message = "You cannot change this match's type.";
246
            $form->get('type')->addError(new FormError($message));
247
        } elseif (!$match->isOfficial() && $form->get('type')->getData() === Match::OFFICIAL) {
248
            $message = "You can't make this an official match.";
249
            $form->get('type')->addError(new FormError($message));
250
        }
251
    }
252
}
253