Completed
Push — master ( a7cf71...06c6ea )
by Craig
06:43
created

MembershipAdministrationController::addAction()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 29
Code Lines 19

Duplication

Lines 8
Ratio 27.59 %

Importance

Changes 0
Metric Value
cc 5
eloc 19
nc 5
nop 3
dl 8
loc 29
rs 8.439
c 0
b 0
f 0
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\GroupEvents;
25
use Zikula\ThemeModule\Engine\Annotation\Theme;
26
use Zikula\UsersModule\Constant as UsersConstant;
27
use Zikula\UsersModule\Entity\UserEntity;
28
29
/**
30
 * @Route("/admin/membership")
31
 *
32
 * Administrative controllers for the groups module
33
 */
34
class MembershipAdministrationController extends AbstractController
35
{
36
    /**
37
     * @Route("/list/{gid}/{letter}/{startNum}", requirements={"gid" = "^[1-9]\d*$", "letter" = "[a-zA-Z]|\*", "startNum" = "\d+"})
38
     * @Method("GET")
39
     * @Theme("admin")
40
     * @Template
41
     *
42
     * Display all members of a group.
43
     *
44
     * @param integer $gid the id of the group to list membership for
45
     * @param string $letter the letter from the alpha filter
46
     * @param integer $startNum the start item number for the pager
47
     *
48
     * @return array
49
     *
50
     * @throws \InvalidArgumentException Thrown if the requested group id is invalid
51
     * @throws AccessDeniedException Thrown if the user doesn't have edit access to the group
52
     */
53
    public function listAction($gid = 0, $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...
54
    {
55
        if (!$this->hasPermission('ZikulaGroupsModule::', $gid . '::', ACCESS_EDIT)) {
56
            throw new AccessDeniedException();
57
        }
58
        $group = $this->get('zikula_groups_module.group_repository')->find($gid);
59
        if (!$group) {
60
            throw new \InvalidArgumentException($this->__('Invalid Group ID.'));
61
        }
62
63
        return [
64
            'group' => $group,
65
//            'pager' => [
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% 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...
66
//                'amountOfItems' => count($usersNotInGroup),
67
//                'itemsPerPage' => $this->getVar('itemsperpage', 25);
68
//            ],
69
            'csrfToken' => $this->get('zikula_core.common.csrf_token_handler')->generate()
70
        ];
71
    }
72
73
    /**
74
     * @Route("/add/{uid}/{gid}/{csrfToken}", requirements={"gid" = "^[1-9]\d*$", "uid" = "^[1-9]\d*$"})
75
     *
76
     * Add user to a group.
77
     *
78
     * @param $uid
79
     * @param $gid
80
     * @param $csrfToken
81
     * @return RedirectResponse
82
     */
83
    public function addAction($uid, $gid, $csrfToken)
84
    {
85
        $this->get('zikula_core.common.csrf_token_handler')->validate($csrfToken);
86
        if (!$this->hasPermission('ZikulaGroupsModule::', $gid . '::', ACCESS_EDIT)) {
87
            throw new AccessDeniedException();
88
        }
89
        $group = $this->get('zikula_groups_module.group_repository')->find($gid);
90
        if (!$group) {
91
            throw new \InvalidArgumentException($this->__('Invalid Group ID.'));
92
        }
93
        /** @var UserEntity $userEntity */
94
        $userEntity = $this->get('zikula_users_module.user_repository')->find($uid);
95
        if (!$userEntity) {
96
            throw new \InvalidArgumentException($this->__('Invalid User ID.'));
97
        }
98
99
        if ($userEntity->getGroups()->contains($group)) {
100
            $this->addFlash('warning', $this->__('The selected user is already a member of this group.'));
101 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...
102
            $userEntity->addGroup($group);
103
            $this->get('doctrine')->getManager()->flush();
104
            $this->addFlash('status', $this->__('Done! The user was added to the group.'));
105
            // Let other modules know that we have updated a group.
106
            $adduserEvent = new GenericEvent(['gid' => $gid, 'uid' => $uid]);
107
            $this->get('event_dispatcher')->dispatch(GroupEvents::GROUP_ADD_USER, $adduserEvent);
108
        }
109
110
        return $this->redirectToRoute('zikulagroupsmodule_membershipadministration_list', ['gid' => $gid]);
111
    }
112
113
    /**
114
     * @Route("/remove/{gid}/{uid}", requirements={"gid" = "^[1-9]\d*$", "uid" = "^[1-9]\d*$"})
115
     * @Theme("admin")
116
     * @Template
117
     *
118
     * Remove a user from a group.
119
     *
120
     * @param Request $request
121
     * @param int $gid
122
     * @param int $uid
123
     * @return mixed Response|void symfony response object if confirmation isn't provided, void otherwise
124
     */
125
    public function removeAction(Request $request, $gid = 0, $uid = 0)
126
    {
127
        if ($request->isMethod('POST')) {
128
            $postVars = $request->request->get('zikulagroupsmodule_removeuser');
129
            $gid = isset($postVars['gid']) ? $postVars['gid'] : 0;
130
            $uid = isset($postVars['uid']) ? $postVars['uid'] : 0;
131
        }
132
        if ($gid < 1 || $uid < 1) {
133
            throw new \InvalidArgumentException($this->__('Invalid Group ID or User ID.'));
134
        }
135
        if (!$this->hasPermission('ZikulaGroupsModule::', $gid.'::', ACCESS_EDIT)) {
136
            throw new AccessDeniedException();
137
        }
138
        $group = $this->get('zikula_groups_module.group_repository')->find($gid);
139
        if (!$group) {
140
            throw new \InvalidArgumentException($this->__('Invalid Group ID.'));
141
        }
142
        $user = $this->get('zikula_users_module.user_repository')->find($uid);
143
        if (!$user) {
144
            throw new \InvalidArgumentException($this->__('Invalid User ID.'));
145
        }
146
147
        $form = $this->createForm('Zikula\GroupsModule\Form\Type\RemoveUserType', [
148
            'gid' => $gid,
149
            'uid' => $uid
150
        ], [
151
            'translator' => $this->get('translator.default')
152
        ]);
153
154
        if ($form->handleRequest($request)->isValid()) {
155
            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...
156
                $user->removeGroup($group);
157
                $this->get('doctrine')->getManager()->flush();
158
                $this->addFlash('status', $this->__('Done! The user was removed from the group.'));
159
                $removeuserEvent = new GenericEvent(null, ['gid' => $gid, 'uid' => $uid]);
160
                $this->get('event_dispatcher')->dispatch(GroupEvents::GROUP_REMOVE_USER, $removeuserEvent);
161
            }
162
            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...
163
                $this->addFlash('status', $this->__('Operation cancelled.'));
164
            }
165
166
            return $this->redirectToRoute('zikulagroupsmodule_membershipadministration_list', ['gid' => $group->getGid()]);
167
        }
168
169
        return [
170
            'form' => $form->createView(),
171
            'group' => $group,
172
            'uname' => $user->getUname()
173
        ];
174
    }
175
176
    /**
177
     * Called from UsersModule/Resources/public/js/Zikula.Users.Admin.View.js
178
     * to populate a username search
179
     *
180
     * @Route("/getusersbyfragmentastable", options={"expose"=true})
181
     * @Method("POST")
182
     * @param Request $request
183
     * @return Response
184
     */
185
    public function getUsersByFragmentAsTableAction(Request $request)
186
    {
187
        if (!$this->hasPermission('ZikulaGroupsodule', '::', ACCESS_MODERATE)) {
188
            return new PlainResponse('');
189
        }
190
        $fragment = $request->request->get('fragment');
191
        $filter = [
192
            'activated' => ['operator' => 'notIn', 'operand' => [
193
                UsersConstant::ACTIVATED_PENDING_REG,
194
                UsersConstant::ACTIVATED_PENDING_DELETE
195
            ]],
196
            'uname' => ['operator' => 'like', 'operand' => "$fragment%"]
197
        ];
198
        $users = $this->get('zikula_users_module.user_repository')->query($filter);
199
200
        return $this->render('@ZikulaGroupsModule/MembershipAdministration/userlist.html.twig', [
201
            'users' => $users,
202
            'gid' => $request->get('gid'),
203
            'csrfToken' => $request->get('csrfToken')
204
        ], new PlainResponse());
205
    }
206
}
207