Completed
Push — master ( 81fc34...b475f1 )
by Florian
05:11
created

ApiController::answerAction()   C

Complexity

Conditions 17
Paths 52

Size

Total Lines 56
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 32
dl 0
loc 56
rs 5.2166
c 0
b 0
f 0
cc 17
nc 52
nop 2

How to fix   Long Method    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
/*
4
 * This file is part of the feedback project.
5
 *
6
 * (c) Florian Moser <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace App\Controller;
13
14
use App\Controller\Base\BaseApiController;
15
use App\Entity\Answer;
16
use App\Entity\Event;
17
use App\Entity\Participant;
18
use App\Entity\Semester;
19
use Symfony\Component\HttpFoundation\JsonResponse;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\Routing\Annotation\Route;
22
23
/**
24
 * @Route("/api")
25
 */
26
class ApiController extends BaseApiController
27
{
28
    /**
29
     * @Route("/active", name="api_active")
30
     *
31
     * @return JsonResponse
32
     */
33
    public function activeEventAction()
34
    {
35
        $now = new \DateTime();
36
        $today = $now->format('Y-m-d');
37
        $time = $now->format('H:i');
38
39
        $events = $this->getDoctrine()->getRepository(Event::class)->findBy(['date' => $today]);
40
        foreach ($events as $event) {
41
            if ($event->getFeedbackStartTime() < $time && $event->getFeedbackEndTime() > $time) {
42
                $event->loadTemplateIfSafe($this->getParameter('PUBLIC_DIR'));
43
44
                return $this->returnEvent($event);
45
            }
46
        }
47
48
        return $this->returnEvent(null);
49
    }
50
51
    /**
52
     * @Route("/{event}/{identifier}/answers", name="api_active_answers")
53
     *
54
     * @param Event $event
55
     * @param $identifier
56
     *
57
     * @throws \Exception
58
     *
59
     * @return JsonResponse
60
     */
61
    public function activeAnswersAction(Event $event, $identifier)
62
    {
63
        if (!$this->canGiveFeedback($event)) {
64
            return $this->json([]);
65
        }
66
67
        //get participant & return answers
68
        $participant = $this->getDoctrine()->getRepository(Participant::class)->findOneBy(['event' => $event->getId(), 'identifier' => $identifier]);
69
        if ($participant !== null) {
70
            return $this->returnAnswers($participant->getAnswers());
71
        }
72
73
        return $this->json([]);
74
    }
75
76
    /**
77
     * @Route("/semesters", name="api_semesters")
78
     *
79
     * @return JsonResponse
80
     */
81
    public function semestersAction()
82
    {
83
        $semesters = $this->getDoctrine()->getRepository(Semester::class)->findBy([], ['name' => 'DESC']);
84
85
        return $this->returnSemester($semesters);
86
    }
87
88
    /**
89
     * @Route("/{event}/answer", name="api_event_answer")
90
     *
91
     * @param Request $request
92
     * @param Event $event
93
     *
94
     * @throws \Exception
95
     *
96
     * @return JsonResponse
97
     */
98
    public function answerAction(Request $request, Event $event)
99
    {
100
        if (!$this->canGiveFeedback($event)) {
101
            return $this->json(false);
102
        }
103
104
        //get request fields
105
        if (!$this->checkAllFieldsSet($request, ['identifier', 'questionIndex', 'value', 'action'], $payload)) {
106
            return $this->json(false);
107
        }
108
109
        //write fields
110
        $identifier = $payload->identifier;
111
        $questionIndex = $payload->questionIndex;
112
        $value = $payload->value;
113
        $action = $payload->action;
114
        $private = property_exists($payload, 'private') && $payload->private === 'true';
115
116
        //ensure all fields set & valid
117
        if (!isset($identifier) || !\is_int($questionIndex) || !isset($value) || !\in_array($action, ['override', 'ensure_value_exists', 'remove_value'], true)) {
118
            return $this->json(false);
119
        }
120
121
        //get participant or create a new one
122
        $participant = $this->getDoctrine()->getRepository(Participant::class)->findOneBy(['identifier' => $identifier, 'event' => $event->getId()]);
123
        if ($participant === null) {
124
            $participant = new Participant();
125
            $participant->setEvent($event);
126
            $participant->setIdentifier($identifier);
127
            $this->fastSave($participant);
128
        }
129
130
        //try to find existing answer
131
        $conditions = ['questionIndex' => $questionIndex, 'participant' => $participant->getId()];
132
        if ($action === 'ensure_value_exists' || $action === 'remove_value') {
133
            $conditions += ['value' => $value];
134
        }
135
        $answer = $this->getDoctrine()->getRepository(Answer::class)->findOneBy($conditions);
136
137
        //create new of not found && not want to remove
138
        if ($answer === null && $action !== 'remove_value') {
139
            $answer = new Answer();
140
            $answer->setParticipant($participant);
141
            $answer->setPrivate($private);
142
            $answer->setQuestionIndex($questionIndex);
143
        }
144
        $answer->setValue($value);
145
146
        //process actions
147
        if ($action === 'override' || $action === 'ensure_value_exists') {
148
            $this->fastSave($answer);
149
        } elseif ($action === 'remove_value' && $answer !== null) {
150
            $this->fastRemove($answer);
151
        }
152
153
        return $this->json(true);
154
    }
155
156
    /**
157
     * @Route("/{event}/finish", name="api_event_finish")
158
     *
159
     * @param Request $request
160
     * @param Event $event
161
     *
162
     * @throws \Exception
163
     *
164
     * @return JsonResponse
165
     */
166
    public function finishAction(Request $request, Event $event)
167
    {
168
        if (!$this->canGiveFeedback($event)) {
169
            return $this->json(1);
170
        }
171
172
        if (!$this->checkAllFieldsSet($request, ['identifier', 'timeNeededInSeconds'], $payload)) {
173
            return $this->json(false);
174
        }
175
176
        //write fields
177
        $identifier = $payload->identifier;
178
        $timeNeededInSeconds = (int)$payload->timeNeededInSeconds;
179
180
        //get participant
181
        $participant = $this->getDoctrine()->getRepository(Participant::class)->findOneBy(['identifier' => $identifier, 'event' => $event->getId()]);
182
        if ($participant === null || $participant->getTimeNeededInSeconds() !== null) {
183
            return $this->json(false);
184
        }
185
186
        //set time info
187
        $participant->setTimeNeededInSeconds($timeNeededInSeconds);
188
        $this->fastSave($participant);
189
190
        return $this->json(true);
191
    }
192
193
    /**
194
     * @param Request $request
195
     * @param string[] $requiredFields
196
     * @param string[] $payload
197
     *
198
     * @return bool
199
     */
200
    private function checkAllFieldsSet(Request $request, array $requiredFields, &$payload)
201
    {
202
        //get request fields
203
        $payload = json_decode($request->getContent());
204
        foreach ($requiredFields as $requiredField) {
205
            if (!property_exists($payload, $requiredField)) {
206
                return false;
207
            }
208
        }
209
210
        return true;
211
    }
212
213
    /**
214
     * @param Event $event
215
     *
216
     * @throws \Exception
217
     *
218
     * @return bool
219
     */
220
    private function canGiveFeedback(Event $event)
221
    {
222
        //prevent hand in too early
223
        if (!$event->feedbackHasStarted()) {
224
            return false;
225
        }
226
227
        //prevent hand in on other days
228
        $now = new \DateTime();
229
        $today = $now->format('Y-m-d');
230
        if ($today !== $event->getDate()) {
231
            return false;
232
        }
233
234
        //prevent hand in too late
235
        $currentTime = $now->format('H:i');
236
        $eventEndTime = \DateTime::createFromFormat('H:i:s', $event->getFeedbackEndTime());
237
        //allow additional 1 hour to hand in after the feedback has been closed
238
        $threshold = $eventEndTime->add(new \DateInterval('PT1H'))->format('H:i');
239
        //prevent if current time higher than threshold & threshold has not done a wrap around
240
        if ($currentTime > $threshold && $event->getFeedbackEndTime() < $threshold) {
241
            return false;
242
        }
243
244
        return true;
245
    }
246
}
247