Completed
Push — master ( f5c851...12cc61 )
by Craig
07:00
created

MembershipController::removeAction()   C

Complexity

Conditions 12
Paths 45

Size

Total Lines 50
Code Lines 33

Duplication

Lines 7
Ratio 14 %

Importance

Changes 0
Metric Value
cc 12
eloc 33
c 0
b 0
f 0
nc 45
nop 3
dl 7
loc 50
rs 5.3904

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
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
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 Zikula\GroupsModule\Controller;
13
14
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
15
use Symfony\Component\HttpFoundation\Request;
16
use Symfony\Component\HttpFoundation\Response;
17
use Symfony\Component\HttpFoundation\RedirectResponse;
18
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
19
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
20
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
21
use Zikula\Core\Controller\AbstractController;
22
use Zikula\Core\Event\GenericEvent;
23
use Zikula\Core\Response\PlainResponse;
24
use Zikula\GroupsModule\Entity\GroupEntity;
25
use Zikula\GroupsModule\GroupEvents;
26
use Zikula\GroupsModule\Helper\CommonHelper;
27
use Zikula\ThemeModule\Engine\Annotation\Theme;
28
use Zikula\UsersModule\Constant as UsersConstant;
29
use Zikula\UsersModule\Entity\UserEntity;
30
31
/**
32
 * @Route("/membership")
33
 *
34
 * Administrative controllers for the groups module
35
 */
36
class MembershipController extends AbstractController
37
{
38
    /**
39
     * @Route("/list/{gid}/{letter}/{startNum}", requirements={"gid" = "^[1-9]\d*$", "letter" = "[a-zA-Z]|\*", "startNum" = "\d+"})
40
     * @Method("GET")
41
     * @Template
42
     *
43
     * Display all members of a group to a user
44
     *
45
     * @param GroupEntity $group
46
     * @param string $letter the letter from the alpha filter
47
     * @param integer $startNum the start item number for the pager
48
     * @return array
49
     */
50
    public function listAction(GroupEntity $group, $letter = '*', $startNum = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $letter is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $startNum is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
51
    {
52
        if (!$this->hasPermission('ZikulaGroupsModule::memberslist', '::', ACCESS_OVERVIEW)) {
53
            throw new AccessDeniedException();
54
        }
55
        $groupsCommon = new CommonHelper($this->getTranslator());
56
        $inactiveLimit = $this->get('zikula_extensions_module.api.variable')->getSystemVar('secinactivemins');
57
        $dateTime = new \DateTime();
58
        $dateTime->modify('-' . $inactiveLimit . 'minutes');
59
60
        return [
61
            'group' => $group,
62
            'groupTypes' => $groupsCommon->gtypeLabels(),
63
            'states' => $groupsCommon->stateLabels(),
64
            'usersOnline' => $this->get('zikula_users_module.user_session_repository')->getUsersSince($dateTime),
65
            'pager' => [
66
                'amountOfItems' => $group->getUsers()->count(),
67
                'itemsPerPage' => $this->getVar('itemsperpage', 25)
68
            ],
69
        ];
70
    }
71
72
    /**
73
     * @Route("/admin/list/{gid}/{letter}/{startNum}", requirements={"gid" = "^[1-9]\d*$", "letter" = "[a-zA-Z]|\*", "startNum" = "\d+"})
74
     * @Method("GET")
75
     * @Theme("admin")
76
     * @Template
77
     *
78
     * Display all members of a group to an admin
79
     *
80
     * @param GroupEntity $group
81
     * @param string $letter the letter from the alpha filter
82
     * @param integer $startNum the start item number for the pager
83
     * @return array
84
     */
85
    public function adminListAction(GroupEntity $group, $letter = '*', $startNum = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $letter is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $startNum is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
86
    {
87
        if (!$this->hasPermission('ZikulaGroupsModule::', $group->getGid() . '::', ACCESS_EDIT)) {
88
            throw new AccessDeniedException();
89
        }
90
91
        return [
92
            'group' => $group,
93
            'pager' => [
94
                'amountOfItems' => $group->getUsers()->count(),
95
                'itemsPerPage' => $this->getVar('itemsperpage', 25)
96
            ],
97
            'csrfToken' => $this->get('zikula_core.common.csrf_token_handler')->generate()
98
        ];
99
    }
100
101
    /**
102
     * @Route("/admin/add/{uid}/{gid}/{csrfToken}", requirements={"gid" = "^[1-9]\d*$", "uid" = "^[1-9]\d*$"})
103
     *
104
     * Add user to a group.
105
     *
106
     * @param UserEntity $userEntity
107
     * @param GroupEntity $group
108
     * @param $csrfToken
109
     * @return RedirectResponse
110
     */
111
    public function addAction(UserEntity $userEntity, GroupEntity $group, $csrfToken)
112
    {
113
        $this->get('zikula_core.common.csrf_token_handler')->validate($csrfToken);
114
        if (!$this->hasPermission('ZikulaGroupsModule::', $group->getGid() . '::', ACCESS_EDIT)) {
115
            throw new AccessDeniedException();
116
        }
117
118
        if ($userEntity->getGroups()->contains($group)) {
119
            $this->addFlash('warning', $this->__('The selected user is already a member of this group.'));
120 View Code Duplication
        } else {
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...
121
            $userEntity->addGroup($group);
122
            $this->get('doctrine')->getManager()->flush();
123
            $this->addFlash('status', $this->__('Done! The user was added to the group.'));
124
            // Let other modules know that we have updated a group.
125
            $addUserEvent = new GenericEvent(['gid' => $group->getGid(), 'uid' => $userEntity->getUid()]);
126
            $this->get('event_dispatcher')->dispatch(GroupEvents::GROUP_ADD_USER, $addUserEvent);
127
        }
128
129
        return $this->redirectToRoute('zikulagroupsmodule_membership_adminlist', ['gid' => $group->getGid()]);
130
    }
131
132
    /**
133
     * Process request by the current user to join a group
134
     * @Route("/join/{gid}", requirements={"gid" = "^[1-9]\d*$"})
135
     * @param GroupEntity $group
136
     * @return RedirectResponse
137
     */
138
    public function joinAction(GroupEntity $group)
139
    {
140
        if (!$this->hasPermission('ZikulaGroupsModule::', '::', ACCESS_OVERVIEW)) {
141
            throw new AccessDeniedException();
142
        }
143
        $currentUserApi = $this->get('zikula_users_module.current_user');
144
        if (!$currentUserApi->isLoggedIn()) {
145
            throw new AccessDeniedException($this->__('Sorry! You must register for a user account on this site before you can join a group.'));
146
        }
147
        /** @var UserEntity $userEntity */
148
        $userEntity = $this->get('zikula_users_module.user_repository')->find($currentUserApi->get('uid'));
149
        if (($group->getGtype() == CommonHelper::GTYPE_PRIVATE)
150
            || ($group->getGtype() == CommonHelper::GTYPE_CORE)
151
            || ($group->getState() == CommonHelper::STATE_CLOSED)
152
            || ($group->getNbumax() > 0 && $group->getUsers()->count() > $group->getNbumax())
153
            || ($group->getUsers()->contains($userEntity))) {
154
            $this->addFlash('error', $this->__('Cannot join the requested group')); // @todo more specific info would be better
155 View Code Duplication
        } else {
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...
156
            $userEntity->addGroup($group);
157
            $this->get('doctrine')->getManager()->flush();
158
            $this->addFlash('success', $this->__f('Joined the "%group" group', ['%group' => $group->getName()]));
159
            // Let other modules know that we have updated a group.
160
            $addUserEvent = new GenericEvent(['gid' => $group->getGid(), 'uid' => $userEntity->getUid()]);
161
            $this->get('event_dispatcher')->dispatch(GroupEvents::GROUP_ADD_USER, $addUserEvent);
162
        }
163
164
        return $this->redirectToRoute('zikulagroupsmodule_group_list');
165
    }
166
167
    /**
168
     * @Route("/admin/remove/{gid}/{uid}", requirements={"gid" = "^[1-9]\d*$", "uid" = "^[1-9]\d*$"})
169
     * @Theme("admin")
170
     * @Template
171
     *
172
     * Remove a user from a group.
173
     *
174
     * @param Request $request
175
     * @param int $gid
176
     * @param int $uid
177
     * @return mixed Response|void symfony response object if confirmation isn't provided, void otherwise
178
     */
179
    public function removeAction(Request $request, $gid = 0, $uid = 0)
180
    {
181
        if ($request->isMethod('POST')) {
182
            $postVars = $request->request->get('zikulagroupsmodule_removeuser');
183
            $gid = isset($postVars['gid']) ? $postVars['gid'] : 0;
184
            $uid = isset($postVars['uid']) ? $postVars['uid'] : 0;
185
        }
186
        if ($gid < 1 || $uid < 1) {
187
            throw new \InvalidArgumentException($this->__('Invalid Group ID or User ID.'));
188
        }
189
        if (!$this->hasPermission('ZikulaGroupsModule::', $gid.'::', ACCESS_EDIT)) {
190
            throw new AccessDeniedException();
191
        }
192
        $group = $this->get('zikula_groups_module.group_repository')->find($gid);
193
        if (!$group) {
194
            throw new \InvalidArgumentException($this->__('Invalid Group ID.'));
195
        }
196
        $user = $this->get('zikula_users_module.user_repository')->find($uid);
197
        if (!$user) {
198
            throw new \InvalidArgumentException($this->__('Invalid User ID.'));
199
        }
200
201
        $form = $this->createForm('Zikula\GroupsModule\Form\Type\RemoveUserType', [
202
            'gid' => $gid,
203
            'uid' => $uid
204
        ], [
205
            'translator' => $this->get('translator.default')
206
        ]);
207
208
        if ($form->handleRequest($request)->isValid()) {
209 View Code Duplication
            if ($form->get('remove')->isClicked()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Form\FormInterface as the method isClicked() does only exist in the following implementations of said interface: Symfony\Component\Form\SubmitButton.

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...
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...
210
                $user->removeGroup($group);
211
                $this->get('doctrine')->getManager()->flush();
212
                $this->addFlash('status', $this->__('Done! The user was removed from the group.'));
213
                $removeUserEvent = new GenericEvent(null, ['gid' => $gid, 'uid' => $uid]);
214
                $this->get('event_dispatcher')->dispatch(GroupEvents::GROUP_REMOVE_USER, $removeUserEvent);
215
            }
216
            if ($form->get('cancel')->isClicked()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Form\FormInterface as the method isClicked() does only exist in the following implementations of said interface: Symfony\Component\Form\SubmitButton.

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...
217
                $this->addFlash('status', $this->__('Operation cancelled.'));
218
            }
219
220
            return $this->redirectToRoute('zikulagroupsmodule_membership_adminlist', ['gid' => $group->getGid()]);
221
        }
222
223
        return [
224
            'form' => $form->createView(),
225
            'group' => $group,
226
            'uname' => $user->getUname()
227
        ];
228
    }
229
230
    /**
231
     * Process request by current user to leave a group
232
     * @Route("/leave/{gid}", requirements={"gid" = "^[1-9]\d*$"})
233
     * @param GroupEntity $group
234
     * @return RedirectResponse
235
     */
236
    public function leaveAction(GroupEntity $group)
237
    {
238
        if (!$this->hasPermission('ZikulaGroupsModule::', '::', ACCESS_OVERVIEW)) {
239
            throw new AccessDeniedException();
240
        }
241
        $currentUserApi = $this->get('zikula_users_module.current_user');
242
        if (!$currentUserApi->isLoggedIn()) {
243
            throw new AccessDeniedException($this->__('Sorry! You must be logged in before you can leave a group.'));
244
        }
245
        /** @var UserEntity $userEntity */
246
        $userEntity = $this->get('zikula_users_module.user_repository')->find($currentUserApi->get('uid'));
247
        $userEntity->removeGroup($group);
248
        $this->get('doctrine')->getManager()->flush();
249
        $this->addFlash('success', $this->__f('Left the "%group" group', ['%group' => $group->getName()]));
250
        // Let other modules know that we have updated a group.
251
        $removeUserEvent = new GenericEvent(['gid' => $group->getGid(), 'uid' => $userEntity->getUid()]);
252
        $this->get('event_dispatcher')->dispatch(GroupEvents::GROUP_REMOVE_USER, $removeUserEvent);
253
254
        return $this->redirectToRoute('zikulagroupsmodule_group_list');
255
    }
256
257
    /**
258
     * Called from UsersModule/Resources/public/js/Zikula.Users.Admin.View.js
259
     * to populate a username search
260
     *
261
     * @Route("/admin/getusersbyfragmentastable", options={"expose"=true})
262
     * @Method("POST")
263
     * @param Request $request
264
     * @return Response
265
     */
266
    public function getUsersByFragmentAsTableAction(Request $request)
267
    {
268
        if (!$this->hasPermission('ZikulaGroupsodule', '::', ACCESS_EDIT)) {
269
            return new PlainResponse('');
270
        }
271
        $fragment = $request->request->get('fragment');
272
        $filter = [
273
            'activated' => ['operator' => 'notIn', 'operand' => [
274
                UsersConstant::ACTIVATED_PENDING_REG,
275
                UsersConstant::ACTIVATED_PENDING_DELETE
276
            ]],
277
            'uname' => ['operator' => 'like', 'operand' => "$fragment%"]
278
        ];
279
        $users = $this->get('zikula_users_module.user_repository')->query($filter);
280
281
        return $this->render('@ZikulaGroupsModule/Membership/userlist.html.twig', [
282
            'users' => $users,
283
            'gid' => $request->get('gid'),
284
            'csrfToken' => $request->get('csrfToken')
285
        ], new PlainResponse());
286
    }
287
}
288