GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( c7ba65...5d6946 )
by Richard
14:48
created

AjaxController   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 266
Duplicated Lines 12.41 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 44
lcom 1
cbo 5
dl 33
loc 266
rs 8.3396
c 4
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A nextSongsAction() 0 20 4
A reloadPerformersAction() 0 5 1
A songSearchAction() 0 22 3
A useTicketAction() 17 17 2
A remotesRedirectAction() 0 4 1
F saveTicketAction() 0 127 25
A deleteTicketAction() 14 14 2
A lastUpdateHashAction() 0 4 1
B newTicketOrderAction() 0 22 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AjaxController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AjaxController, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: wechsler
5
 * Date: 28/01/2017
6
 * Time: 16:08
7
 */
8
9
namespace Phase\TakeATicketBundle\Controller;
10
11
use Phase\TakeATicket\Model\Instrument;
12
use Phase\TakeATicket\Model\Platform;
13
use Phase\TakeATicketBundle\Entity\User;
14
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
15
use Symfony\Component\HttpFoundation\JsonResponse;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
18
19
class AjaxController extends BaseController
20
{
21
    const MANAGER_REQUIRED_ROLE = 'ROLE_ADMIN';
22
    const BAND_IDENTIFIER_BAND_NAME = 1;
23
    const BAND_IDENTIFIER_PERFORMERS = 2;
24
25
    /**
26
     * @var int Whether to identify band by its name or a list of performers
27
     */
28
    protected $bandIdentifier = self::BAND_IDENTIFIER_PERFORMERS;
29
30
    /**
31
     * @return JsonResponse
32
     *
33
     * FIXME does not honour config.displayOptions.songInPreview - always shows track!
34
     */
35
    public function nextSongsAction()
36
    {
37
        //        $this->setJsonErrorHandler();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
38
        //        $includePrivate = $this->app['security']->isGranted(self::MANAGER_REQUIRED_ROLE);
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
39
        $includePrivate = false;
40
        $next = $this->getDataStore()->fetchUpcomingTickets($includePrivate);
41
        if ($includePrivate) {
42
            $show = $next;
43
        } else {
44
            $show = [];
45
            foreach ($next as $k => $ticket) {
46
                $show[$k] = $ticket;
47
                if ($ticket['blocking']) {
48
                    break;
49
                }
50
            }
51
        }
52
53
        return new JsonResponse($show);
54
    }
55
56
    public function reloadPerformersAction()
57
    {
58
        $performers = $this->getDataStore()->generatePerformerStats();
59
        return new JsonResponse($performers);
60
    }
61
62
    public function songSearchAction(Request $request)
63
    {
64
        $searchString = $request->get('searchString');
65
        $searchCount = 10;
66
        if ($request->get('searchCount')) {
67
            $searchCount = $request->get('searchCount');
68
        }
69
        $dataStore = $this->getDataStore();
70
        $songs = $dataStore->findSongsBySearchString($searchString, $searchCount);
71
        // Need to add sources, instruments
72
        $hydrated = [];
73
74
        foreach ($songs as $song) {
75
            $song = $dataStore->expandSongData($song);
76
77
            $hydrated[] = $song;
78
        }
79
80
        $jsonResponse = new JsonResponse(['ok' => 'ok', 'searchString' => $searchString, 'songs' => $hydrated]);
81
82
        return $jsonResponse;
83
    }
84
85 View Code Duplication
    public function useTicketAction(Request $request)
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...
86
    {
87
        //        $this->setJsonErrorHandler();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
88
89
        $this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE);
90
91
        $id = $request->get('ticketId');
92
        $res = $this->getDataStore()->markTicketUsedById($id);
93
        //FIXME fetch ticket with extra data
94
        if ($res) {
95
            $jsonResponse = new JsonResponse(['ok' => 'ok']);
96
        } else {
97
            $jsonResponse = new JsonResponse(['ok' => 'fail'], 500);
98
        }
99
100
        return $jsonResponse;
101
    }
102
103
    public function remotesRedirectAction()
104
    {
105
        return new JsonResponse($this->getDataStore()->fetchSetting('remotesUrl'));
106
    }
107
108
    public function saveTicketAction(Request $request)
109
    {
110
        if (!$this->getDataStore()->fetchSetting('selfSubmission')) {
111
            $this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE);
112
        }
113
114
        $title = $request->get('title');
115
        $songKey = $request->get('songId');
116
        $band = $request->get('band') ?: []; // band must be array even if null (as passed by AJAX if no performers)
117
        $private = $request->get('private') === 'true' ? 1 : 0;
118
        $blocking = $request->get('blocking') === 'true' ? 1 : 0;
119
        $existingTicketId = $request->get('existingTicketId');
120
        $submissionKey = trim($request->get('submissionKey'));
121
        $userId = null;
122
123
        if ($this->isGranted(self::MANAGER_REQUIRED_ROLE)) {
124
            $user = $this->getUser();
125
            /** @var User $user */
126
            $userId = $user->getId();
127
        } else {
128
            $blocking = 0;
129
            $private = 1;
130
            if ($existingTicketId) {
131
                throw new AccessDeniedException('Cannot modify existing tickets');
132
            }
133
134
            // Check song is unused, check no performers have more than 3 upcoming songs
135
            // Ensure that name format is valid
136
137
            $dataErrors = [];
138
139
            $ticketsForSong = $this->getDataStore()->getQueueEntriesForSongId($songKey);
140
141
            if (count($ticketsForSong)) {
142
                $dataErrors[] = 'The song is already taken';
143
            }
144
145
            $performerStats = $this->getDataStore()->generatePerformerStats();
146
147
            foreach ($band as $instrumentCandidates) {
148
                foreach ($instrumentCandidates as $candidate) {
149
                    $candidate = trim($candidate);
150
                    if ($candidate) {
151
                        if (preg_match('/\w+ \w+/', $candidate)) {
152
                            foreach ($performerStats as $performerStat) {
153
                                if (($performerStat['songsPending'] > 2) &&
154
                                    !strcasecmp($candidate, $performerStat['performerName'])
155
                                ) {
156
                                    $dataErrors[] = "$candidate has too many songs pending";
157
                                }
158
                            }
159
                        } else {
160
                            $dataErrors[] = "'$candidate' is not a valid name";
161
                        }
162
                    }
163
                }
164
            }
165
166
            if ($this->getDataStore()->fetchSetting('selfSubmissionKey') &&
167
                strcasecmp($submissionKey, $this->getDataStore()->fetchSetting('selfSubmissionKey'))
168
            ) {
169
                $dataErrors[] = 'Secret code wrong or missing';
170
            }
171
172
            if ($dataErrors) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $dataErrors 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...
173
                $responseData = [
174
                    'status' => 'error',
175
                    'message' => implode(', ', $dataErrors)
176
                ];
177
                return new JsonResponse($responseData, 200);
178
            }
179
        }
180
181
        $song = null;
182
        $songId = null;
183
184
        if (preg_match('/^[a-f0-9]{6}$/i', $songKey)) {
185
            $song = $this->getDataStore()->fetchSongByKey($songKey);
186
        } elseif (preg_match('/^\d+$/', $songKey)) {
187
            $song = $this->getDataStore()->fetchSongRowById($songKey);
188
        }
189
190
        if ($song) {
191
            $songId = $song['id'];
192
        }
193
194
        if (!$title) {
195
            $title = null;
196
        }
197
198
        if ($existingTicketId) {
199
            $ticketId = $existingTicketId;
200
        } else {
201
            $ticketId = $this->getDataStore()->storeNewTicket($title, $songId, $userId);
202
        }
203
204
        // update even new tickets so that we can add any new columns easily
205
        $updated = ['title' => $title, 'songId' => $songId, 'blocking' => $blocking, 'private' => $private];
206
207
        $this->getDataStore()->updateTicketById(
208
            $ticketId,
209
            $updated
210
        );
211
212
        // think this is legacy?
213
        if ($this->bandIdentifier === self::BAND_IDENTIFIER_PERFORMERS) {
214
            $this->getDataStore()->storeBandToTicket($ticketId, $band);
215
        }
216
217
        $ticket = $this->getDataStore()->fetchTicketById($ticketId);
218
219
        $ticket = $this->getDataStore()->expandTicketData($ticket);
220
221
        $responseData = [
222
            'ticket' => $ticket,
223
            'performers' => $this->getDataStore()->generatePerformerStats(),
224
            'status' => 'ok'
225
        ];
226
227
        if ($ticketId) {
228
            $jsonResponse = new JsonResponse($responseData);
229
        } else {
230
            $jsonResponse = new JsonResponse($responseData, 500);
231
        }
232
233
        return $jsonResponse;
234
    }
235
236 View Code Duplication
    public function deleteTicketAction(Request $request)
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...
237
    {
238
        $this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE);
239
240
        $id = $request->get('ticketId');
241
        $res = $this->getDataStore()->deleteTicketById($id);
242
        if ($res) {
243
            $jsonResponse = new JsonResponse(['ok' => 'ok']);
244
        } else {
245
            $jsonResponse = new JsonResponse(['ok' => 'fail'], 500);
246
        }
247
248
        return $jsonResponse;
249
    }
250
251
    /**
252
     * Opaque hash that changes when new tickets are added (may cover further changes in future)
253
     *
254
     * @return JsonResponse
255
     * @throws \Doctrine\DBAL\DBALException
256
     */
257
    public function lastUpdateHashAction()
258
    {
259
        return new JsonResponse(['hash' => count($this->getDataStore()->fetchUndeletedTickets())]);
260
    }
261
262
    public function newTicketOrderAction(Request $request)
263
    {
264
        $this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE);
265
266
        $idOrder = $request->get('idOrder');
267
268
        if (!is_array($idOrder)) {
269
            throw new \InvalidArgumentException('Order must be array!');
270
        }
271
272
        $res = true;
273
        foreach ($idOrder as $offset => $id) {
274
            $res = $res && $this->getDataStore()->updateTicketOffsetById($id, $offset);
275
        }
276
        if ($res) {
277
            $jsonResponse = new JsonResponse(['ok' => 'ok']);
278
        } else {
279
            $jsonResponse = new JsonResponse(['ok' => 'fail', 'message' => 'Failed to store new sort order'], 500);
280
        }
281
282
        return $jsonResponse;
283
    }
284
}
285