1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Kaliop\eZMigrationBundle\Core\Executor; |
4
|
|
|
|
5
|
|
|
use eZ\Publish\API\Repository\Values\User\User; |
6
|
|
|
use Kaliop\eZMigrationBundle\API\Collection\UserCollection; |
7
|
|
|
use Kaliop\eZMigrationBundle\Core\Matcher\UserGroupMatcher; |
8
|
|
|
use Kaliop\eZMigrationBundle\Core\Matcher\UserMatcher; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Handles user migrations. |
12
|
|
|
*/ |
13
|
|
|
class UserManager extends RepositoryExecutor |
14
|
|
|
{ |
15
|
|
|
protected $supportedStepTypes = array('user'); |
16
|
|
|
|
17
|
|
|
protected $userMatcher; |
18
|
|
|
|
19
|
|
|
protected $userGroupMatcher; |
20
|
|
|
|
21
|
|
|
public function __construct(UserMatcher $userMatcher, UserGroupMatcher $userGroupMatcher) |
22
|
|
|
{ |
23
|
|
|
$this->userMatcher = $userMatcher; |
24
|
|
|
$this->userGroupMatcher = $userGroupMatcher; |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Creates a user based on the DSL instructions. |
29
|
|
|
* |
30
|
|
|
* @todo allow setting extra profile attributes! |
31
|
|
|
*/ |
32
|
|
|
protected function create($step) |
33
|
|
|
{ |
34
|
|
|
if (!isset($step->dsl['groups'])) { |
35
|
|
|
throw new \Exception('No user groups set to create user in.'); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
if (!is_array($step->dsl['groups'])) { |
39
|
|
|
$step->dsl['groups'] = array($step->dsl['groups']); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
$userService = $this->repository->getUserService(); |
43
|
|
|
$contentTypeService = $this->repository->getContentTypeService(); |
44
|
|
|
|
45
|
|
|
$userGroups = array(); |
46
|
|
View Code Duplication |
foreach ($step->dsl['groups'] as $groupId) { |
|
|
|
|
47
|
|
|
$groupId = $this->referenceResolver->resolveReference($groupId); |
48
|
|
|
$userGroup = $this->userGroupMatcher->matchOneByKey($groupId); |
49
|
|
|
|
50
|
|
|
// q: in which case can we have no group? And should we throw an exception? |
51
|
|
|
//if ($userGroup) { |
|
|
|
|
52
|
|
|
$userGroups[] = $userGroup; |
53
|
|
|
//} |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
// FIXME: Hard coding content type to user for now |
57
|
|
|
$userContentType = $contentTypeService->loadContentTypeByIdentifier($this->getUserContentType($step)); |
58
|
|
|
|
59
|
|
|
$userCreateStruct = $userService->newUserCreateStruct( |
60
|
|
|
$step->dsl['username'], |
61
|
|
|
$step->dsl['email'], |
62
|
|
|
$step->dsl['password'], |
63
|
|
|
$this->getLanguageCode($step), |
64
|
|
|
$userContentType |
65
|
|
|
); |
66
|
|
|
$userCreateStruct->setField('first_name', $step->dsl['first_name']); |
67
|
|
|
$userCreateStruct->setField('last_name', $step->dsl['last_name']); |
68
|
|
|
|
69
|
|
|
// Create the user |
70
|
|
|
$user = $userService->createUser($userCreateStruct, $userGroups); |
71
|
|
|
|
72
|
|
|
$this->setReferences($user, $step); |
|
|
|
|
73
|
|
|
|
74
|
|
|
return $user; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Method to handle the update operation of the migration instructions |
79
|
|
|
* |
80
|
|
|
* @todo allow setting extra profile attributes! |
81
|
|
|
*/ |
82
|
|
|
protected function update($step) |
83
|
|
|
{ |
84
|
|
|
$userCollection = $this->matchUsers('user', $step); |
85
|
|
|
|
86
|
|
|
if (count($userCollection) > 1 && isset($step->dsl['references'])) { |
87
|
|
|
throw new \Exception("Can not execute User update because multiple user match, and a references section is specified in the dsl. References can be set when only 1 user matches"); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
if (count($userCollection) > 1 && isset($step->dsl['email'])) { |
91
|
|
|
throw new \Exception("Can not execute User update because multiple user match, and an email section is specified in the dsl."); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
$userService = $this->repository->getUserService(); |
95
|
|
|
|
96
|
|
|
foreach ($userCollection as $key => $user) { |
|
|
|
|
97
|
|
|
|
98
|
|
|
$userUpdateStruct = $userService->newUserUpdateStruct(); |
99
|
|
|
|
100
|
|
|
if (isset($step->dsl['email'])) { |
101
|
|
|
$userUpdateStruct->email = $step->dsl['email']; |
102
|
|
|
} |
103
|
|
|
if (isset($step->dsl['password'])) { |
104
|
|
|
$userUpdateStruct->password = (string)$step->dsl['password']; |
105
|
|
|
} |
106
|
|
|
if (isset($step->dsl['enabled'])) { |
107
|
|
|
$userUpdateStruct->enabled = $step->dsl['enabled']; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
$user = $userService->updateUser($user, $userUpdateStruct); |
111
|
|
|
|
112
|
|
|
if (isset($step->dsl['groups'])) { |
113
|
|
|
$groups = $step->dsl['groups']; |
114
|
|
|
|
115
|
|
|
if (!is_array($groups)) { |
116
|
|
|
$groups = array($groups); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
$assignedGroups = $userService->loadUserGroupsOfUser($user); |
120
|
|
|
|
121
|
|
|
$targetGroupIds = []; |
122
|
|
|
// Assigning new groups to the user |
123
|
|
|
foreach ($groups as $groupToAssignId) { |
124
|
|
|
$groupId = $this->referenceResolver->resolveReference($groupToAssignId); |
125
|
|
|
$groupToAssign = $this->userGroupMatcher->matchOneByKey($groupId); |
126
|
|
|
$targetGroupIds[] = $groupToAssign->id; |
127
|
|
|
|
128
|
|
|
$present = false; |
129
|
|
|
foreach ($assignedGroups as $assignedGroup) { |
130
|
|
|
// Make sure we assign the user only to groups he isn't already assigned to |
131
|
|
|
if ($assignedGroup->id == $groupToAssign->id) { |
132
|
|
|
$present = true; |
133
|
|
|
break; |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
if (!$present) { |
137
|
|
|
$userService->assignUserToUserGroup($user, $groupToAssign); |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
// Unassigning groups that are not in the list in the migration |
142
|
|
|
foreach ($assignedGroups as $assignedGroup) { |
143
|
|
|
if (!in_array($assignedGroup->id, $targetGroupIds)) { |
144
|
|
|
$userService->unAssignUserFromUserGroup($user, $assignedGroup); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$userCollection[$key] = $user; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
$this->setReferences($userCollection, $step); |
|
|
|
|
153
|
|
|
|
154
|
|
|
return $userCollection; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Method to handle the delete operation of the migration instructions |
159
|
|
|
*/ |
160
|
|
View Code Duplication |
protected function delete($step) |
|
|
|
|
161
|
|
|
{ |
162
|
|
|
$userCollection = $this->matchUsers('delete', $step); |
163
|
|
|
|
164
|
|
|
$this->setReferences($userCollection, $step); |
|
|
|
|
165
|
|
|
|
166
|
|
|
$userService = $this->repository->getUserService(); |
167
|
|
|
|
168
|
|
|
foreach ($userCollection as $user) { |
|
|
|
|
169
|
|
|
$userService->deleteUser($user); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
return $userCollection; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* @param string $action |
177
|
|
|
* @return UserCollection |
178
|
|
|
* @throws \Exception |
179
|
|
|
*/ |
180
|
|
|
protected function matchUsers($action, $step) |
181
|
|
|
{ |
182
|
|
|
if (!isset($step->dsl['id']) && !isset($step->dsl['user_id']) && !isset($step->dsl['email']) && !isset($step->dsl['username']) && !isset($step->dsl['match'])) { |
183
|
|
|
throw new \Exception("The id, email or username of a user or a match condition is required to $action it"); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
// Backwards compat |
187
|
|
|
if (isset($step->dsl['match'])) { |
188
|
|
|
$match = $step->dsl['match']; |
189
|
|
|
} else { |
190
|
|
|
$conds = array(); |
191
|
|
|
if (isset($step->dsl['id'])) { |
192
|
|
|
$conds['id'] = $step->dsl['id']; |
193
|
|
|
} |
194
|
|
|
if (isset($step->dsl['user_id'])) { |
195
|
|
|
$conds['id'] = $step->dsl['user_id']; |
196
|
|
|
} |
197
|
|
|
if (isset($step->dsl['email'])) { |
198
|
|
|
$conds['email'] = $step->dsl['email']; |
199
|
|
|
} |
200
|
|
|
if (isset($step->dsl['username'])) { |
201
|
|
|
$conds['login'] = $step->dsl['username']; |
202
|
|
|
} |
203
|
|
|
$match = $conds; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
// convert the references passed in the match |
207
|
|
|
$match = $this->resolveReferencesRecursively($match); |
208
|
|
|
|
209
|
|
|
return $this->userMatcher->match($match); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* @param User $user |
214
|
|
|
* @param array $references the definitions of the references to set |
215
|
|
|
* @throws \InvalidArgumentException When trying to assign a reference to an unsupported attribute |
216
|
|
|
* @return array key: the reference names, values: the reference values |
217
|
|
|
*/ |
218
|
|
|
protected function getReferencesValues(User $user, array $references) |
219
|
|
|
{ |
220
|
|
View Code Duplication |
foreach ($references as $reference) { |
|
|
|
|
221
|
|
|
|
222
|
|
|
switch ($reference['attribute']) { |
223
|
|
|
case 'user_id': |
224
|
|
|
case 'id': |
225
|
|
|
$value = $user->id; |
226
|
|
|
break; |
227
|
|
|
case 'email': |
228
|
|
|
$value = $user->email; |
229
|
|
|
break; |
230
|
|
|
case 'enabled': |
231
|
|
|
$value = $user->enabled; |
232
|
|
|
break; |
233
|
|
|
case 'login': |
234
|
|
|
$value = $user->login; |
235
|
|
|
break; |
236
|
|
|
default: |
237
|
|
|
throw new \InvalidArgumentException('User Manager does not support setting references for attribute ' . $reference['attribute']); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
$refs[$reference['identifier']] = $value; |
|
|
|
|
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
return $refs; |
|
|
|
|
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
|
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.