Completed
Push — 7.0 ( b99d59...59754b )
by André
80:45 queued 61:00
created

UserService::createPasswordHash()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 35
Code Lines 21

Duplication

Lines 6
Ratio 17.14 %

Importance

Changes 0
Metric Value
cc 7
eloc 21
nc 7
nop 4
dl 6
loc 35
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the eZ\Publish\Core\Repository\UserService class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Repository;
10
11
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
12
use eZ\Publish\Core\Repository\Values\User\UserCreateStruct;
13
use eZ\Publish\API\Repository\Values\User\UserCreateStruct as APIUserCreateStruct;
14
use eZ\Publish\API\Repository\Values\User\UserUpdateStruct;
15
use eZ\Publish\Core\Repository\Values\User\User;
16
use eZ\Publish\API\Repository\Values\User\User as APIUser;
17
use eZ\Publish\Core\Repository\Values\User\UserGroup;
18
use eZ\Publish\API\Repository\Values\User\UserGroup as APIUserGroup;
19
use eZ\Publish\Core\Repository\Values\User\UserGroupCreateStruct;
20
use eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct as APIUserGroupCreateStruct;
21
use eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct;
22
use eZ\Publish\API\Repository\Values\Content\Location;
23
use eZ\Publish\API\Repository\Values\Content\Content as APIContent;
24
use eZ\Publish\SPI\Persistence\User\Handler;
25
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
26
use eZ\Publish\API\Repository\UserService as UserServiceInterface;
27
use eZ\Publish\SPI\Persistence\User as SPIUser;
28
use eZ\Publish\Core\FieldType\User\Value as UserValue;
29
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalAnd as CriterionLogicalAnd;
30
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\ContentTypeId as CriterionContentTypeId;
31
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LocationId as CriterionLocationId;
32
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\ParentLocationId as CriterionParentLocationId;
33
use eZ\Publish\Core\Base\Exceptions\ContentValidationException;
34
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue;
35
use eZ\Publish\Core\Base\Exceptions\BadStateException;
36
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
37
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
38
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
39
use Exception;
40
41
/**
42
 * This service provides methods for managing users and user groups.
43
 *
44
 * @example Examples/user.php
45
 */
46
class UserService implements UserServiceInterface
47
{
48
    /**
49
     * @var \eZ\Publish\API\Repository\Repository
50
     */
51
    protected $repository;
52
53
    /**
54
     * @var \eZ\Publish\SPI\Persistence\User\Handler
55
     */
56
    protected $userHandler;
57
58
    /**
59
     * @var array
60
     */
61
    protected $settings;
62
63
    /**
64
     * Setups service with reference to repository object that created it & corresponding handler.
65
     *
66
     * @param \eZ\Publish\API\Repository\Repository $repository
67
     * @param \eZ\Publish\SPI\Persistence\User\Handler $userHandler
68
     * @param array $settings
69
     */
70
    public function __construct(RepositoryInterface $repository, Handler $userHandler, array $settings = array())
71
    {
72
        $this->repository = $repository;
73
        $this->userHandler = $userHandler;
74
        // Union makes sure default settings are ignored if provided in argument
75
        $this->settings = $settings + array(
76
            'defaultUserPlacement' => 12,
77
            'userClassID' => 4, // @todo Rename this settings to swap out "Class" for "Type"
78
            'userGroupClassID' => 3,
79
            'hashType' => APIUser::DEFAULT_PASSWORD_HASH,
80
            'siteName' => 'ez.no',
81
        );
82
    }
83
84
    /**
85
     * Creates a new user group using the data provided in the ContentCreateStruct parameter.
86
     *
87
     * In 4.x in the content type parameter in the profile is ignored
88
     * - the content type is determined via configuration and can be set to null.
89
     * The returned version is published.
90
     *
91
     * @param \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct $userGroupCreateStruct a structure for setting all necessary data to create this user group
92
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $parentGroup
93
     *
94
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
95
     *
96
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to create a user group
97
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the input structure has invalid data
98
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userGroupCreateStruct is not valid
99
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is missing or set to an empty value
100
     */
101
    public function createUserGroup(APIUserGroupCreateStruct $userGroupCreateStruct, APIUserGroup $parentGroup)
102
    {
103
        $contentService = $this->repository->getContentService();
104
        $locationService = $this->repository->getLocationService();
105
        $contentTypeService = $this->repository->getContentTypeService();
106
107
        if ($userGroupCreateStruct->contentType === null) {
108
            $userGroupContentType = $contentTypeService->loadContentType($this->settings['userGroupClassID']);
109
            $userGroupCreateStruct->contentType = $userGroupContentType;
110
        }
111
112
        $loadedParentGroup = $this->loadUserGroup($parentGroup->id);
113
114
        if ($loadedParentGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) {
115
            throw new InvalidArgumentException('parentGroup', 'parent user group has no main location');
116
        }
117
118
        $locationCreateStruct = $locationService->newLocationCreateStruct(
119
            $loadedParentGroup->getVersionInfo()->getContentInfo()->mainLocationId
120
        );
121
122
        $this->repository->beginTransaction();
123
        try {
124
            $contentDraft = $contentService->createContent($userGroupCreateStruct, array($locationCreateStruct));
125
            $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo());
126
            $this->repository->commit();
127
        } catch (Exception $e) {
128
            $this->repository->rollback();
129
            throw $e;
130
        }
131
132
        return $this->buildDomainUserGroupObject($publishedContent);
133
    }
134
135
    /**
136
     * Loads a user group for the given id.
137
     *
138
     * @param mixed $id
139
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
140
     *
141
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
142
     *
143
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to create a user group
144
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if the user group with the given id was not found
145
     */
146
    public function loadUserGroup($id, array $prioritizedLanguages = [])
147
    {
148
        $content = $this->repository->getContentService()->loadContent($id, $prioritizedLanguages);
149
150
        return $this->buildDomainUserGroupObject($content);
151
    }
152
153
    /**
154
     * Loads the sub groups of a user group.
155
     *
156
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
157
     * @param int $offset the start offset for paging
158
     * @param int $limit the number of user groups returned
159
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
160
     *
161
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup[]
162
     *
163
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to read the user group
164
     */
165
    public function loadSubUserGroups(APIUserGroup $userGroup, $offset = 0, $limit = 25, array $prioritizedLanguages = [])
166
    {
167
        $locationService = $this->repository->getLocationService();
168
169
        $loadedUserGroup = $this->loadUserGroup($userGroup->id);
170
        if (!$this->repository->canUser('content', 'read', $loadedUserGroup)) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::canUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::canUser() instead. Indicates if the current user is allowed to perform an action given by the function on the given
objects. Example: canUser( 'content', 'edit', $content, $location ); This will check edit permission on content given the specific location, if skipped if will check on all locations. Example2: canUser( 'section', 'assign', $content, $section ); Check if user has access to assign $content to $section.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
171
            throw new UnauthorizedException('content', 'read');
172
        }
173
174
        if ($loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) {
175
            return array();
176
        }
177
178
        $mainGroupLocation = $locationService->loadLocation(
179
            $loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId
180
        );
181
182
        $searchResult = $this->searchSubGroups($mainGroupLocation, $offset, $limit);
183
        if ($searchResult->totalCount == 0) {
184
            return array();
185
        }
186
187
        $subUserGroups = array();
188 View Code Duplication
        foreach ($searchResult->searchHits as $searchHit) {
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...
189
            $subUserGroups[] = $this->buildDomainUserGroupObject(
190
                $this->repository->getContentService()->internalLoadContent(
0 ignored issues
show
Bug introduced by
The method internalLoadContent() does not exist on eZ\Publish\API\Repository\ContentService. Did you maybe mean loadContent()?

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.

Loading history...
191
                    $searchHit->valueObject->contentInfo->id,
0 ignored issues
show
Documentation introduced by
The property contentInfo does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
192
                    $prioritizedLanguages
193
                )
194
            );
195
        }
196
197
        return $subUserGroups;
198
    }
199
200
    /**
201
     * Returns (searches) subgroups of a user group described by its main location.
202
     *
203
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
204
     * @param int $offset
205
     * @param int $limit
206
     *
207
     * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult
208
     */
209
    protected function searchSubGroups(Location $location, $offset = 0, $limit = 25)
210
    {
211
        $searchQuery = new LocationQuery();
212
213
        $searchQuery->offset = $offset;
214
        $searchQuery->limit = $limit;
215
216
        $searchQuery->filter = new CriterionLogicalAnd([
217
            new CriterionContentTypeId($this->settings['userGroupClassID']),
218
            new CriterionParentLocationId($location->id),
219
        ]);
220
221
        $searchQuery->sortClauses = $location->getSortClauses();
0 ignored issues
show
Documentation Bug introduced by
It seems like $location->getSortClauses() of type array<integer,object,{"0":"object"}> is incompatible with the declared type array<integer,object<eZ\...tent\Query\SortClause>> of property $sortClauses.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
222
223
        return $this->repository->getSearchService()->findLocations($searchQuery, array(), false);
224
    }
225
226
    /**
227
     * Removes a user group.
228
     *
229
     * the users which are not assigned to other groups will be deleted.
230
     *
231
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
232
     *
233
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to create a user group
234
     */
235 View Code Duplication
    public function deleteUserGroup(APIUserGroup $userGroup)
236
    {
237
        $loadedUserGroup = $this->loadUserGroup($userGroup->id);
238
239
        $this->repository->beginTransaction();
240
        try {
241
            //@todo: what happens to sub user groups and users below sub user groups
242
            $affectedLocationIds = $this->repository->getContentService()->deleteContent($loadedUserGroup->getVersionInfo()->getContentInfo());
243
            $this->repository->commit();
244
        } catch (Exception $e) {
245
            $this->repository->rollback();
246
            throw $e;
247
        }
248
249
        return $affectedLocationIds;
250
    }
251
252
    /**
253
     * Moves the user group to another parent.
254
     *
255
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
256
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $newParent
257
     *
258
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to move the user group
259
     */
260
    public function moveUserGroup(APIUserGroup $userGroup, APIUserGroup $newParent)
261
    {
262
        $loadedUserGroup = $this->loadUserGroup($userGroup->id);
263
        $loadedNewParent = $this->loadUserGroup($newParent->id);
264
265
        $locationService = $this->repository->getLocationService();
266
267
        if ($loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) {
268
            throw new BadStateException('userGroup', 'existing user group is not stored and/or does not have any location yet');
269
        }
270
271
        if ($loadedNewParent->getVersionInfo()->getContentInfo()->mainLocationId === null) {
272
            throw new BadStateException('newParent', 'new user group is not stored and/or does not have any location yet');
273
        }
274
275
        $userGroupMainLocation = $locationService->loadLocation(
276
            $loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId
277
        );
278
        $newParentMainLocation = $locationService->loadLocation(
279
            $loadedNewParent->getVersionInfo()->getContentInfo()->mainLocationId
280
        );
281
282
        $this->repository->beginTransaction();
283
        try {
284
            $locationService->moveSubtree($userGroupMainLocation, $newParentMainLocation);
285
            $this->repository->commit();
286
        } catch (Exception $e) {
287
            $this->repository->rollback();
288
            throw $e;
289
        }
290
    }
291
292
    /**
293
     * Updates the group profile with fields and meta data.
294
     *
295
     * 4.x: If the versionUpdateStruct is set in $userGroupUpdateStruct, this method internally creates a content draft, updates ts with the provided data
296
     * and publishes the draft. If a draft is explicitly required, the user group can be updated via the content service methods.
297
     *
298
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
299
     * @param \eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct $userGroupUpdateStruct
300
     *
301
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
302
     *
303
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to update the user group
304
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userGroupUpdateStruct is not valid
305
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is set empty
306
     */
307
    public function updateUserGroup(APIUserGroup $userGroup, UserGroupUpdateStruct $userGroupUpdateStruct)
308
    {
309
        if ($userGroupUpdateStruct->contentUpdateStruct === null &&
310
            $userGroupUpdateStruct->contentMetadataUpdateStruct === null) {
311
            // both update structs are empty, nothing to do
312
            return $userGroup;
313
        }
314
315
        $contentService = $this->repository->getContentService();
316
317
        $loadedUserGroup = $this->loadUserGroup($userGroup->id);
318
319
        $this->repository->beginTransaction();
320
        try {
321
            $publishedContent = $loadedUserGroup;
322 View Code Duplication
            if ($userGroupUpdateStruct->contentUpdateStruct !== null) {
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...
323
                $contentDraft = $contentService->createContentDraft($loadedUserGroup->getVersionInfo()->getContentInfo());
324
325
                $contentDraft = $contentService->updateContent(
326
                    $contentDraft->getVersionInfo(),
327
                    $userGroupUpdateStruct->contentUpdateStruct
328
                );
329
330
                $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo());
331
            }
332
333
            if ($userGroupUpdateStruct->contentMetadataUpdateStruct !== null) {
334
                $publishedContent = $contentService->updateContentMetadata(
335
                    $publishedContent->getVersionInfo()->getContentInfo(),
336
                    $userGroupUpdateStruct->contentMetadataUpdateStruct
337
                );
338
            }
339
340
            $this->repository->commit();
341
        } catch (Exception $e) {
342
            $this->repository->rollback();
343
            throw $e;
344
        }
345
346
        return $this->buildDomainUserGroupObject($publishedContent);
347
    }
348
349
    /**
350
     * Create a new user. The created user is published by this method.
351
     *
352
     * @param \eZ\Publish\API\Repository\Values\User\UserCreateStruct $userCreateStruct the data used for creating the user
353
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup[] $parentGroups the groups which are assigned to the user after creation
354
     *
355
     * @return \eZ\Publish\API\Repository\Values\User\User
356
     *
357
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to move the user group
358
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userCreateStruct is not valid
359
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is missing or set to an empty value
360
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if a user with provided login already exists
361
     */
362
    public function createUser(APIUserCreateStruct $userCreateStruct, array $parentGroups)
363
    {
364
        if (empty($parentGroups)) {
365
            throw new InvalidArgumentValue('parentGroups', $parentGroups);
366
        }
367
368
        if (!is_string($userCreateStruct->login) || empty($userCreateStruct->login)) {
369
            throw new InvalidArgumentValue('login', $userCreateStruct->login, 'UserCreateStruct');
370
        }
371
372 View Code Duplication
        if (!is_string($userCreateStruct->email) || empty($userCreateStruct->email)) {
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...
373
            throw new InvalidArgumentValue('email', $userCreateStruct->email, 'UserCreateStruct');
374
        }
375
376
        if (!preg_match('/^.+@.+\..+$/', $userCreateStruct->email)) {
377
            throw new InvalidArgumentValue('email', $userCreateStruct->email, 'UserCreateStruct');
378
        }
379
380
        if (!is_string($userCreateStruct->password) || empty($userCreateStruct->password)) {
381
            throw new InvalidArgumentValue('password', $userCreateStruct->password, 'UserCreateStruct');
382
        }
383
384
        if (!is_bool($userCreateStruct->enabled)) {
385
            throw new InvalidArgumentValue('enabled', $userCreateStruct->enabled, 'UserCreateStruct');
386
        }
387
388
        try {
389
            $this->userHandler->loadByLogin($userCreateStruct->login);
390
            throw new InvalidArgumentException('userCreateStruct', 'User with provided login already exists');
391
        } catch (NotFoundException $e) {
392
            // Do nothing
393
        }
394
395
        $contentService = $this->repository->getContentService();
396
        $locationService = $this->repository->getLocationService();
397
        $contentTypeService = $this->repository->getContentTypeService();
398
399
        if ($userCreateStruct->contentType === null) {
400
            $userContentType = $contentTypeService->loadContentType($this->settings['userClassID']);
401
            $userCreateStruct->contentType = $userContentType;
402
        }
403
404
        $locationCreateStructs = array();
405
        foreach ($parentGroups as $parentGroup) {
406
            $parentGroup = $this->loadUserGroup($parentGroup->id);
407
            if ($parentGroup->getVersionInfo()->getContentInfo()->mainLocationId !== null) {
408
                $locationCreateStructs[] = $locationService->newLocationCreateStruct(
409
                    $parentGroup->getVersionInfo()->getContentInfo()->mainLocationId
410
                );
411
            }
412
        }
413
414
        // Search for the first ezuser field type in content type
415
        $userFieldDefinition = null;
416
        foreach ($userCreateStruct->contentType->getFieldDefinitions() as $fieldDefinition) {
417
            if ($fieldDefinition->fieldTypeIdentifier == 'ezuser') {
418
                $userFieldDefinition = $fieldDefinition;
419
                break;
420
            }
421
        }
422
423
        if ($userFieldDefinition === null) {
424
            throw new ContentValidationException('Provided content type does not contain ezuser field type');
425
        }
426
427
        $fixUserFieldType = true;
428
        foreach ($userCreateStruct->fields as $index => $field) {
429
            if ($field->fieldDefIdentifier == $userFieldDefinition->identifier) {
430
                if ($field->value instanceof UserValue) {
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
431
                    $userCreateStruct->fields[$index]->value->login = $userCreateStruct->login;
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
432
                } else {
433
                    $userCreateStruct->fields[$index]->value = new UserValue(
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
434
                        array(
435
                            'login' => $userCreateStruct->login,
436
                        )
437
                    );
438
                }
439
440
                $fixUserFieldType = false;
441
            }
442
        }
443
444
        if ($fixUserFieldType) {
445
            $userCreateStruct->setField(
446
                $userFieldDefinition->identifier,
447
                new UserValue(
448
                    array(
449
                        'login' => $userCreateStruct->login,
450
                    )
451
                )
452
            );
453
        }
454
455
        $this->repository->beginTransaction();
456
        try {
457
            $contentDraft = $contentService->createContent($userCreateStruct, $locationCreateStructs);
458
            // Create user before publishing, so that external data can be returned
459
            $spiUser = $this->userHandler->create(
460
                new SPIUser(
461
                    array(
462
                        'id' => $contentDraft->id,
463
                        'login' => $userCreateStruct->login,
464
                        'email' => $userCreateStruct->email,
465
                        'passwordHash' => $this->createPasswordHash(
466
                            $userCreateStruct->login,
467
                            $userCreateStruct->password,
468
                            $this->settings['siteName'],
469
                            $this->settings['hashType']
470
                        ),
471
                        'hashAlgorithm' => $this->settings['hashType'],
472
                        'isEnabled' => $userCreateStruct->enabled,
473
                        'maxLogin' => 0,
474
                    )
475
                )
476
            );
477
            $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo());
478
479
            $this->repository->commit();
480
        } catch (Exception $e) {
481
            $this->repository->rollback();
482
            throw $e;
483
        }
484
485
        return $this->buildDomainUserObject($spiUser, $publishedContent);
486
    }
487
488
    /**
489
     * Loads a user.
490
     *
491
     * @param mixed $userId
492
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
493
     *
494
     * @return \eZ\Publish\API\Repository\Values\User\User
495
     *
496
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if a user with the given id was not found
497
     */
498
    public function loadUser($userId, array $prioritizedLanguages = [])
499
    {
500
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $content */
501
        $content = $this->repository->getContentService()->internalLoadContent($userId, $prioritizedLanguages);
0 ignored issues
show
Bug introduced by
The method internalLoadContent() does not exist on eZ\Publish\API\Repository\ContentService. Did you maybe mean loadContent()?

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.

Loading history...
502
        // Get spiUser value from Field Value
503
        foreach ($content->getFields() as $field) {
504
            if (!$field->value instanceof UserValue) {
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
505
                continue;
506
            }
507
508
            /** @var \eZ\Publish\Core\FieldType\User\Value $value */
509
            $value = $field->value;
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
510
            $spiUser = new SPIUser();
511
            $spiUser->id = $value->contentId;
512
            $spiUser->login = $value->login;
513
            $spiUser->email = $value->email;
514
            $spiUser->hashAlgorithm = $value->passwordHashType;
515
            $spiUser->passwordHash = $value->passwordHash;
516
            $spiUser->isEnabled = $value->enabled;
517
            $spiUser->maxLogin = $value->maxLogin;
518
            break;
519
        }
520
521
        // If for some reason not found, load it
522
        if (!isset($spiUser)) {
523
            $spiUser = $this->userHandler->load($userId);
524
        }
525
526
        return $this->buildDomainUserObject($spiUser, $content);
527
    }
528
529
    /**
530
     * Loads anonymous user.
531
     *
532
     * @deprecated since 5.3, use loadUser( $anonymousUserId ) instead
533
     *
534
     * @uses ::loadUser()
535
     *
536
     * @return \eZ\Publish\API\Repository\Values\User\User
537
     */
538
    public function loadAnonymousUser()
539
    {
540
        return $this->loadUser($this->settings['anonymousUserID']);
541
    }
542
543
    /**
544
     * Loads a user for the given login and password.
545
     *
546
     * If the password hash type differs from that configured for the service, it will be updated to the configured one.
547
     *
548
     * {@inheritdoc}
549
     *
550
     * @param string $login
551
     * @param string $password the plain password
552
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
553
     *
554
     * @return \eZ\Publish\API\Repository\Values\User\User
555
     *
556
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if credentials are invalid
557
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if a user with the given credentials was not found
558
     */
559
    public function loadUserByCredentials($login, $password, array $prioritizedLanguages = [])
560
    {
561
        if (!is_string($login) || empty($login)) {
562
            throw new InvalidArgumentValue('login', $login);
563
        }
564
565
        if (!is_string($password)) {
566
            throw new InvalidArgumentValue('password', $password);
567
        }
568
569
        $spiUser = $this->userHandler->loadByLogin($login);
570
        if (!$this->verifyPassword($login, $password, $spiUser)) {
571
            throw new NotFoundException('user', $login);
572
        }
573
574
        $this->updatePasswordHash($login, $password, $spiUser);
575
576
        return $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages);
577
    }
578
579
    /**
580
     * Update password hash to the type configured for the service, if they differ.
581
     *
582
     * @param string $login User login
583
     * @param string $password User password
584
     * @param \eZ\Publish\SPI\Persistence\User $spiUser
585
     */
586
    private function updatePasswordHash($login, $password, SPIUser $spiUser)
587
    {
588
        if ($spiUser->hashAlgorithm !== $this->settings['hashType']) {
589
            $spiUser->passwordHash = $this->createPasswordHash($login, $password, null, $this->settings['hashType']);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createPasswordHas...->settings['hashType']) can also be of type false. However, the property $passwordHash is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
590
            $spiUser->hashAlgorithm = $this->settings['hashType'];
591
            $this->userHandler->update($spiUser);
592
        }
593
    }
594
595
    /**
596
     * Loads a user for the given login.
597
     *
598
     * {@inheritdoc}
599
     *
600
     * @param string $login
601
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
602
     *
603
     * @return \eZ\Publish\API\Repository\Values\User\User
604
     *
605
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if a user with the given credentials was not found
606
     */
607
    public function loadUserByLogin($login, array $prioritizedLanguages = [])
608
    {
609
        if (!is_string($login) || empty($login)) {
610
            throw new InvalidArgumentValue('login', $login);
611
        }
612
613
        $spiUser = $this->userHandler->loadByLogin($login);
614
615
        return $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages);
616
    }
617
618
    /**
619
     * Loads a user for the given email.
620
     *
621
     * {@inheritdoc}
622
     *
623
     * @param string $email
624
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
625
     *
626
     * @return \eZ\Publish\API\Repository\Values\User\User[]
627
     */
628
    public function loadUsersByEmail($email, array $prioritizedLanguages = [])
629
    {
630
        if (!is_string($email) || empty($email)) {
631
            throw new InvalidArgumentValue('email', $email);
632
        }
633
634
        $users = array();
635
        foreach ($this->userHandler->loadByEmail($email) as $spiUser) {
636
            $users[] = $this->buildDomainUserObject($spiUser, null, $prioritizedLanguages);
637
        }
638
639
        return $users;
640
    }
641
642
    /**
643
     * This method deletes a user.
644
     *
645
     * @param \eZ\Publish\API\Repository\Values\User\User $user
646
     *
647
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to delete the user
648
     */
649 View Code Duplication
    public function deleteUser(APIUser $user)
650
    {
651
        $loadedUser = $this->loadUser($user->id);
652
653
        $this->repository->beginTransaction();
654
        try {
655
            $affectedLocationIds = $this->repository->getContentService()->deleteContent($loadedUser->getVersionInfo()->getContentInfo());
656
            $this->userHandler->delete($loadedUser->id);
657
            $this->repository->commit();
658
        } catch (Exception $e) {
659
            $this->repository->rollback();
660
            throw $e;
661
        }
662
663
        return $affectedLocationIds;
664
    }
665
666
    /**
667
     * Updates a user.
668
     *
669
     * 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
670
     * and publishes the draft. If a draft is explicitly required, the user group can be updated via the content service methods.
671
     *
672
     * @param \eZ\Publish\API\Repository\Values\User\User $user
673
     * @param \eZ\Publish\API\Repository\Values\User\UserUpdateStruct $userUpdateStruct
674
     *
675
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to update the user
676
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $userUpdateStruct is not valid
677
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is set empty
678
     *
679
     * @return \eZ\Publish\API\Repository\Values\User\User
680
     */
681
    public function updateUser(APIUser $user, UserUpdateStruct $userUpdateStruct)
682
    {
683
        $loadedUser = $this->loadUser($user->id);
684
685
        // We need to determine if we have anything to update.
686
        // UserUpdateStruct is specific as some of the new content is in
687
        // content update struct and some of it is in additional fields like
688
        // email, password and so on
689
        $doUpdate = false;
690
        foreach ($userUpdateStruct as $propertyValue) {
0 ignored issues
show
Bug introduced by
The expression $userUpdateStruct of type object<eZ\Publish\API\Re...\User\UserUpdateStruct> is not traversable.
Loading history...
691
            if ($propertyValue !== null) {
692
                $doUpdate = true;
693
                break;
694
            }
695
        }
696
697
        if (!$doUpdate) {
698
            // Nothing to update, so we just quit
699
            return $user;
700
        }
701
702
        if ($userUpdateStruct->email !== null) {
703 View Code Duplication
            if (!is_string($userUpdateStruct->email) || empty($userUpdateStruct->email)) {
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...
704
                throw new InvalidArgumentValue('email', $userUpdateStruct->email, 'UserUpdateStruct');
705
            }
706
707
            if (!preg_match('/^.+@.+\..+$/', $userUpdateStruct->email)) {
708
                throw new InvalidArgumentValue('email', $userUpdateStruct->email, 'UserUpdateStruct');
709
            }
710
        }
711
712 View Code Duplication
        if ($userUpdateStruct->password !== null && (!is_string($userUpdateStruct->password) || empty($userUpdateStruct->password))) {
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...
713
            throw new InvalidArgumentValue('password', $userUpdateStruct->password, 'UserUpdateStruct');
714
        }
715
716
        if ($userUpdateStruct->enabled !== null && !is_bool($userUpdateStruct->enabled)) {
717
            throw new InvalidArgumentValue('enabled', $userUpdateStruct->enabled, 'UserUpdateStruct');
718
        }
719
720
        if ($userUpdateStruct->maxLogin !== null && !is_int($userUpdateStruct->maxLogin)) {
721
            throw new InvalidArgumentValue('maxLogin', $userUpdateStruct->maxLogin, 'UserUpdateStruct');
722
        }
723
724
        $contentService = $this->repository->getContentService();
725
726
        if (!$this->repository->canUser('content', 'edit', $loadedUser)) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::canUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::canUser() instead. Indicates if the current user is allowed to perform an action given by the function on the given
objects. Example: canUser( 'content', 'edit', $content, $location ); This will check edit permission on content given the specific location, if skipped if will check on all locations. Example2: canUser( 'section', 'assign', $content, $section ); Check if user has access to assign $content to $section.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
727
            throw new UnauthorizedException('content', 'edit');
728
        }
729
730
        $this->repository->beginTransaction();
731
        try {
732
            $publishedContent = $loadedUser;
733 View Code Duplication
            if ($userUpdateStruct->contentUpdateStruct !== null) {
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...
734
                $contentDraft = $contentService->createContentDraft($loadedUser->getVersionInfo()->getContentInfo());
735
                $contentDraft = $contentService->updateContent(
736
                    $contentDraft->getVersionInfo(),
737
                    $userUpdateStruct->contentUpdateStruct
738
                );
739
                $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo());
740
            }
741
742
            if ($userUpdateStruct->contentMetadataUpdateStruct !== null) {
743
                $contentService->updateContentMetadata(
744
                    $publishedContent->getVersionInfo()->getContentInfo(),
745
                    $userUpdateStruct->contentMetadataUpdateStruct
746
                );
747
            }
748
749
            $this->userHandler->update(
750
                new SPIUser(
751
                    array(
752
                        'id' => $loadedUser->id,
753
                        'login' => $loadedUser->login,
0 ignored issues
show
Documentation introduced by
The property $login is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
754
                        'email' => $userUpdateStruct->email ?: $loadedUser->email,
0 ignored issues
show
Documentation introduced by
The property $email is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
755
                        'passwordHash' => $userUpdateStruct->password ?
756
                            $this->createPasswordHash(
757
                                $loadedUser->login,
0 ignored issues
show
Documentation introduced by
The property $login is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
758
                                $userUpdateStruct->password,
759
                                $this->settings['siteName'],
760
                                $this->settings['hashType']
761
                            ) :
762
                            $loadedUser->passwordHash,
0 ignored issues
show
Documentation introduced by
The property $passwordHash is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
763
                        'hashAlgorithm' => $userUpdateStruct->password ?
764
                            $this->settings['hashType'] :
765
                            $loadedUser->hashAlgorithm,
0 ignored issues
show
Documentation introduced by
The property $hashAlgorithm is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
766
                        'isEnabled' => $userUpdateStruct->enabled !== null ? $userUpdateStruct->enabled : $loadedUser->enabled,
0 ignored issues
show
Documentation introduced by
The property $enabled is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
767
                        'maxLogin' => $userUpdateStruct->maxLogin !== null ? (int)$userUpdateStruct->maxLogin : $loadedUser->maxLogin,
0 ignored issues
show
Documentation introduced by
The property $maxLogin is declared protected in eZ\Publish\API\Repository\Values\User\User. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
768
                    )
769
                )
770
            );
771
772
            $this->repository->commit();
773
        } catch (Exception $e) {
774
            $this->repository->rollback();
775
            throw $e;
776
        }
777
778
        return $this->loadUser($loadedUser->id);
779
    }
780
781
    /**
782
     * Assigns a new user group to the user.
783
     *
784
     * @param \eZ\Publish\API\Repository\Values\User\User $user
785
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
786
     *
787
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to assign the user group to the user
788
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the user is already in the given user group
789
     */
790
    public function assignUserToUserGroup(APIUser $user, APIUserGroup $userGroup)
791
    {
792
        $loadedUser = $this->loadUser($user->id);
793
        $loadedGroup = $this->loadUserGroup($userGroup->id);
794
        $locationService = $this->repository->getLocationService();
795
796
        $existingGroupIds = array();
797
        $userLocations = $locationService->loadLocations($loadedUser->getVersionInfo()->getContentInfo());
798
        foreach ($userLocations as $userLocation) {
799
            $existingGroupIds[] = $userLocation->parentLocationId;
800
        }
801
802
        if ($loadedGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) {
803
            throw new BadStateException('userGroup', 'user group has no main location or no locations');
804
        }
805
806
        if (in_array($loadedGroup->getVersionInfo()->getContentInfo()->mainLocationId, $existingGroupIds)) {
807
            // user is already assigned to the user group
808
            throw new InvalidArgumentException('user', 'user is already in the given user group');
809
        }
810
811
        $locationCreateStruct = $locationService->newLocationCreateStruct(
812
            $loadedGroup->getVersionInfo()->getContentInfo()->mainLocationId
813
        );
814
815
        $this->repository->beginTransaction();
816
        try {
817
            $locationService->createLocation(
818
                $loadedUser->getVersionInfo()->getContentInfo(),
819
                $locationCreateStruct
820
            );
821
            $this->repository->commit();
822
        } catch (Exception $e) {
823
            $this->repository->rollback();
824
            throw $e;
825
        }
826
    }
827
828
    /**
829
     * Removes a user group from the user.
830
     *
831
     * @param \eZ\Publish\API\Repository\Values\User\User $user
832
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
833
     *
834
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to remove the user group from the user
835
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the user is not in the given user group
836
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException If $userGroup is the last assigned user group
837
     */
838
    public function unAssignUserFromUserGroup(APIUser $user, APIUserGroup $userGroup)
839
    {
840
        $loadedUser = $this->loadUser($user->id);
841
        $loadedGroup = $this->loadUserGroup($userGroup->id);
842
        $locationService = $this->repository->getLocationService();
843
844
        $userLocations = $locationService->loadLocations($loadedUser->getVersionInfo()->getContentInfo());
845
        if (empty($userLocations)) {
846
            throw new BadStateException('user', 'user has no locations, cannot unassign from group');
847
        }
848
849
        if ($loadedGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) {
850
            throw new BadStateException('userGroup', 'user group has no main location or no locations, cannot unassign');
851
        }
852
853
        foreach ($userLocations as $userLocation) {
854
            if ($userLocation->parentLocationId == $loadedGroup->getVersionInfo()->getContentInfo()->mainLocationId) {
855
                // Throw this specific BadState when we know argument is valid
856
                if (count($userLocations) === 1) {
857
                    throw new BadStateException('user', 'user only has one user group, cannot unassign from last group');
858
                }
859
860
                $this->repository->beginTransaction();
861
                try {
862
                    $locationService->deleteLocation($userLocation);
863
                    $this->repository->commit();
864
865
                    return;
866
                } catch (Exception $e) {
867
                    $this->repository->rollback();
868
                    throw $e;
869
                }
870
            }
871
        }
872
873
        throw new InvalidArgumentException('userGroup', 'user is not in the given user group');
874
    }
875
876
    /**
877
     * Loads the user groups the user belongs to.
878
     *
879
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed read the user or user group
880
     *
881
     * @param \eZ\Publish\API\Repository\Values\User\User $user
882
     * @param int $offset the start offset for paging
883
     * @param int $limit the number of user groups returned
884
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
885
     *
886
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup[]
887
     */
888
    public function loadUserGroupsOfUser(APIUser $user, $offset = 0, $limit = 25, array $prioritizedLanguages = [])
889
    {
890
        $locationService = $this->repository->getLocationService();
891
892
        if (!$this->repository->getPermissionResolver()->canUser('content', 'read', $user)) {
893
            throw new UnauthorizedException('content', 'read');
894
        }
895
896
        $userLocations = $locationService->loadLocations(
897
            $user->getVersionInfo()->getContentInfo()
898
        );
899
900
        $parentLocationIds = array();
901
        foreach ($userLocations as $userLocation) {
902
            if ($userLocation->parentLocationId !== null) {
903
                $parentLocationIds[] = $userLocation->parentLocationId;
904
            }
905
        }
906
907
        $searchQuery = new LocationQuery();
908
909
        $searchQuery->offset = $offset;
910
        $searchQuery->limit = $limit;
911
        $searchQuery->performCount = false;
912
913
        $searchQuery->filter = new CriterionLogicalAnd(
914
            [
915
                new CriterionContentTypeId($this->settings['userGroupClassID']),
916
                new CriterionLocationId($parentLocationIds),
917
            ]
918
        );
919
920
        $searchResult = $this->repository->getSearchService()->findLocations($searchQuery);
921
922
        $userGroups = [];
923 View Code Duplication
        foreach ($searchResult->searchHits as $resultItem) {
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...
924
            $userGroups[] = $this->buildDomainUserGroupObject(
925
                $this->repository->getContentService()->internalLoadContent(
0 ignored issues
show
Bug introduced by
The method internalLoadContent() does not exist on eZ\Publish\API\Repository\ContentService. Did you maybe mean loadContent()?

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.

Loading history...
926
                    $resultItem->valueObject->contentInfo->id,
0 ignored issues
show
Documentation introduced by
The property contentInfo does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
927
                    $prioritizedLanguages
928
                )
929
            );
930
        }
931
932
        return $userGroups;
933
    }
934
935
    /**
936
     * Loads the users of a user group.
937
     *
938
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the authenticated user is not allowed to read the users or user group
939
     *
940
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
941
     * @param int $offset the start offset for paging
942
     * @param int $limit the number of users returned
943
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
944
     *
945
     * @return \eZ\Publish\API\Repository\Values\User\User[]
946
     */
947
    public function loadUsersOfUserGroup(
948
        APIUserGroup $userGroup,
949
        $offset = 0,
950
        $limit = 25,
951
        array $prioritizedLanguages = []
952
    ) {
953
        $loadedUserGroup = $this->loadUserGroup($userGroup->id);
954
955
        if ($loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId === null) {
956
            return [];
957
        }
958
959
        $mainGroupLocation = $this->repository->getLocationService()->loadLocation(
960
            $loadedUserGroup->getVersionInfo()->getContentInfo()->mainLocationId
961
        );
962
963
        $searchQuery = new LocationQuery();
964
965
        $searchQuery->filter = new CriterionLogicalAnd(
966
            [
967
                new CriterionContentTypeId($this->settings['userClassID']),
968
                new CriterionParentLocationId($mainGroupLocation->id),
969
            ]
970
        );
971
972
        $searchQuery->offset = $offset;
973
        $searchQuery->limit = $limit;
974
        $searchQuery->performCount = false;
975
        $searchQuery->sortClauses = $mainGroupLocation->getSortClauses();
0 ignored issues
show
Documentation Bug introduced by
It seems like $mainGroupLocation->getSortClauses() of type array<integer,object,{"0":"object"}> is incompatible with the declared type array<integer,object<eZ\...tent\Query\SortClause>> of property $sortClauses.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
976
977
        $searchResult = $this->repository->getSearchService()->findLocations($searchQuery);
978
979
        $users = [];
980
        foreach ($searchResult->searchHits as $resultItem) {
981
            $users[] = $this->buildDomainUserObject(
982
                $this->userHandler->load($resultItem->valueObject->contentInfo->id),
0 ignored issues
show
Documentation introduced by
The property contentInfo does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
983
                $this->repository->getContentService()->internalLoadContent(
0 ignored issues
show
Bug introduced by
The method internalLoadContent() does not exist on eZ\Publish\API\Repository\ContentService. Did you maybe mean loadContent()?

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.

Loading history...
984
                    $resultItem->valueObject->contentInfo->id,
0 ignored issues
show
Documentation introduced by
The property contentInfo does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
985
                    $prioritizedLanguages
986
                )
987
            );
988
        }
989
990
        return $users;
991
    }
992
993
    /**
994
     * Instantiate a user create class.
995
     *
996
     * @param string $login the login of the new user
997
     * @param string $email the email of the new user
998
     * @param string $password the plain password of the new user
999
     * @param string $mainLanguageCode the main language for the underlying content object
1000
     * @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
1001
     *
1002
     * @return \eZ\Publish\API\Repository\Values\User\UserCreateStruct
1003
     */
1004
    public function newUserCreateStruct($login, $email, $password, $mainLanguageCode, $contentType = null)
1005
    {
1006
        if ($contentType === null) {
1007
            $contentType = $this->repository->getContentTypeService()->loadContentType(
1008
                $this->settings['userClassID']
1009
            );
1010
        }
1011
1012
        return new UserCreateStruct(
1013
            array(
1014
                'contentType' => $contentType,
1015
                'mainLanguageCode' => $mainLanguageCode,
1016
                'login' => $login,
1017
                'email' => $email,
1018
                'password' => $password,
1019
                'enabled' => true,
1020
                'fields' => array(),
1021
            )
1022
        );
1023
    }
1024
1025
    /**
1026
     * Instantiate a user group create class.
1027
     *
1028
     * @param string $mainLanguageCode The main language for the underlying content object
1029
     * @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
1030
     *
1031
     * @return \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct
1032
     */
1033
    public function newUserGroupCreateStruct($mainLanguageCode, $contentType = null)
1034
    {
1035
        if ($contentType === null) {
1036
            $contentType = $this->repository->getContentTypeService()->loadContentType(
1037
                $this->settings['userGroupClassID']
1038
            );
1039
        }
1040
1041
        return new UserGroupCreateStruct(
1042
            array(
1043
                'contentType' => $contentType,
1044
                'mainLanguageCode' => $mainLanguageCode,
1045
                'fields' => array(),
1046
            )
1047
        );
1048
    }
1049
1050
    /**
1051
     * Instantiate a new user update struct.
1052
     *
1053
     * @return \eZ\Publish\API\Repository\Values\User\UserUpdateStruct
1054
     */
1055
    public function newUserUpdateStruct()
1056
    {
1057
        return new UserUpdateStruct();
1058
    }
1059
1060
    /**
1061
     * Instantiate a new user group update struct.
1062
     *
1063
     * @return \eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct
1064
     */
1065
    public function newUserGroupUpdateStruct()
1066
    {
1067
        return new UserGroupUpdateStruct();
1068
    }
1069
1070
    /**
1071
     * Builds the domain UserGroup object from provided Content object.
1072
     *
1073
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1074
     *
1075
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
1076
     */
1077
    protected function buildDomainUserGroupObject(APIContent $content)
1078
    {
1079
        $locationService = $this->repository->getLocationService();
1080
1081
        $subGroupCount = 0;
1082
        if ($content->getVersionInfo()->getContentInfo()->mainLocationId !== null) {
1083
            $mainLocation = $locationService->loadLocation(
1084
                $content->getVersionInfo()->getContentInfo()->mainLocationId
1085
            );
1086
            $parentLocation = $locationService->loadLocation($mainLocation->parentLocationId);
1087
            $subGroups = $this->searchSubGroups($mainLocation, 0, 0);
1088
            $subGroupCount = $subGroups->totalCount;
1089
        }
1090
1091
        return new UserGroup(
1092
            array(
1093
                'content' => $content,
1094
                'parentId' => isset($parentLocation) ? $parentLocation->contentId : null,
1095
                'subGroupCount' => $subGroupCount,
1096
            )
1097
        );
1098
    }
1099
1100
    /**
1101
     * Builds the domain user object from provided persistence user object.
1102
     *
1103
     * @param \eZ\Publish\SPI\Persistence\User $spiUser
1104
     * @param \eZ\Publish\API\Repository\Values\Content\Content|null $content
1105
     * @param string[] $prioritizedLanguages Used as prioritized language code on translated properties of returned object.
1106
     *
1107
     * @return \eZ\Publish\API\Repository\Values\User\User
1108
     */
1109
    protected function buildDomainUserObject(
1110
        SPIUser $spiUser,
1111
        APIContent $content = null,
1112
        array $prioritizedLanguages = []
1113
    ) {
1114
        if ($content === null) {
1115
            $content = $this->repository->getContentService()->internalLoadContent(
0 ignored issues
show
Bug introduced by
The method internalLoadContent() does not exist on eZ\Publish\API\Repository\ContentService. Did you maybe mean loadContent()?

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.

Loading history...
1116
                $spiUser->id,
1117
                $prioritizedLanguages
1118
            );
1119
        }
1120
1121
        return new User(
1122
            array(
1123
                'content' => $content,
1124
                'login' => $spiUser->login,
1125
                'email' => $spiUser->email,
1126
                'passwordHash' => $spiUser->passwordHash,
1127
                'hashAlgorithm' => (int)$spiUser->hashAlgorithm,
1128
                'enabled' => $spiUser->isEnabled,
1129
                'maxLogin' => (int)$spiUser->maxLogin,
1130
            )
1131
        );
1132
    }
1133
1134
    /**
1135
     * Verifies if the provided login and password are valid.
1136
     *
1137
     * @param string $login User login
1138
     * @param string $password User password
1139
     * @param \eZ\Publish\SPI\Persistence\User $spiUser Loaded user handler
1140
     *
1141
     * @return bool return true if the login and password are sucessfully
1142
     * validate and false, if not.
1143
     */
1144
    protected function verifyPassword($login, $password, $spiUser)
1145
    {
1146
        // In case of bcrypt let php's password functionality do it's magic
1147
        if ($spiUser->hashAlgorithm === APIUser::PASSWORD_HASH_BCRYPT ||
1148
            $spiUser->hashAlgorithm === APIUser::PASSWORD_HASH_PHP_DEFAULT) {
1149
            return password_verify($password, $spiUser->passwordHash);
1150
        }
1151
1152
        // Randomize login time to protect against timing attacks
1153
        usleep(mt_rand(0, 30000));
1154
1155
        $passwordHash = $this->createPasswordHash(
1156
            $login,
1157
            $password,
1158
            $this->settings['siteName'],
1159
            $spiUser->hashAlgorithm
1160
        );
1161
1162
        return $passwordHash === $spiUser->passwordHash;
1163
    }
1164
1165
    /**
1166
     * Returns password hash based on user data and site settings.
1167
     *
1168
     * @param string $login User login
1169
     * @param string $password User password
1170
     * @param string $site The name of the site
1171
     * @param int $type Type of password to generate
1172
     *
1173
     * @return string Generated password hash
1174
     *
1175
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the type is not recognized
1176
     */
1177
    protected function createPasswordHash($login, $password, $site, $type)
1178
    {
1179
        $deprecationWarningFormat = 'Password hash type %s is deprecated since 6.13.';
1180
1181
        switch ($type) {
1182
            case APIUser::PASSWORD_HASH_MD5_PASSWORD:
0 ignored issues
show
Deprecated Code introduced by
The constant eZ\Publish\API\Repositor...SWORD_HASH_MD5_PASSWORD has been deprecated with message: since 6.13

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1183
                @trigger_error(sprintf($deprecationWarningFormat, 'PASSWORD_HASH_MD5_PASSWORD'), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1184
1185
                return md5($password);
1186
1187 View Code Duplication
            case APIUser::PASSWORD_HASH_MD5_USER:
0 ignored issues
show
Deprecated Code introduced by
The constant eZ\Publish\API\Repositor...:PASSWORD_HASH_MD5_USER has been deprecated with message: since 6.13

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
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...
1188
                @trigger_error(sprintf($deprecationWarningFormat, 'PASSWORD_HASH_MD5_USER'), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1189
1190
                return md5("$login\n$password");
1191
1192 View Code Duplication
            case APIUser::PASSWORD_HASH_MD5_SITE:
0 ignored issues
show
Deprecated Code introduced by
The constant eZ\Publish\API\Repositor...:PASSWORD_HASH_MD5_SITE has been deprecated with message: since 6.13

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
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...
1193
                @trigger_error(sprintf($deprecationWarningFormat, 'PASSWORD_HASH_MD5_SITE'), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1194
1195
                return md5("$login\n$password\n$site");
1196
1197
            case APIUser::PASSWORD_HASH_PLAINTEXT:
0 ignored issues
show
Deprecated Code introduced by
The constant eZ\Publish\API\Repositor...PASSWORD_HASH_PLAINTEXT has been deprecated with message: since 6.13

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
1198
                @trigger_error(sprintf($deprecationWarningFormat, 'PASSWORD_HASH_PLAINTEXT'), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1199
1200
                return $password;
1201
1202
            case APIUser::PASSWORD_HASH_BCRYPT:
1203
                return password_hash($password, PASSWORD_BCRYPT);
1204
1205
            case APIUser::PASSWORD_HASH_PHP_DEFAULT:
1206
                return password_hash($password, PASSWORD_DEFAULT);
1207
1208
            default:
1209
                throw new InvalidArgumentException('type', "Password hash type '$type' is not recognized");
1210
        }
1211
    }
1212
}
1213