Complex classes like UserService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use UserService, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
62 | class UserService implements UserServiceInterface |
||
63 | { |
||
64 | /** @var \eZ\Publish\API\Repository\Repository */ |
||
65 | protected $repository; |
||
66 | |||
67 | /** @var \eZ\Publish\SPI\Persistence\User\Handler */ |
||
68 | protected $userHandler; |
||
69 | |||
70 | /** @var \eZ\Publish\SPI\Persistence\Content\Location\Handler */ |
||
71 | private $locationHandler; |
||
72 | |||
73 | /** @var array */ |
||
74 | protected $settings; |
||
75 | |||
76 | /** @var \Psr\Log\LoggerInterface|null */ |
||
77 | protected $logger; |
||
78 | |||
79 | /** @var \eZ\Publish\API\Repository\PermissionResolver */ |
||
80 | private $permissionResolver; |
||
81 | |||
82 | public function setLogger(LoggerInterface $logger = null) |
||
83 | { |
||
84 | $this->logger = $logger; |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * Setups service with reference to repository object that created it & corresponding handler. |
||
89 | * |
||
90 | * @param \eZ\Publish\API\Repository\Repository $repository |
||
91 | * @param \eZ\Publish\SPI\Persistence\User\Handler $userHandler |
||
92 | * @param \eZ\Publish\SPI\Persistence\Content\Location\Handler $locationHandler |
||
93 | * @param array $settings |
||
94 | */ |
||
95 | public function __construct( |
||
96 | RepositoryInterface $repository, |
||
97 | PermissionResolver $permissionResolver, |
||
98 | Handler $userHandler, |
||
99 | LocationHandler $locationHandler, |
||
100 | array $settings = [] |
||
101 | ) { |
||
102 | $this->repository = $repository; |
||
103 | $this->permissionResolver = $permissionResolver; |
||
104 | $this->userHandler = $userHandler; |
||
105 | $this->locationHandler = $locationHandler; |
||
106 | // Union makes sure default settings are ignored if provided in argument |
||
107 | $this->settings = $settings + [ |
||
108 | 'defaultUserPlacement' => 12, |
||
109 | 'userClassID' => 4, // @todo Rename this settings to swap out "Class" for "Type" |
||
110 | 'userGroupClassID' => 3, |
||
111 | 'hashType' => APIUser::DEFAULT_PASSWORD_HASH, |
||
112 | 'siteName' => 'ez.no', |
||
113 | ]; |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Creates a new user group using the data provided in the ContentCreateStruct parameter. |
||
118 | * |
||
119 | * In 4.x in the content type parameter in the profile is ignored |
||
120 | * - the content type is determined via configuration and can be set to null. |
||
121 | * The returned version is published. |
||
122 | * |
||
123 | * @param \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct $userGroupCreateStruct a structure for setting all necessary data to create this user group |
||
124 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $parentGroup |
||
125 | * |
||
126 | * @return \eZ\Publish\API\Repository\Values\User\UserGroup |
||
127 | * |
||
128 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to create a user group |
||
129 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the input structure has invalid data |
||
130 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userGroupCreateStruct is not valid |
||
131 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is missing or set to an empty value |
||
132 | */ |
||
133 | public function createUserGroup(APIUserGroupCreateStruct $userGroupCreateStruct, APIUserGroup $parentGroup) |
||
134 | { |
||
135 | $contentService = $this->repository->getContentService(); |
||
136 | $locationService = $this->repository->getLocationService(); |
||
137 | $contentTypeService = $this->repository->getContentTypeService(); |
||
138 | |||
139 | if ($userGroupCreateStruct->contentType === null) { |
||
140 | $userGroupContentType = $contentTypeService->loadContentType($this->settings['userGroupClassID']); |
||
141 | $userGroupCreateStruct->contentType = $userGroupContentType; |
||
142 | } |
||
143 | |||
144 | $loadedParentGroup = $this->loadUserGroup($parentGroup->id); |
||
145 | |||
146 | if ($loadedParentGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) { |
||
147 | throw new InvalidArgumentException('parentGroup', 'parent user group has no main location'); |
||
148 | } |
||
149 | |||
150 | $locationCreateStruct = $locationService->newLocationCreateStruct( |
||
151 | $loadedParentGroup->getVersionInfo()->getContentInfo()->mainLocationId |
||
152 | ); |
||
153 | |||
154 | $this->repository->beginTransaction(); |
||
155 | try { |
||
156 | $contentDraft = $contentService->createContent($userGroupCreateStruct, [$locationCreateStruct]); |
||
157 | $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo()); |
||
158 | $this->repository->commit(); |
||
159 | } catch (Exception $e) { |
||
160 | $this->repository->rollback(); |
||
161 | throw $e; |
||
162 | } |
||
163 | |||
164 | return $this->buildDomainUserGroupObject($publishedContent); |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Loads a user group for the given id. |
||
169 | * |
||
170 | * @param mixed $id |
||
171 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
172 | * |
||
173 | * @return \eZ\Publish\API\Repository\Values\User\UserGroup |
||
174 | * |
||
175 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to create a user group |
||
176 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if the user group with the given id was not found |
||
177 | */ |
||
178 | public function loadUserGroup($id, array $prioritizedLanguages = []) |
||
179 | { |
||
180 | $content = $this->repository->getContentService()->loadContent($id, $prioritizedLanguages); |
||
181 | |||
182 | return $this->buildDomainUserGroupObject($content); |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Loads the sub groups of a user group. |
||
187 | * |
||
188 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
189 | * @param int $offset the start offset for paging |
||
190 | * @param int $limit the number of user groups returned |
||
191 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
192 | * |
||
193 | * @return \eZ\Publish\API\Repository\Values\User\UserGroup[] |
||
194 | * |
||
195 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to read the user group |
||
196 | */ |
||
197 | public function loadSubUserGroups(APIUserGroup $userGroup, $offset = 0, $limit = 25, array $prioritizedLanguages = []) |
||
198 | { |
||
199 | $locationService = $this->repository->getLocationService(); |
||
200 | |||
201 | $loadedUserGroup = $this->loadUserGroup($userGroup->id); |
||
202 | if (!$this->permissionResolver->canUser('content', 'read', $loadedUserGroup)) { |
||
203 | throw new UnauthorizedException('content', 'read'); |
||
204 | } |
||
205 | |||
206 | if ($loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) { |
||
207 | return []; |
||
208 | } |
||
209 | |||
210 | $mainGroupLocation = $locationService->loadLocation( |
||
211 | $loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId |
||
212 | ); |
||
213 | |||
214 | $searchResult = $this->searchSubGroups($mainGroupLocation, $offset, $limit); |
||
215 | if ($searchResult->totalCount == 0) { |
||
216 | return []; |
||
217 | } |
||
218 | |||
219 | $subUserGroups = []; |
||
220 | foreach ($searchResult->searchHits as $searchHit) { |
||
221 | $subUserGroups[] = $this->buildDomainUserGroupObject( |
||
222 | $this->repository->getContentService()->internalLoadContent( |
||
|
|||
223 | $searchHit->valueObject->contentInfo->id, |
||
224 | $prioritizedLanguages |
||
225 | ) |
||
226 | ); |
||
227 | } |
||
228 | |||
229 | return $subUserGroups; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Returns (searches) subgroups of a user group described by its main location. |
||
234 | * |
||
235 | * @param \eZ\Publish\API\Repository\Values\Content\Location $location |
||
236 | * @param int $offset |
||
237 | * @param int $limit |
||
238 | * |
||
239 | * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult |
||
240 | */ |
||
241 | protected function searchSubGroups(Location $location, $offset = 0, $limit = 25) |
||
242 | { |
||
243 | $searchQuery = new LocationQuery(); |
||
244 | |||
245 | $searchQuery->offset = $offset; |
||
246 | $searchQuery->limit = $limit; |
||
247 | |||
248 | $searchQuery->filter = new CriterionLogicalAnd([ |
||
249 | new CriterionContentTypeId($this->settings['userGroupClassID']), |
||
250 | new CriterionParentLocationId($location->id), |
||
251 | ]); |
||
252 | |||
253 | $searchQuery->sortClauses = $location->getSortClauses(); |
||
254 | |||
255 | return $this->repository->getSearchService()->findLocations($searchQuery, [], false); |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * Removes a user group. |
||
260 | * |
||
261 | * the users which are not assigned to other groups will be deleted. |
||
262 | * |
||
263 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
264 | * |
||
265 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to create a user group |
||
266 | */ |
||
267 | public function deleteUserGroup(APIUserGroup $userGroup) |
||
268 | { |
||
269 | $loadedUserGroup = $this->loadUserGroup($userGroup->id); |
||
270 | |||
271 | $this->repository->beginTransaction(); |
||
272 | try { |
||
273 | //@todo: what happens to sub user groups and users below sub user groups |
||
274 | $affectedLocationIds = $this->repository->getContentService()->deleteContent($loadedUserGroup->getVersionInfo()->getContentInfo()); |
||
275 | $this->repository->commit(); |
||
276 | } catch (Exception $e) { |
||
277 | $this->repository->rollback(); |
||
278 | throw $e; |
||
279 | } |
||
280 | |||
281 | return $affectedLocationIds; |
||
282 | } |
||
283 | |||
284 | /** |
||
285 | * Moves the user group to another parent. |
||
286 | * |
||
287 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
288 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $newParent |
||
289 | * |
||
290 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to move the user group |
||
291 | */ |
||
292 | public function moveUserGroup(APIUserGroup $userGroup, APIUserGroup $newParent) |
||
293 | { |
||
294 | $loadedUserGroup = $this->loadUserGroup($userGroup->id); |
||
295 | $loadedNewParent = $this->loadUserGroup($newParent->id); |
||
296 | |||
297 | $locationService = $this->repository->getLocationService(); |
||
298 | |||
299 | if ($loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) { |
||
300 | throw new BadStateException('userGroup', 'existing user group is not stored and/or does not have any location yet'); |
||
301 | } |
||
302 | |||
303 | if ($loadedNewParent->getVersionInfo()->getContentInfo()->mainLocationId === null) { |
||
304 | throw new BadStateException('newParent', 'new user group is not stored and/or does not have any location yet'); |
||
305 | } |
||
306 | |||
307 | $userGroupMainLocation = $locationService->loadLocation( |
||
308 | $loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId |
||
309 | ); |
||
310 | $newParentMainLocation = $locationService->loadLocation( |
||
311 | $loadedNewParent->getVersionInfo()->getContentInfo()->mainLocationId |
||
312 | ); |
||
313 | |||
314 | $this->repository->beginTransaction(); |
||
315 | try { |
||
316 | $locationService->moveSubtree($userGroupMainLocation, $newParentMainLocation); |
||
317 | $this->repository->commit(); |
||
318 | } catch (Exception $e) { |
||
319 | $this->repository->rollback(); |
||
320 | throw $e; |
||
321 | } |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Updates the group profile with fields and meta data. |
||
326 | * |
||
327 | * 4.x: If the versionUpdateStruct is set in $userGroupUpdateStruct, this method internally creates a content draft, updates ts with the provided data |
||
328 | * and publishes the draft. If a draft is explicitly required, the user group can be updated via the content service methods. |
||
329 | * |
||
330 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
331 | * @param \eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct $userGroupUpdateStruct |
||
332 | * |
||
333 | * @return \eZ\Publish\API\Repository\Values\User\UserGroup |
||
334 | * |
||
335 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to update the user group |
||
336 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userGroupUpdateStruct is not valid |
||
337 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is set empty |
||
338 | */ |
||
339 | public function updateUserGroup(APIUserGroup $userGroup, UserGroupUpdateStruct $userGroupUpdateStruct) |
||
340 | { |
||
341 | if ($userGroupUpdateStruct->contentUpdateStruct === null && |
||
342 | $userGroupUpdateStruct->contentMetadataUpdateStruct === null) { |
||
343 | // both update structs are empty, nothing to do |
||
344 | return $userGroup; |
||
345 | } |
||
346 | |||
347 | $contentService = $this->repository->getContentService(); |
||
348 | |||
349 | $loadedUserGroup = $this->loadUserGroup($userGroup->id); |
||
350 | |||
351 | $this->repository->beginTransaction(); |
||
352 | try { |
||
353 | $publishedContent = $loadedUserGroup; |
||
354 | if ($userGroupUpdateStruct->contentUpdateStruct !== null) { |
||
355 | $contentDraft = $contentService->createContentDraft($loadedUserGroup->getVersionInfo()->getContentInfo()); |
||
356 | |||
357 | $contentDraft = $contentService->updateContent( |
||
358 | $contentDraft->getVersionInfo(), |
||
359 | $userGroupUpdateStruct->contentUpdateStruct |
||
360 | ); |
||
361 | |||
362 | $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo()); |
||
363 | } |
||
364 | |||
365 | if ($userGroupUpdateStruct->contentMetadataUpdateStruct !== null) { |
||
366 | $publishedContent = $contentService->updateContentMetadata( |
||
367 | $publishedContent->getVersionInfo()->getContentInfo(), |
||
368 | $userGroupUpdateStruct->contentMetadataUpdateStruct |
||
369 | ); |
||
370 | } |
||
371 | |||
372 | $this->repository->commit(); |
||
373 | } catch (Exception $e) { |
||
374 | $this->repository->rollback(); |
||
375 | throw $e; |
||
376 | } |
||
377 | |||
378 | return $this->buildDomainUserGroupObject($publishedContent); |
||
379 | } |
||
380 | |||
381 | /** |
||
382 | * Create a new user. The created user is published by this method. |
||
383 | * |
||
384 | * @param \eZ\Publish\API\Repository\Values\User\UserCreateStruct $userCreateStruct the data used for creating the user |
||
385 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup[] $parentGroups the groups which are assigned to the user after creation |
||
386 | * |
||
387 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
388 | * |
||
389 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to move the user group |
||
390 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userCreateStruct is not valid |
||
391 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is missing or set to an empty value |
||
392 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if a user with provided login already exists |
||
393 | */ |
||
394 | public function createUser(APIUserCreateStruct $userCreateStruct, array $parentGroups) |
||
395 | { |
||
396 | if (empty($parentGroups)) { |
||
397 | throw new InvalidArgumentValue('parentGroups', $parentGroups); |
||
398 | } |
||
399 | |||
400 | if (!is_string($userCreateStruct->login) || empty($userCreateStruct->login)) { |
||
401 | throw new InvalidArgumentValue('login', $userCreateStruct->login, 'UserCreateStruct'); |
||
402 | } |
||
403 | |||
404 | if (!is_string($userCreateStruct->email) || empty($userCreateStruct->email)) { |
||
405 | throw new InvalidArgumentValue('email', $userCreateStruct->email, 'UserCreateStruct'); |
||
406 | } |
||
407 | |||
408 | if (!preg_match('/^.+@.+\..+$/', $userCreateStruct->email)) { |
||
409 | throw new InvalidArgumentValue('email', $userCreateStruct->email, 'UserCreateStruct'); |
||
410 | } |
||
411 | |||
412 | if (!is_string($userCreateStruct->password) || empty($userCreateStruct->password)) { |
||
413 | throw new InvalidArgumentValue('password', $userCreateStruct->password, 'UserCreateStruct'); |
||
414 | } |
||
415 | |||
416 | if (!is_bool($userCreateStruct->enabled)) { |
||
417 | throw new InvalidArgumentValue('enabled', $userCreateStruct->enabled, 'UserCreateStruct'); |
||
418 | } |
||
419 | |||
420 | try { |
||
421 | $this->userHandler->loadByLogin($userCreateStruct->login); |
||
422 | throw new InvalidArgumentException('userCreateStruct', 'User with provided login already exists'); |
||
423 | } catch (NotFoundException $e) { |
||
424 | // Do nothing |
||
425 | } |
||
426 | |||
427 | $contentService = $this->repository->getContentService(); |
||
428 | $locationService = $this->repository->getLocationService(); |
||
429 | $contentTypeService = $this->repository->getContentTypeService(); |
||
430 | |||
431 | if ($userCreateStruct->contentType === null) { |
||
432 | $userCreateStruct->contentType = $contentTypeService->loadContentType($this->settings['userClassID']); |
||
433 | } |
||
434 | |||
435 | $errors = $this->validatePassword($userCreateStruct->password, new PasswordValidationContext([ |
||
436 | 'contentType' => $userCreateStruct->contentType, |
||
437 | ])); |
||
438 | if (!empty($errors)) { |
||
439 | throw new UserPasswordValidationException('password', $errors); |
||
440 | } |
||
441 | |||
442 | $locationCreateStructs = []; |
||
443 | foreach ($parentGroups as $parentGroup) { |
||
444 | $parentGroup = $this->loadUserGroup($parentGroup->id); |
||
445 | if ($parentGroup->getVersionInfo()->getContentInfo()->mainLocationId !== null) { |
||
446 | $locationCreateStructs[] = $locationService->newLocationCreateStruct( |
||
447 | $parentGroup->getVersionInfo()->getContentInfo()->mainLocationId |
||
448 | ); |
||
449 | } |
||
450 | } |
||
451 | |||
452 | // Search for the first ezuser field type in content type |
||
453 | $userFieldDefinition = null; |
||
454 | foreach ($userCreateStruct->contentType->getFieldDefinitions() as $fieldDefinition) { |
||
455 | if ($fieldDefinition->fieldTypeIdentifier == 'ezuser') { |
||
456 | $userFieldDefinition = $fieldDefinition; |
||
457 | break; |
||
458 | } |
||
459 | } |
||
460 | |||
461 | if ($userFieldDefinition === null) { |
||
462 | throw new ContentValidationException('Provided content type does not contain ezuser field type'); |
||
463 | } |
||
464 | |||
465 | $fixUserFieldType = true; |
||
466 | foreach ($userCreateStruct->fields as $index => $field) { |
||
467 | if ($field->fieldDefIdentifier == $userFieldDefinition->identifier) { |
||
468 | if ($field->value instanceof UserValue) { |
||
469 | $userCreateStruct->fields[$index]->value->login = $userCreateStruct->login; |
||
470 | } else { |
||
471 | $userCreateStruct->fields[$index]->value = new UserValue( |
||
472 | [ |
||
473 | 'login' => $userCreateStruct->login, |
||
474 | ] |
||
475 | ); |
||
476 | } |
||
477 | |||
478 | $fixUserFieldType = false; |
||
479 | } |
||
480 | } |
||
481 | |||
482 | if ($fixUserFieldType) { |
||
483 | $userCreateStruct->setField( |
||
484 | $userFieldDefinition->identifier, |
||
485 | new UserValue( |
||
486 | [ |
||
487 | 'login' => $userCreateStruct->login, |
||
488 | ] |
||
489 | ) |
||
490 | ); |
||
491 | } |
||
492 | |||
493 | $this->repository->beginTransaction(); |
||
494 | try { |
||
495 | $contentDraft = $contentService->createContent($userCreateStruct, $locationCreateStructs); |
||
496 | // Create user before publishing, so that external data can be returned |
||
497 | $spiUser = $this->userHandler->create( |
||
498 | new SPIUser( |
||
499 | [ |
||
500 | 'id' => $contentDraft->id, |
||
501 | 'login' => $userCreateStruct->login, |
||
502 | 'email' => $userCreateStruct->email, |
||
503 | 'passwordHash' => $this->createPasswordHash( |
||
504 | $userCreateStruct->login, |
||
505 | $userCreateStruct->password, |
||
506 | $this->settings['siteName'], |
||
507 | $this->settings['hashType'] |
||
508 | ), |
||
509 | 'hashAlgorithm' => $this->settings['hashType'], |
||
510 | 'passwordUpdatedAt' => time(), |
||
511 | 'isEnabled' => $userCreateStruct->enabled, |
||
512 | 'maxLogin' => 0, |
||
513 | ] |
||
514 | ) |
||
515 | ); |
||
516 | $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo()); |
||
517 | |||
518 | $this->repository->commit(); |
||
519 | } catch (Exception $e) { |
||
520 | $this->repository->rollback(); |
||
521 | throw $e; |
||
522 | } |
||
523 | |||
524 | return $this->buildDomainUserObject($spiUser, $publishedContent); |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * Loads a user. |
||
529 | * |
||
530 | * @param mixed $userId |
||
531 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
532 | * |
||
533 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
534 | * |
||
535 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if a user with the given id was not found |
||
536 | */ |
||
537 | public function loadUser($userId, array $prioritizedLanguages = []) |
||
538 | { |
||
539 | /** @var \eZ\Publish\API\Repository\Values\Content\Content $content */ |
||
540 | $content = $this->repository->getContentService()->internalLoadContent($userId, $prioritizedLanguages); |
||
541 | // Get spiUser value from Field Value |
||
542 | foreach ($content->getFields() as $field) { |
||
543 | if (!$field->value instanceof UserValue) { |
||
544 | continue; |
||
545 | } |
||
546 | |||
547 | /** @var \eZ\Publish\Core\FieldType\User\Value $value */ |
||
548 | $value = $field->value; |
||
549 | $spiUser = new SPIUser(); |
||
550 | $spiUser->id = $value->contentId; |
||
551 | $spiUser->login = $value->login; |
||
552 | $spiUser->email = $value->email; |
||
553 | $spiUser->hashAlgorithm = $value->passwordHashType; |
||
554 | $spiUser->passwordHash = $value->passwordHash; |
||
555 | $spiUser->passwordUpdatedAt = $value->passwordUpdatedAt ? $value->passwordUpdatedAt->getTimestamp() : null; |
||
556 | $spiUser->isEnabled = $value->enabled; |
||
557 | $spiUser->maxLogin = $value->maxLogin; |
||
558 | break; |
||
559 | } |
||
560 | |||
561 | // If for some reason not found, load it |
||
562 | if (!isset($spiUser)) { |
||
563 | $spiUser = $this->userHandler->load($userId); |
||
564 | } |
||
565 | |||
566 | return $this->buildDomainUserObject($spiUser, $content); |
||
567 | } |
||
568 | |||
569 | /** |
||
570 | * Loads a user for the given login and password. |
||
571 | * |
||
572 | * If the password hash type differs from that configured for the service, it will be updated to the configured one. |
||
573 | * |
||
574 | * {@inheritdoc} |
||
575 | * |
||
576 | * @param string $login |
||
577 | * @param string $password the plain password |
||
578 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
579 | * |
||
580 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
581 | * |
||
582 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if credentials are invalid |
||
583 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if a user with the given credentials was not found |
||
584 | */ |
||
585 | public function loadUserByCredentials($login, $password, array $prioritizedLanguages = []) |
||
586 | { |
||
587 | if (!is_string($login) || empty($login)) { |
||
588 | throw new InvalidArgumentValue('login', $login); |
||
589 | } |
||
590 | |||
591 | if (!is_string($password)) { |
||
592 | throw new InvalidArgumentValue('password', $password); |
||
593 | } |
||
594 | |||
595 | $spiUser = $this->userHandler->loadByLogin($login); |
||
596 | if (!$this->verifyPassword($login, $password, $spiUser)) { |
||
597 | throw new NotFoundException('user', $login); |
||
598 | } |
||
599 | |||
600 | // Don't catch BadStateException, on purpose, to avoid broken hashes. |
||
601 | $this->updatePasswordHash($login, $password, $spiUser); |
||
602 | |||
603 | return $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages); |
||
604 | } |
||
605 | |||
606 | /** |
||
607 | * Update password hash to the type configured for the service, if they differ. |
||
608 | * |
||
609 | * @param string $login User login |
||
610 | * @param string $password User password |
||
611 | * @param \eZ\Publish\SPI\Persistence\User $spiUser |
||
612 | * |
||
613 | * @throws \eZ\Publish\Core\Base\Exceptions\BadStateException if the password is not correctly saved, in which case the update is reverted |
||
614 | */ |
||
615 | private function updatePasswordHash($login, $password, SPIUser $spiUser) |
||
616 | { |
||
617 | if ($spiUser->hashAlgorithm === $this->settings['hashType']) { |
||
618 | return; |
||
619 | } |
||
620 | |||
621 | $spiUser->passwordHash = $this->createPasswordHash($login, $password, null, $this->settings['hashType']); |
||
622 | $spiUser->hashAlgorithm = $this->settings['hashType']; |
||
623 | |||
624 | $this->repository->beginTransaction(); |
||
625 | $this->userHandler->update($spiUser); |
||
626 | $reloadedSpiUser = $this->userHandler->load($spiUser->id); |
||
627 | |||
628 | if ($reloadedSpiUser->passwordHash === $spiUser->passwordHash) { |
||
629 | $this->repository->commit(); |
||
630 | } else { |
||
631 | // Password hash was not correctly saved, possible cause: EZP-28692 |
||
632 | $this->repository->rollback(); |
||
633 | if (isset($this->logger)) { |
||
634 | $this->logger->critical('Password hash could not be updated. Please verify that your database schema is up to date.'); |
||
635 | } |
||
636 | |||
637 | throw new BadStateException( |
||
638 | 'user', |
||
639 | 'Could not save updated password hash, reverting to previous hash. Please verify that your database schema is up to date.' |
||
640 | ); |
||
641 | } |
||
642 | } |
||
643 | |||
644 | /** |
||
645 | * Loads a user for the given login. |
||
646 | * |
||
647 | * {@inheritdoc} |
||
648 | * |
||
649 | * @param string $login |
||
650 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
651 | * |
||
652 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
653 | * |
||
654 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if a user with the given credentials was not found |
||
655 | */ |
||
656 | public function loadUserByLogin($login, array $prioritizedLanguages = []) |
||
657 | { |
||
658 | if (!is_string($login) || empty($login)) { |
||
659 | throw new InvalidArgumentValue('login', $login); |
||
660 | } |
||
661 | |||
662 | $spiUser = $this->userHandler->loadByLogin($login); |
||
663 | |||
664 | return $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages); |
||
665 | } |
||
666 | |||
667 | /** |
||
668 | * Loads a user for the given email. |
||
669 | * |
||
670 | * {@inheritdoc} |
||
671 | * |
||
672 | * @param string $email |
||
673 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
674 | * |
||
675 | * @return \eZ\Publish\API\Repository\Values\User\User[] |
||
676 | */ |
||
677 | public function loadUsersByEmail($email, array $prioritizedLanguages = []) |
||
678 | { |
||
679 | if (!is_string($email) || empty($email)) { |
||
680 | throw new InvalidArgumentValue('email', $email); |
||
681 | } |
||
682 | |||
683 | $users = []; |
||
684 | foreach ($this->userHandler->loadByEmail($email) as $spiUser) { |
||
685 | $users[] = $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages); |
||
686 | } |
||
687 | |||
688 | return $users; |
||
689 | } |
||
690 | |||
691 | /** |
||
692 | * Loads a user for the given token. |
||
693 | * |
||
694 | * {@inheritdoc} |
||
695 | * |
||
696 | * @param string $hash |
||
697 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
698 | * |
||
699 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
700 | * |
||
701 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
702 | * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue |
||
703 | */ |
||
704 | public function loadUserByToken($hash, array $prioritizedLanguages = []) |
||
705 | { |
||
706 | if (!is_string($hash) || empty($hash)) { |
||
707 | throw new InvalidArgumentValue('hash', $hash); |
||
708 | } |
||
709 | |||
710 | $spiUser = $this->userHandler->loadUserByToken($hash); |
||
711 | |||
712 | return $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages); |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * This method deletes a user. |
||
717 | * |
||
718 | * @param \eZ\Publish\API\Repository\Values\User\User $user |
||
719 | * |
||
720 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to delete the user |
||
721 | */ |
||
722 | public function deleteUser(APIUser $user) |
||
723 | { |
||
724 | $loadedUser = $this->loadUser($user->id); |
||
725 | |||
726 | $this->repository->beginTransaction(); |
||
727 | try { |
||
728 | $affectedLocationIds = $this->repository->getContentService()->deleteContent($loadedUser->getVersionInfo()->getContentInfo()); |
||
729 | $this->userHandler->delete($loadedUser->id); |
||
730 | $this->repository->commit(); |
||
731 | } catch (Exception $e) { |
||
732 | $this->repository->rollback(); |
||
733 | throw $e; |
||
734 | } |
||
735 | |||
736 | return $affectedLocationIds; |
||
737 | } |
||
738 | |||
739 | /** |
||
740 | * Updates a user. |
||
741 | * |
||
742 | * 4.x: If the versionUpdateStruct is set in the user update structure, this method internally creates a content draft, updates ts with the provided data |
||
743 | * and publishes the draft. If a draft is explicitly required, the user group can be updated via the content service methods. |
||
744 | * |
||
745 | * @param \eZ\Publish\API\Repository\Values\User\User $user |
||
746 | * @param \eZ\Publish\API\Repository\Values\User\UserUpdateStruct $userUpdateStruct |
||
747 | * |
||
748 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userUpdateStruct is not valid |
||
749 | * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is set empty |
||
750 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to update the user |
||
751 | * |
||
752 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
753 | */ |
||
754 | public function updateUser(APIUser $user, UserUpdateStruct $userUpdateStruct) |
||
755 | { |
||
756 | $loadedUser = $this->loadUser($user->id); |
||
757 | |||
758 | // We need to determine if we have anything to update. |
||
759 | // UserUpdateStruct is specific as some of the new content is in |
||
760 | // content update struct and some of it is in additional fields like |
||
761 | // email, password and so on |
||
762 | $doUpdate = false; |
||
763 | foreach ($userUpdateStruct as $propertyValue) { |
||
764 | if ($propertyValue !== null) { |
||
765 | $doUpdate = true; |
||
766 | break; |
||
767 | } |
||
768 | } |
||
769 | |||
770 | if (!$doUpdate) { |
||
771 | // Nothing to update, so we just quit |
||
772 | return $user; |
||
773 | } |
||
774 | |||
775 | if ($userUpdateStruct->email !== null) { |
||
776 | if (!is_string($userUpdateStruct->email) || empty($userUpdateStruct->email)) { |
||
777 | throw new InvalidArgumentValue('email', $userUpdateStruct->email, 'UserUpdateStruct'); |
||
778 | } |
||
779 | |||
780 | if (!preg_match('/^.+@.+\..+$/', $userUpdateStruct->email)) { |
||
781 | throw new InvalidArgumentValue('email', $userUpdateStruct->email, 'UserUpdateStruct'); |
||
782 | } |
||
783 | } |
||
784 | |||
785 | if ($userUpdateStruct->enabled !== null && !is_bool($userUpdateStruct->enabled)) { |
||
786 | throw new InvalidArgumentValue('enabled', $userUpdateStruct->enabled, 'UserUpdateStruct'); |
||
787 | } |
||
788 | |||
789 | if ($userUpdateStruct->maxLogin !== null && !is_int($userUpdateStruct->maxLogin)) { |
||
790 | throw new InvalidArgumentValue('maxLogin', $userUpdateStruct->maxLogin, 'UserUpdateStruct'); |
||
791 | } |
||
792 | |||
793 | if ($userUpdateStruct->password !== null) { |
||
794 | if (!is_string($userUpdateStruct->password) || empty($userUpdateStruct->password)) { |
||
795 | throw new InvalidArgumentValue('password', $userUpdateStruct->password, 'UserUpdateStruct'); |
||
796 | } |
||
797 | |||
798 | $userContentType = $this->repository->getContentTypeService()->loadContentType( |
||
799 | $user->contentInfo->contentTypeId |
||
800 | ); |
||
801 | |||
802 | $errors = $this->validatePassword($userUpdateStruct->password, new PasswordValidationContext([ |
||
803 | 'contentType' => $userContentType, |
||
804 | 'user' => $user, |
||
805 | ])); |
||
806 | |||
807 | if (!empty($errors)) { |
||
808 | throw new UserPasswordValidationException('password', $errors); |
||
809 | } |
||
810 | } |
||
811 | |||
812 | $contentService = $this->repository->getContentService(); |
||
813 | |||
814 | $canEditContent = $this->permissionResolver->canUser('content', 'edit', $loadedUser); |
||
815 | |||
816 | if (!$canEditContent && $this->isUserProfileUpdateRequested($userUpdateStruct)) { |
||
817 | throw new UnauthorizedException('content', 'edit'); |
||
818 | } |
||
819 | |||
820 | if (!empty($userUpdateStruct->password) && |
||
821 | !$canEditContent && |
||
822 | !$this->permissionResolver->canUser('user', 'password', $loadedUser) |
||
823 | ) { |
||
824 | throw new UnauthorizedException('user', 'password'); |
||
825 | } |
||
826 | |||
827 | $this->repository->beginTransaction(); |
||
828 | try { |
||
829 | $publishedContent = $loadedUser; |
||
830 | if ($userUpdateStruct->contentUpdateStruct !== null) { |
||
831 | $contentDraft = $contentService->createContentDraft($loadedUser->getVersionInfo()->getContentInfo()); |
||
832 | $contentDraft = $contentService->updateContent( |
||
833 | $contentDraft->getVersionInfo(), |
||
834 | $userUpdateStruct->contentUpdateStruct |
||
835 | ); |
||
836 | $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo()); |
||
837 | } |
||
838 | |||
839 | if ($userUpdateStruct->contentMetadataUpdateStruct !== null) { |
||
840 | $contentService->updateContentMetadata( |
||
841 | $publishedContent->getVersionInfo()->getContentInfo(), |
||
842 | $userUpdateStruct->contentMetadataUpdateStruct |
||
843 | ); |
||
844 | } |
||
845 | |||
846 | $spiUser = new SPIUser([ |
||
847 | 'id' => $loadedUser->id, |
||
848 | 'login' => $loadedUser->login, |
||
849 | 'email' => $userUpdateStruct->email ?: $loadedUser->email, |
||
850 | 'isEnabled' => $userUpdateStruct->enabled !== null ? $userUpdateStruct->enabled : $loadedUser->enabled, |
||
851 | 'maxLogin' => $userUpdateStruct->maxLogin !== null ? (int)$userUpdateStruct->maxLogin : $loadedUser->maxLogin, |
||
852 | ]); |
||
853 | |||
854 | if ($userUpdateStruct->password) { |
||
855 | $spiUser->passwordHash = $this->createPasswordHash( |
||
856 | $loadedUser->login, |
||
857 | $userUpdateStruct->password, |
||
858 | $this->settings['siteName'], |
||
859 | $this->settings['hashType'] |
||
860 | ); |
||
861 | $spiUser->hashAlgorithm = $this->settings['hashType']; |
||
862 | $spiUser->passwordUpdatedAt = time(); |
||
863 | } else { |
||
864 | $spiUser->passwordHash = $loadedUser->passwordHash; |
||
865 | $spiUser->hashAlgorithm = $loadedUser->hashAlgorithm; |
||
866 | $spiUser->passwordUpdatedAt = $loadedUser->passwordUpdatedAt ? $loadedUser->passwordUpdatedAt->getTimestamp() : null; |
||
867 | } |
||
868 | |||
869 | $this->userHandler->update($spiUser); |
||
870 | |||
871 | $this->repository->commit(); |
||
872 | } catch (Exception $e) { |
||
873 | $this->repository->rollback(); |
||
874 | throw $e; |
||
875 | } |
||
876 | |||
877 | return $this->loadUser($loadedUser->id); |
||
878 | } |
||
879 | |||
880 | /** |
||
881 | * Update the user token information specified by the user token struct. |
||
882 | * |
||
883 | * @param \eZ\Publish\API\Repository\Values\User\User $user |
||
884 | * @param \eZ\Publish\API\Repository\Values\User\UserTokenUpdateStruct $userTokenUpdateStruct |
||
885 | * |
||
886 | * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue |
||
887 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
888 | * @throws \RuntimeException |
||
889 | * @throws \Exception |
||
890 | * |
||
891 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
892 | */ |
||
893 | public function updateUserToken(APIUser $user, UserTokenUpdateStruct $userTokenUpdateStruct) |
||
894 | { |
||
895 | $loadedUser = $this->loadUser($user->id); |
||
896 | |||
897 | if ($userTokenUpdateStruct->hashKey !== null && (!is_string($userTokenUpdateStruct->hashKey) || empty($userTokenUpdateStruct->hashKey))) { |
||
898 | throw new InvalidArgumentValue('hashKey', $userTokenUpdateStruct->hashKey, 'UserTokenUpdateStruct'); |
||
899 | } |
||
900 | |||
901 | if ($userTokenUpdateStruct->time === null) { |
||
902 | throw new InvalidArgumentValue('time', $userTokenUpdateStruct->time, 'UserTokenUpdateStruct'); |
||
903 | } |
||
904 | |||
905 | $this->repository->beginTransaction(); |
||
906 | try { |
||
907 | $this->userHandler->updateUserToken( |
||
908 | new SPIUserTokenUpdateStruct( |
||
909 | [ |
||
910 | 'userId' => $loadedUser->id, |
||
911 | 'hashKey' => $userTokenUpdateStruct->hashKey, |
||
912 | 'time' => $userTokenUpdateStruct->time->getTimestamp(), |
||
913 | ] |
||
914 | ) |
||
915 | ); |
||
916 | $this->repository->commit(); |
||
917 | } catch (Exception $e) { |
||
918 | $this->repository->rollback(); |
||
919 | throw $e; |
||
920 | } |
||
921 | |||
922 | return $this->loadUser($loadedUser->id); |
||
923 | } |
||
924 | |||
925 | /** |
||
926 | * Expires user token with user hash. |
||
927 | * |
||
928 | * @param string $hash |
||
929 | */ |
||
930 | public function expireUserToken($hash) |
||
941 | |||
942 | /** |
||
943 | * Assigns a new user group to the user. |
||
944 | * |
||
945 | * @param \eZ\Publish\API\Repository\Values\User\User $user |
||
946 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
947 | * |
||
948 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to assign the user group to the user |
||
949 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the user is already in the given user group |
||
950 | */ |
||
951 | public function assignUserToUserGroup(APIUser $user, APIUserGroup $userGroup) |
||
988 | |||
989 | /** |
||
990 | * Removes a user group from the user. |
||
991 | * |
||
992 | * @param \eZ\Publish\API\Repository\Values\User\User $user |
||
993 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
994 | * |
||
995 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to remove the user group from the user |
||
996 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the user is not in the given user group |
||
997 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException If $userGroup is the last assigned user group |
||
998 | */ |
||
999 | public function unAssignUserFromUserGroup(APIUser $user, APIUserGroup $userGroup) |
||
1036 | |||
1037 | /** |
||
1038 | * Loads the user groups the user belongs to. |
||
1039 | * |
||
1040 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed read the user or user group |
||
1041 | * |
||
1042 | * @param \eZ\Publish\API\Repository\Values\User\User $user |
||
1043 | * @param int $offset the start offset for paging |
||
1044 | * @param int $limit the number of user groups returned |
||
1045 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
1046 | * |
||
1047 | * @return \eZ\Publish\API\Repository\Values\User\UserGroup[] |
||
1048 | */ |
||
1049 | public function loadUserGroupsOfUser(APIUser $user, $offset = 0, $limit = 25, array $prioritizedLanguages = []) |
||
1050 | { |
||
1051 | $locationService = $this->repository->getLocationService(); |
||
1052 | |||
1053 | if (!$this->repository->getPermissionResolver()->canUser('content', 'read', $user)) { |
||
1054 | throw new UnauthorizedException('content', 'read'); |
||
1055 | } |
||
1056 | |||
1057 | $userLocations = $locationService->loadLocations( |
||
1058 | $user->getVersionInfo()->getContentInfo() |
||
1059 | ); |
||
1060 | |||
1061 | $parentLocationIds = []; |
||
1062 | foreach ($userLocations as $userLocation) { |
||
1063 | if ($userLocation->parentLocationId !== null) { |
||
1064 | $parentLocationIds[] = $userLocation->parentLocationId; |
||
1065 | } |
||
1066 | } |
||
1067 | |||
1068 | $searchQuery = new LocationQuery(); |
||
1069 | |||
1070 | $searchQuery->offset = $offset; |
||
1071 | $searchQuery->limit = $limit; |
||
1072 | $searchQuery->performCount = false; |
||
1073 | |||
1074 | $searchQuery->filter = new CriterionLogicalAnd( |
||
1075 | [ |
||
1076 | new CriterionContentTypeId($this->settings['userGroupClassID']), |
||
1077 | new CriterionLocationId($parentLocationIds), |
||
1078 | ] |
||
1079 | ); |
||
1080 | |||
1081 | $searchResult = $this->repository->getSearchService()->findLocations($searchQuery); |
||
1082 | |||
1083 | $userGroups = []; |
||
1084 | foreach ($searchResult->searchHits as $resultItem) { |
||
1085 | $userGroups[] = $this->buildDomainUserGroupObject( |
||
1086 | $this->repository->getContentService()->internalLoadContent( |
||
1087 | $resultItem->valueObject->contentInfo->id, |
||
1088 | $prioritizedLanguages |
||
1089 | ) |
||
1090 | ); |
||
1091 | } |
||
1092 | |||
1093 | return $userGroups; |
||
1094 | } |
||
1095 | |||
1096 | /** |
||
1097 | * Loads the users of a user group. |
||
1098 | * |
||
1099 | * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to read the users or user group |
||
1100 | * |
||
1101 | * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup |
||
1102 | * @param int $offset the start offset for paging |
||
1103 | * @param int $limit the number of users returned |
||
1104 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
1105 | * |
||
1106 | * @return \eZ\Publish\API\Repository\Values\User\User[] |
||
1107 | */ |
||
1108 | public function loadUsersOfUserGroup( |
||
1153 | |||
1154 | /** |
||
1155 | * {@inheritdoc} |
||
1156 | */ |
||
1157 | public function isUser(APIContent $content): bool |
||
1174 | |||
1175 | /** |
||
1176 | * {@inheritdoc} |
||
1177 | */ |
||
1178 | public function isUserGroup(APIContent $content): bool |
||
1182 | |||
1183 | /** |
||
1184 | * Instantiate a user create class. |
||
1185 | * |
||
1186 | * @param string $login the login of the new user |
||
1187 | * @param string $email the email of the new user |
||
1188 | * @param string $password the plain password of the new user |
||
1189 | * @param string $mainLanguageCode the main language for the underlying content object |
||
1190 | * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType 5.x the content type for the underlying content object. In 4.x it is ignored and taken from the configuration |
||
1191 | * |
||
1192 | * @return \eZ\Publish\API\Repository\Values\User\UserCreateStruct |
||
1193 | */ |
||
1194 | public function newUserCreateStruct($login, $email, $password, $mainLanguageCode, $contentType = null) |
||
1214 | |||
1215 | /** |
||
1216 | * Instantiate a user group create class. |
||
1217 | * |
||
1218 | * @param string $mainLanguageCode The main language for the underlying content object |
||
1219 | * @param null|\eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType 5.x the content type for the underlying content object. In 4.x it is ignored and taken from the configuration |
||
1220 | * |
||
1221 | * @return \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct |
||
1222 | */ |
||
1223 | public function newUserGroupCreateStruct($mainLanguageCode, $contentType = null) |
||
1239 | |||
1240 | /** |
||
1241 | * Instantiate a new user update struct. |
||
1242 | * |
||
1243 | * @return \eZ\Publish\API\Repository\Values\User\UserUpdateStruct |
||
1244 | */ |
||
1245 | public function newUserUpdateStruct() |
||
1249 | |||
1250 | /** |
||
1251 | * Instantiate a new user group update struct. |
||
1252 | * |
||
1253 | * @return \eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct |
||
1254 | */ |
||
1255 | public function newUserGroupUpdateStruct() |
||
1259 | |||
1260 | /** |
||
1261 | * {@inheritdoc} |
||
1262 | */ |
||
1263 | public function validatePassword(string $password, PasswordValidationContext $context = null): array |
||
1295 | |||
1296 | /** |
||
1297 | * Builds the domain UserGroup object from provided Content object. |
||
1298 | * |
||
1299 | * @param \eZ\Publish\API\Repository\Values\Content\Content $content |
||
1300 | * |
||
1301 | * @return \eZ\Publish\API\Repository\Values\User\UserGroup |
||
1302 | */ |
||
1303 | protected function buildDomainUserGroupObject(APIContent $content) |
||
1321 | |||
1322 | /** |
||
1323 | * Builds the domain user object from provided persistence user object. |
||
1324 | * |
||
1325 | * @param \eZ\Publish\SPI\Persistence\User $spiUser |
||
1326 | * @param \eZ\Publish\API\Repository\Values\Content\Content|null $content |
||
1327 | * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
||
1328 | * |
||
1329 | * @return \eZ\Publish\API\Repository\Values\User\User |
||
1330 | */ |
||
1331 | protected function buildDomainUserObject( |
||
1332 | SPIUser $spiUser, |
||
1333 | APIContent $content = null, |
||
1334 | array $prioritizedLanguages = [] |
||
1335 | ) { |
||
1336 | if ($content === null) { |
||
1337 | $content = $this->repository->getContentService()->internalLoadContent( |
||
1338 | $spiUser->id, |
||
1339 | $prioritizedLanguages |
||
1340 | ); |
||
1341 | } |
||
1356 | |||
1357 | public function getPasswordInfo(APIUser $user): PasswordInfo |
||
1388 | |||
1389 | private function getUserFieldDefinition(ContentType $contentType): ?FieldDefinition |
||
1399 | |||
1400 | /** |
||
1401 | * Verifies if the provided login and password are valid. |
||
1402 | * |
||
1403 | * @param string $login User login |
||
1404 | * @param string $password User password |
||
1405 | * @param \eZ\Publish\SPI\Persistence\User $spiUser Loaded user handler |
||
1406 | * |
||
1407 | * @return bool return true if the login and password are sucessfully |
||
1408 | * validate and false, if not. |
||
1409 | */ |
||
1410 | protected function verifyPassword($login, $password, $spiUser) |
||
1430 | |||
1431 | /** |
||
1432 | * Returns password hash based on user data and site settings. |
||
1433 | * |
||
1434 | * @param string $login User login |
||
1435 | * @param string $password User password |
||
1436 | * @param string $site The name of the site |
||
1437 | * @param int $type Type of password to generate |
||
1438 | * |
||
1439 | * @return string Generated password hash |
||
1440 | * |
||
1441 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the type is not recognized |
||
1442 | */ |
||
1443 | protected function createPasswordHash($login, $password, $site, $type) |
||
1478 | |||
1479 | /** |
||
1480 | * Return true if any of the UserUpdateStruct properties refers to User Profile (Content) update. |
||
1481 | * |
||
1482 | * @param UserUpdateStruct $userUpdateStruct |
||
1483 | * |
||
1484 | * @return bool |
||
1485 | */ |
||
1486 | private function isUserProfileUpdateRequested(UserUpdateStruct $userUpdateStruct) |
||
1495 | |||
1496 | private function getDateTime(?int $timestamp): ?DateTimeInterface |
||
1508 | } |
||
1509 |
This check marks calls to methods that do not seem to exist on an object.
This is most likely the result of a method being renamed without all references to it being renamed likewise.