PollController::lockAction()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 9.0168
c 0
b 0
f 0
cc 5
nc 4
nop 1
1
<?php
2
/*
3
 * Copyright 2014-2018 Arnaud Bienvenu
4
 *
5
 * This file is part of Kyela.
6
7
 * Kyela is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
12
 * Kyela is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with Kyela.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
namespace Abienvenu\KyelaBundle\Controller;
23
24
use Abienvenu\KyelaBundle\Form\Type\FormActionsType;
25
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
26
use Symfony\Component\HttpFoundation\Request;
27
use Symfony\Component\Routing\Annotation\Route;
28
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
29
use Abienvenu\KyelaBundle\Entity\Poll;
30
use Abienvenu\KyelaBundle\Entity\Choice;
31
use Abienvenu\KyelaBundle\Entity\Participant;
32
use Abienvenu\KyelaBundle\Form\Type\PollType;
33
use Abienvenu\KyelaBundle\Form\Type\NewPollType;
34
use Abienvenu\KyelaBundle\Form\Type\LockPollType;
35
use Abienvenu\KyelaBundle\Form\Type\ParticipantType;
36
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
37
38
/**
39
 * Poll controller.
40
 *
41
 * @Route("/")
42
 */
43
class PollController extends CRUDController
44
{
45
    protected $entityName = 'KyelaBundle:Poll';
46
    protected $cancelRoute = 'poll_show';
47
    protected $successRoute = 'poll_show';
48
    protected $deleteRoute = 'poll_delete';
49
    protected $deleteSuccessRoute = 'poll_new';
50
51
    /**
52
     * Displays a form to create a new Poll entity.
53
     *
54
     * @Route("", name="poll_new", methods={"GET", "POST"})
55
     * @Template()
56
     */
57
    public function newAction(Request $request)
58
    {
59
        $poll = new Poll();
60
61
        $t = $this->get('translator');
62
        // Setup default (and hidden) values
63
        $poll->setUrl(uniqid());
64
        $poll->setTitle($t->trans('new.poll'));
65
        $poll->setHeadLines('');
66
        $poll->setBottomLines('');
67
        $poll->setAccessCode('');
68
        $poll->addChoice((new Choice)->setName($t->trans('yes'))->setValue(1)->setColor('green')->setPriority(0)->setPoll($poll)->setIcon('ok'));
69
        $poll->addChoice((new Choice)->setName($t->trans('maybe'))->setValue(0)->setColor('orange')->setPriority(1)->setPoll($poll)->setIcon('time'));
70
        $poll->addChoice((new Choice)->setName($t->trans('no'))->setValue(0)->setColor('red')->setPriority(2)->setPoll($poll)->setIcon('remove'));
71
72
        $baseUrl = $this->generateUrl('poll_show', ['pollUrl' => $poll->getUrl()], UrlGeneratorInterface::ABSOLUTE_URL);
73
        $successMessage = $this->get('translator')->trans('poll.created %url%', ['%url%' => $baseUrl]);
74
75
        return $this->doNewAction(NewPollType::class, $poll, $request, $successMessage);
76
    }
77
78
    /**
79
     * Shows the poll
80
     *
81
     * @Route("/{pollUrl}/", name="poll_show", methods="GET")
82
     * @Template()
83
     */
84
    public function showAction()
85
    {
86
        $em = $this->getDoctrine()->getManager();
87
        $hasPastEvents = count($em->getRepository('KyelaBundle:Event')->getFutureOrPastEvents($this->poll, false));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method getFutureOrPastEvents() does only exist in the following implementations of said interface: Abienvenu\KyelaBundle\Entity\EventRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
88
89
        $participant_form = $this->createForm(ParticipantType::class, new Participant(), [
90
            'action' => $this->generateUrlWithPoll('participant_new'),
91
            'method' => 'POST'
92
        ]);
93
94
        return [
95
            'poll' => $this->poll,
96
            'hasPastEvents' => $hasPastEvents,
97
            'participant_form' => $participant_form->createView(),
98
        ];
99
    }
100
101
    /**
102
     * Shows a simplified poll to be used in iframe
103
     *
104
     * @Route("/{pollUrl}/frame", name="poll_showframe", methods="GET")
105
     * @Template()
106
     */
107
    public function frameAction()
108
    {
109
        return ['poll' => $this->poll];
110
    }
111
112
    /**
113
     * Shows events only (to use withing iframes)
114
     *
115
     * @Route("/{pollUrl}/events", methods="GET")
116
     * @Template()
117
     */
118
    public function eventsAction()
119
    {
120
        return ['poll' => $this->poll];
121
    }
122
123
    /**
124
     * Shows participations only (to use withing iframes)
125
     *
126
     * @Route("/{pollUrl}/participations", methods="GET")
127
     * @Template()
128
     */
129
    public function participationsAction()
130
    {
131
        return ['poll' => $this->poll];
132
    }
133
134
    /**
135
     * Shows the poll with past events only
136
     *
137
     * @Route("/{pollUrl}/archive", name="poll_archive", methods="GET")
138
     * @Template()
139
     */
140
    public function archiveAction()
141
    {
142
        return ['poll' => $this->poll];
143
    }
144
145
    /**
146
     * Displays a form to edit an existing Poll entity.
147
     *
148
     * @Route("/{pollUrl}/edit", name="poll_edit", methods={"GET", "PUT"})
149
     * @Template()
150
     */
151
    public function editAction(Request $request, $pollUrl)
152
    {
153
        if ($this->poll->getAccessCode()) {
154
            return $this->redirect($this->generateUrl('poll_unlock', ['pollUrl' => $this->poll->getUrl()]));
155
        }
156
        $oldUrl = $this->poll->getUrl();
157
        $response = $this->doEditAction(PollType::class, $this->poll->getId(), $request);
158
        if ($request->isMethod('PUT') && $oldUrl != $this->poll->getUrl())
159
        {
160
            $baseUrl = $this->generateUrl('poll_show', ['pollUrl' => $this->poll->getUrl()], UrlGeneratorInterface::ABSOLUTE_URL);
161
            $flashMessage = $this->get('translator')->trans('poll.modified %url%', ['%url%' => $baseUrl]);
162
            $request->getSession()->getFlashBag()->add('success', $flashMessage);
163
        }
164
        return $response;
165
    }
166
167
    /**
168
     * Deletes a Poll entity.
169
     *
170
     * @Route("/{pollUrl}/", name="poll_delete", methods="DELETE")
171
     */
172
    public function deleteAction(Request $request, $pollUrl)
173
    {
174
        return $this->doDeleteAction($request, $this->poll->getId());
175
    }
176
177
    /**
178
     * Display a form to setup a lock on the Poll
179
     *
180
     * @Route("/{pollUrl}/lock", name="poll_lock", methods={"GET", "PUT"})
181
     * @Template()
182
     */
183
    public function lockAction(Request $request)
184
    {
185
        $form = $this->createForm(LockPollType::class, $this->poll, [
186
            'method' => 'PUT',
187
        ]);
188
189
        $form->add('actions', FormActionsType::class, [
190
            'buttons' => [
191
                'save' => ['type' => SubmitType::class, 'options' => ['label' => 'save']],
192
                'cancel' => ['type' => SubmitType::class, 'options' => ['label' => 'cancel', 'attr' => ['type' => 'default', 'novalidate' => true]]],
193
            ]
194
        ]);
195
196
        if ($request->isMethod('PUT') && $this->poll)
197
        {
198
            $em = $this->getDoctrine()->getManager();
199
            $form->handleRequest($request);
200
            if ($form->get('actions')->get('cancel')->isClicked()) {
201
                $em->refresh($this->poll);
202
                return $this->redirect($this->generateUrl('poll_edit', ['pollUrl' => $this->poll->getUrl()]));
203
            }
204
            if ($form->isValid()) {
205
                $em->flush();
206
                $flashMessage = $this->get('translator')->trans('poll.locked %lock%', ['%lock%' => $this->poll->getAccessCode()]);
207
                $request->getSession()->getFlashBag()->add('success', $flashMessage);
208
                return $this->redirect($this->generateUrl('poll_show', ['pollUrl' => $this->poll->getUrl()]));
209
            }
210
            else {
211
                $em->refresh($this->poll);
212
            }
213
        }
214
215
        return [
216
            'poll'   => $this->poll,
217
            'form'   => $form->createView(),
218
        ];
219
    }
220
221
    /**
222
     * Display a form to unlock the Poll
223
     *
224
     * @Route("/{pollUrl}/unlock", name="poll_unlock", methods={"GET", "PUT"})
225
     * @Template()
226
     */
227
    public function unlockAction(Request $request)
228
    {
229
        $poll = (new Poll)->setTitle("dummy")->setUrl("dummy");
230
        $form = $this->createForm(LockPollType::class, $poll, [
231
            'method' => 'PUT',
232
        ]);
233
        $form->add('actions', FormActionsType::class, [
234
            'buttons' => [
235
                'save' => ['type' => SubmitType::class, 'options' => ['label' => 'save']],
236
                'cancel' => ['type' => SubmitType::class, 'options' => ['label' => 'cancel', 'attr' => ['type' => 'default', 'novalidate' => true]]],
237
            ]
238
        ]);
239
240
        if ($request->isMethod('PUT'))
241
        {
242
            $form->handleRequest($request);
243
            if ($form->get('actions')->get('cancel')->isClicked()) {
244
                return $this->redirect($this->generateUrl('poll_show', ['pollUrl' => $this->poll->getUrl()]));
245
            }
246
            if ($form->isValid()) {
247
                if ($poll->getAccessCode() == $this->poll->getAccessCode()) {
248
                    $this->poll->setAccessCode('');
249
                    $em = $this->getDoctrine()->getManager();
250
                    $em->flush();
251
                    $flashMessage = $this->get('translator')->trans('poll.unlocked');
252
                    $request->getSession()->getFlashBag()->add('success', $flashMessage);
253
                    return $this->redirect($this->generateUrl('poll_edit', ['pollUrl' => $this->poll->getUrl()]));
254
                }
255
                else {
256
                    $flashMessage = $this->get('translator')->trans('unlock.failed');
257
                    $request->getSession()->getFlashBag()->add('success', $flashMessage);
258
                }
259
            }
260
        }
261
262
        return [
263
            'poll'   => $this->poll,
264
            'form'   => $form->createView(),
265
        ];
266
    }
267
}
268