Completed
Push — master ( 09cee1...75eab4 )
by Gaetano
06:21
created

UserGroupManager   B

Complexity

Total Complexity 32

Size/Duplication

Total Lines 209
Duplicated Lines 36.36 %

Coupling/Cohesion

Components 1
Dependencies 16

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 16
dl 76
loc 209
ccs 0
cts 128
cp 0
rs 8.123
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B create() 10 43 6
B update() 0 55 9
A delete() 14 14 2
C matchUserGroups() 23 23 7
B getReferencesValues() 21 21 6
A setSection() 8 8 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use eZ\Publish\API\Repository\Values\Content\Content;
6
use eZ\Publish\API\Repository\Values\User\UserGroup;
7
use Kaliop\eZMigrationBundle\Core\Matcher\UserGroupMatcher;
8
use Kaliop\eZMigrationBundle\API\Collection\UserGroupCollection;
9
use Kaliop\eZMigrationBundle\Core\Matcher\RoleMatcher;
10
use Kaliop\eZMigrationBundle\Core\Matcher\SectionMatcher;
11
12
/**
13
 * Handles user-group migrations.
14
 */
15
class UserGroupManager extends RepositoryExecutor
16
{
17
    protected $supportedStepTypes = array('user_group');
18
19
    protected $userGroupMatcher;
20
    protected $roleMatcher;
21
    protected $sectionMatcher;
22
23
    public function __construct(UserGroupMatcher $userGroupMatcher, RoleMatcher $roleMatcher, SectionMatcher $sectionMatcher)
24
    {
25
        $this->userGroupMatcher = $userGroupMatcher;
26
        $this->roleMatcher = $roleMatcher;
27
        $this->sectionMatcher = $sectionMatcher;
28
    }
29
30
    /**
31
     * Method to handle the create operation of the migration instructions
32
     */
33
    protected function create($step)
34
    {
35
        $userService = $this->repository->getUserService();
36
37
        $parentGroupId = $step->dsl['parent_group_id'];
38
        $parentGroupId = $this->referenceResolver->resolveReference($parentGroupId);
39
        $parentGroup = $this->userGroupMatcher->matchOneByKey($parentGroupId);
40
41
        $contentType = $this->repository->getContentTypeService()->loadContentTypeByIdentifier("user_group");
42
43
        $userGroupCreateStruct = $userService->newUserGroupCreateStruct($this->getLanguageCode($step), $contentType);
44
        $userGroupCreateStruct->setField('name', $step->dsl['name']);
45
46
        if (isset($step->dsl['remote_id'])) {
47
            $userGroupCreateStruct->remoteId = $step->dsl['remote_id'];
48
        }
49
50
        if (isset($step->dsl['description'])) {
51
            $userGroupCreateStruct->setField('description', $step->dsl['description']);
52
        }
53
54 View Code Duplication
        if (isset($step->dsl['section'])) {
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...
55
            $sectionKey = $this->referenceResolver->resolveReference($step->dsl['section']);
56
            $section = $this->sectionMatcher->matchOneByKey($sectionKey);
57
            $userGroupCreateStruct->sectionId = $section->id;
58
        }
59
60
        $userGroup = $userService->createUserGroup($userGroupCreateStruct, $parentGroup);
61
62
        if (isset($step->dsl['roles'])) {
63
            $roleService = $this->repository->getRoleService();
64
            // we support both Ids and Identifiers
65 View Code Duplication
            foreach ($step->dsl['roles'] as $roleId) {
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...
66
                $roleId = $this->referenceResolver->resolveReference($roleId);
67
                $role = $this->roleMatcher->matchOneByKey($roleId);
68
                $roleService->assignRoleToUserGroup($role, $userGroup);
69
            }
70
        }
71
72
        $this->setReferences($userGroup, $step);
0 ignored issues
show
Documentation introduced by
$userGroup is of type object<eZ\Publish\API\Re...\Values\User\UserGroup>, but the function expects a object<Object>|object<Ka...ctCollectionCollection>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
73
74
        return $userGroup;
75
    }
76
77
    /**
78
     * Method to handle the update operation of the migration instructions
79
     *
80
     * @throws \Exception When the ID of the user group is missing from the migration definition.
81
     */
82
    protected function update($step)
83
    {
84
        $userGroupCollection = $this->matchUserGroups('update', $step);
85
86
        if (count($userGroupCollection) > 1 && isset($step->dsl['references'])) {
87
            throw new \Exception("Can not execute Group update because multiple groups match, and a references section is specified in the dsl. References can be set when only 1 group matches");
88
        }
89
90
        $userService = $this->repository->getUserService();
91
        $contentService = $this->repository->getContentService();
92
93
        foreach ($userGroupCollection as $key => $userGroup) {
0 ignored issues
show
Bug introduced by
The expression $userGroupCollection of type object<Kaliop\eZMigratio...erGroupCollection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
94
95
            /** @var $updateStruct \eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct */
96
            $updateStruct = $userService->newUserGroupUpdateStruct();
97
98
            /** @var $contentUpdateStruct \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct */
99
            $contentUpdateStruct = $contentService->newContentUpdateStruct();
100
101
            if (isset($step->dsl['name'])) {
102
                $contentUpdateStruct->setField('name', $step->dsl['name']);
103
            }
104
105
            if (isset($step->dsl['remote_id'])) {
106
                $contentUpdateStruct->remoteId = $step->dsl['remote_id'];
107
            }
108
109
            if (isset($step->dsl['description'])) {
110
                $contentUpdateStruct->setField('description', $step->dsl['description']);
111
            }
112
113
            $updateStruct->contentUpdateStruct = $contentUpdateStruct;
114
115
            $userGroup = $userService->updateUserGroup($userGroup, $updateStruct);
116
117
            if (isset($step->dsl['parent_group_id'])) {
118
                $parentGroupId = $step->dsl['parent_group_id'];
119
                $parentGroupId = $this->referenceResolver->resolveReference($parentGroupId);
120
                $newParentGroup = $this->userGroupMatcher->matchOneByKey($parentGroupId);
121
122
                // Move group to new parent
123
                $userService->moveUserGroup($userGroup, $newParentGroup);
124
            }
125
126
            if (isset($step->dsl['section'])) {
127
                $this->setSection($userGroup, $step->dsl['section']);
128
            }
129
130
            $userGroupCollection[$key] = $userGroup;
131
        }
132
133
        $this->setReferences($userGroupCollection, $step);
0 ignored issues
show
Documentation introduced by
$userGroupCollection is of type object<Kaliop\eZMigratio...erGroupCollection>|null, but the function expects a object<Object>|object<Ka...ctCollectionCollection>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
134
135
        return $userGroupCollection;
136
    }
137
138
    /**
139
     * Method to handle the delete operation of the migration instructions
140
     *
141
     * @throws \Exception When there are no groups specified for deletion.
142
     */
143 View Code Duplication
    protected function delete($step)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
144
    {
145
        $userGroupCollection = $this->matchUserGroups('delete', $step);
146
147
        $this->setReferences($userGroupCollection, $step);
0 ignored issues
show
Documentation introduced by
$userGroupCollection is of type object<Kaliop\eZMigratio...erGroupCollection>|null, but the function expects a object<Object>|object<Ka...ctCollectionCollection>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
148
149
        $userService = $this->repository->getUserService();
150
151
        foreach ($userGroupCollection as $userGroup) {
0 ignored issues
show
Bug introduced by
The expression $userGroupCollection of type object<Kaliop\eZMigratio...erGroupCollection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
152
            $userService->deleteUserGroup($userGroup);
153
        }
154
155
        return $userGroupCollection;
156
    }
157
158
    /**
159
     * @param string $action
160
     * @return UserGroupCollection
161
     * @throws \Exception
162
     */
163 View Code Duplication
    protected function matchUserGroups($action, $step)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
164
    {
165
        if (!isset($step->dsl['id']) && !isset($step->dsl['group']) && !isset($step->dsl['match'])) {
166
            throw new \Exception("The id of a user group or a match condition is required to $action it");
167
        }
168
169
        // Backwards compat
170
        if (isset($step->dsl['match'])) {
171
            $match = $step->dsl['match'];
172
        } else {
173
            if (isset($step->dsl['id'])) {
174
                $match = array('id' => $step->dsl['id']);
175
            }
176
            if (isset($step->dsl['group'])) {
177
                $match = array('id' => $step->dsl['group']);
178
            }
179
        }
180
181
        // convert the references passed in the match
182
        $match = $this->resolveReferencesRecursively($match);
0 ignored issues
show
Bug introduced by
The variable $match does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
183
184
        return $this->userGroupMatcher->match($match);
185
    }
186
187
    /**
188
     * @param UserGroup $userGroup
189
     * @param array $references the definitions of the references to set
190
     * @throws \InvalidArgumentException When trying to assign a reference to an unsupported attribute
191
     * @return array key: the reference names, values: the reference values
192
     */
193 View Code Duplication
    protected function getReferencesValues(UserGroup $userGroup, array $references)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
194
    {
195
        $refs = array();
196
197
        foreach ($references as $reference) {
198
            switch ($reference['attribute']) {
199
                case 'object_id':
200
                case 'content_id':
201
                case 'user_group_id':
202
                case 'id':
203
                    $value = $userGroup->id;
204
                    break;
205
                default:
206
                    throw new \InvalidArgumentException('User Group Manager does not support setting references for attribute ' . $reference['attribute']);
207
            }
208
209
            $refs[$reference['identifier']] = $value;
210
        }
211
212
        return $refs;
213
    }
214
215 View Code Duplication
    protected function setSection(Content $content, $sectionKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
216
    {
217
        $sectionKey = $this->referenceResolver->resolveReference($sectionKey);
218
        $section = $this->sectionMatcher->matchOneByKey($sectionKey);
219
220
        $sectionService = $this->repository->getSectionService();
221
        $sectionService->assignSection($content->contentInfo, $section);
222
    }
223
}
224