AdminObjectAclManipulator::buildAcl()   F
last analyzed

Complexity

Conditions 19
Paths 228

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 63
rs 3.3333
c 0
b 0
f 0
cc 19
nc 228
nop 3

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
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Util;
15
16
use Sonata\AdminBundle\Form\Type\AclMatrixType;
17
use Symfony\Component\Form\Extension\Core\Type\FormType;
18
use Symfony\Component\Form\Form;
19
use Symfony\Component\Form\FormBuilderInterface;
20
use Symfony\Component\Form\FormFactoryInterface;
21
use Symfony\Component\Form\FormInterface;
22
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
23
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
24
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
25
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
26
use Symfony\Component\Security\Core\User\UserInterface;
27
28
/**
29
 * A manipulator for updating ACL related to an object.
30
 *
31
 * @final since sonata-project/admin-bundle 3.52
32
 *
33
 * @author Kévin Dunglas <[email protected]>
34
 * @author Baptiste Meyer <[email protected]>
35
 */
36
class AdminObjectAclManipulator
37
{
38
    public const ACL_USERS_FORM_NAME = 'acl_users_form';
39
    public const ACL_ROLES_FORM_NAME = 'acl_roles_form';
40
41
    /**
42
     * @var FormFactoryInterface
43
     */
44
    protected $formFactory;
45
    /**
46
     * @var string
47
     */
48
    protected $maskBuilderClass;
49
50
    /**
51
     * @param string $maskBuilderClass
52
     */
53
    public function __construct(FormFactoryInterface $formFactory, $maskBuilderClass)
54
    {
55
        $this->formFactory = $formFactory;
56
        $this->maskBuilderClass = $maskBuilderClass;
57
    }
58
59
    /**
60
     * Gets mask builder class name.
61
     *
62
     * @return string
63
     */
64
    public function getMaskBuilderClass()
65
    {
66
        return $this->maskBuilderClass;
67
    }
68
69
    /**
70
     * Gets the ACL users form.
71
     *
72
     * @return FormInterface
73
     */
74
    public function createAclUsersForm(AdminObjectAclData $data)
75
    {
76
        $aclValues = $data->getAclUsers();
77
        $formBuilder = $this->formFactory->createNamedBuilder(self::ACL_USERS_FORM_NAME, FormType::class);
78
        $form = $this->buildForm($data, $formBuilder, $aclValues);
79
        $data->setAclUsersForm($form);
80
81
        return $form;
82
    }
83
84
    /**
85
     * Gets the ACL roles form.
86
     *
87
     * @return FormInterface
88
     */
89
    public function createAclRolesForm(AdminObjectAclData $data)
90
    {
91
        $aclValues = $data->getAclRoles();
92
        $formBuilder = $this->formFactory->createNamedBuilder(self::ACL_ROLES_FORM_NAME, FormType::class);
93
        $form = $this->buildForm($data, $formBuilder, $aclValues);
94
        $data->setAclRolesForm($form);
95
96
        return $form;
97
    }
98
99
    /**
100
     * Updates ACL users.
101
     */
102
    public function updateAclUsers(AdminObjectAclData $data): void
103
    {
104
        $aclValues = $data->getAclUsers();
105
        $form = $data->getAclUsersForm();
106
107
        $this->buildAcl($data, $form, $aclValues);
108
    }
109
110
    /**
111
     * Updates ACL roles.
112
     */
113
    public function updateAclRoles(AdminObjectAclData $data): void
114
    {
115
        $aclValues = $data->getAclRoles();
116
        $form = $data->getAclRolesForm();
117
118
        $this->buildAcl($data, $form, $aclValues);
119
    }
120
121
    /**
122
     * Builds ACL.
123
     */
124
    protected function buildAcl(AdminObjectAclData $data, FormInterface $form, \Traversable $aclValues): void
125
    {
126
        $masks = $data->getMasks();
127
        $acl = $data->getAcl();
128
        $matrices = $form->getData();
129
130
        foreach ($aclValues as $aclValue) {
131
            foreach ($matrices as $key => $matrix) {
132
                if ($aclValue instanceof UserInterface) {
133
                    if (\array_key_exists('user', $matrix) && $aclValue->getUsername() === $matrix['user']) {
134
                        $matrices[$key]['acl_value'] = $aclValue;
135
                    }
136
                } elseif (\array_key_exists('role', $matrix) && $aclValue === $matrix['role']) {
137
                    $matrices[$key]['acl_value'] = $aclValue;
138
                }
139
            }
140
        }
141
142
        foreach ($matrices as $matrix) {
143
            if (!isset($matrix['acl_value'])) {
144
                continue;
145
            }
146
147
            $securityIdentity = $this->getSecurityIdentity($matrix['acl_value']);
148
            $maskBuilder = new $this->maskBuilderClass();
149
150
            foreach ($data->getUserPermissions() as $permission) {
151
                if (isset($matrix[$permission]) && true === $matrix[$permission]) {
152
                    $maskBuilder->add($permission);
153
                }
154
            }
155
156
            // Restore OWNER and MASTER permissions
157
            if (!$data->isOwner()) {
158
                foreach ($data->getOwnerPermissions() as $permission) {
159
                    if ($acl->isGranted([$masks[$permission]], [$securityIdentity])) {
160
                        $maskBuilder->add($permission);
161
                    }
162
                }
163
            }
164
165
            $mask = $maskBuilder->get();
166
167
            $index = null;
168
            $ace = null;
169
            foreach ($acl->getObjectAces() as $currentIndex => $currentAce) {
170
                if ($currentAce->getSecurityIdentity()->equals($securityIdentity)) {
171
                    $index = $currentIndex;
172
                    $ace = $currentAce;
173
174
                    break;
175
                }
176
            }
177
178
            if ($ace) {
179
                $acl->updateObjectAce($index, $mask);
180
            } else {
181
                $acl->insertObjectAce($securityIdentity, $mask);
182
            }
183
        }
184
185
        $data->getSecurityHandler()->updateAcl($acl);
186
    }
187
188
    /**
189
     * Builds the form.
190
     *
191
     * @return FormInterface
192
     */
193
    protected function buildForm(AdminObjectAclData $data, FormBuilderInterface $formBuilder, \Traversable $aclValues)
194
    {
195
        // Retrieve object identity
196
        $objectIdentity = ObjectIdentity::fromDomainObject($data->getObject());
197
        $acl = $data->getSecurityHandler()->getObjectAcl($objectIdentity);
198
        if (!$acl) {
199
            $acl = $data->getSecurityHandler()->createAcl($objectIdentity);
200
        }
201
202
        $data->setAcl($acl);
203
204
        $masks = $data->getMasks();
205
        $securityInformation = $data->getSecurityInformation();
206
207
        foreach ($aclValues as $key => $aclValue) {
208
            $securityIdentity = $this->getSecurityIdentity($aclValue);
209
            $permissions = [];
210
211
            foreach ($data->getUserPermissions() as $permission) {
212
                try {
213
                    $checked = $acl->isGranted([$masks[$permission]], [$securityIdentity]);
214
                } catch (NoAceFoundException $e) {
215
                    $checked = false;
216
                }
217
218
                $attr = [];
219
                if (
220
                    self::ACL_ROLES_FORM_NAME === $formBuilder->getName()
221
                    && isset($securityInformation[$aclValue])
222
                    && false !== array_search($permission, $securityInformation[$aclValue], true)
223
                ) {
224
                    $attr['disabled'] = 'disabled';
225
                }
226
227
                $permissions[$permission] = [
228
                    'required' => false,
229
                    'data' => $checked,
230
                    'disabled' => \array_key_exists('disabled', $attr),
231
                    'attr' => $attr,
232
                ];
233
            }
234
235
            $formBuilder->add(
236
                $key,
237
                AclMatrixType::class,
238
                ['permissions' => $permissions, 'acl_value' => $aclValue]
239
            );
240
        }
241
242
        return $formBuilder->getForm();
243
    }
244
245
    /**
246
     * Gets a user or a role security identity.
247
     *
248
     * @param string|UserInterface $aclValue
249
     *
250
     * @return RoleSecurityIdentity|UserSecurityIdentity
251
     */
252
    protected function getSecurityIdentity($aclValue)
253
    {
254
        return ($aclValue instanceof UserInterface)
255
            ? UserSecurityIdentity::fromAccount($aclValue)
256
            : new RoleSecurityIdentity($aclValue)
257
        ;
258
    }
259
}
260