Completed
Push — master ( 2686f5...0602f1 )
by Gaetano
09:57
created

UserGroupManager::load()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
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...ion\AbstractCollection>.

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
    protected function load($step)
78
    {
79
        $userGroupCollection = $this->matchUserGroups('load', $step);
80
81
        $this->setReferences($userGroupCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $userGroupCollection defined by $this->matchUserGroups('load', $step) on line 79 can be null; however, Kaliop\eZMigrationBundle...ecutor::setReferences() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
82
83
        return $userGroupCollection;
84
    }
85
86
    /**
87
     * Method to handle the update operation of the migration instructions
88
     *
89
     * @throws \Exception When the ID of the user group is missing from the migration definition.
90
     */
91
    protected function update($step)
92
    {
93
        $userGroupCollection = $this->matchUserGroups('update', $step);
94
95
        if (count($userGroupCollection) > 1 && isset($step->dsl['references'])) {
96
            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");
97
        }
98
99
        $userService = $this->repository->getUserService();
100
        $contentService = $this->repository->getContentService();
101
102
        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...
103
104
            /** @var $updateStruct \eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct */
105
            $updateStruct = $userService->newUserGroupUpdateStruct();
106
107
            /** @var $contentUpdateStruct \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct */
108
            $contentUpdateStruct = $contentService->newContentUpdateStruct();
109
110
            if (isset($step->dsl['name'])) {
111
                $contentUpdateStruct->setField('name', $step->dsl['name']);
112
            }
113
114
            if (isset($step->dsl['remote_id'])) {
115
                $contentUpdateStruct->remoteId = $step->dsl['remote_id'];
116
            }
117
118
            if (isset($step->dsl['description'])) {
119
                $contentUpdateStruct->setField('description', $step->dsl['description']);
120
            }
121
122
            $updateStruct->contentUpdateStruct = $contentUpdateStruct;
123
124
            $userGroup = $userService->updateUserGroup($userGroup, $updateStruct);
125
126
            if (isset($step->dsl['parent_group_id'])) {
127
                $parentGroupId = $step->dsl['parent_group_id'];
128
                $parentGroupId = $this->referenceResolver->resolveReference($parentGroupId);
129
                $newParentGroup = $this->userGroupMatcher->matchOneByKey($parentGroupId);
130
131
                // Move group to new parent
132
                $userService->moveUserGroup($userGroup, $newParentGroup);
133
            }
134
135
            if (isset($step->dsl['section'])) {
136
                $this->setSection($userGroup, $step->dsl['section']);
137
            }
138
139
            $userGroupCollection[$key] = $userGroup;
140
        }
141
142
        $this->setReferences($userGroupCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $userGroupCollection defined by $this->matchUserGroups('update', $step) on line 93 can be null; however, Kaliop\eZMigrationBundle...ecutor::setReferences() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
143
144
        return $userGroupCollection;
145
    }
146
147
    /**
148
     * Method to handle the delete operation of the migration instructions
149
     *
150
     * @throws \Exception When there are no groups specified for deletion.
151
     */
152 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...
153
    {
154
        $userGroupCollection = $this->matchUserGroups('delete', $step);
155
156
        $this->setReferences($userGroupCollection, $step);
0 ignored issues
show
Bug introduced by
It seems like $userGroupCollection defined by $this->matchUserGroups('delete', $step) on line 154 can be null; however, Kaliop\eZMigrationBundle...ecutor::setReferences() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
157
158
        $userService = $this->repository->getUserService();
159
160
        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...
161
            $userService->deleteUserGroup($userGroup);
162
        }
163
164
        return $userGroupCollection;
165
    }
166
167
    /**
168
     * @param string $action
169
     * @return UserGroupCollection
170
     * @throws \Exception
171
     */
172 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...
173
    {
174
        if (!isset($step->dsl['id']) && !isset($step->dsl['group']) && !isset($step->dsl['match'])) {
175
            throw new \Exception("The id of a user group or a match condition is required to $action it");
176
        }
177
178
        // Backwards compat
179
        if (isset($step->dsl['match'])) {
180
            $match = $step->dsl['match'];
181
        } else {
182
            if (isset($step->dsl['id'])) {
183
                $match = array('id' => $step->dsl['id']);
184
            }
185
            if (isset($step->dsl['group'])) {
186
                $match = array('id' => $step->dsl['group']);
187
            }
188
        }
189
190
        // convert the references passed in the match
191
        $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...
192
193
        return $this->userGroupMatcher->match($match);
194
    }
195
196
    /**
197
     * @param UserGroup $userGroup
198
     * @param array $references the definitions of the references to set
199
     * @throws \InvalidArgumentException When trying to assign a reference to an unsupported attribute
200
     * @return array key: the reference names, values: the reference values
201
     */
202
    protected function getReferencesValues($userGroup, array $references, $step)
203
    {
204
        $refs = array();
205
206
        foreach ($references as $reference) {
207
            switch ($reference['attribute']) {
208
                case 'object_id':
209
                case 'content_id':
210
                case 'user_group_id':
211
                case 'id':
212
                    $value = $userGroup->id;
213
                    break;
214 View Code Duplication
                case 'users_ids':
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...
215
                    $value = [];
216
                    $userService = $this->repository->getUserService();
217
                    $limit = 100;
218
                    $offset = 0;
219
                    do {
220
                        $users = $userService->loadUsersOfUserGroup($userGroup, $offset, $limit);
221
                        foreach ($users as $user) {
222
                            $value[] = $user->id;
223
                        }
224
                    } while (count($userService));
225
                    break;
226
                default:
227
                    throw new \InvalidArgumentException('User Group Manager does not support setting references for attribute ' . $reference['attribute']);
228
            }
229
230
            $refs[$reference['identifier']] = $value;
231
        }
232
233
        return $refs;
234
    }
235
236 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...
237
    {
238
        $sectionKey = $this->referenceResolver->resolveReference($sectionKey);
239
        $section = $this->sectionMatcher->matchOneByKey($sectionKey);
240
241
        $sectionService = $this->repository->getSectionService();
242
        $sectionService->assignSection($content->contentInfo, $section);
243
    }
244
}
245