Completed
Push — ezp26179-rest_session_refresh_... ( 3cfe0a )
by
unknown
33:58
created

User::setTokenStorage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
/**
4
 * File containing the User controller 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
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\Core\REST\Server\Controller;
12
13
use eZ\Publish\Core\REST\Common\Message;
14
use eZ\Publish\Core\REST\Server\Values;
15
use eZ\Publish\Core\REST\Server\Exceptions;
16
use eZ\Publish\Core\REST\Server\Controller as RestController;
17
use eZ\Publish\API\Repository\UserService;
18
use eZ\Publish\API\Repository\ContentService;
19
use eZ\Publish\API\Repository\ContentTypeService;
20
use eZ\Publish\API\Repository\RoleService;
21
use eZ\Publish\API\Repository\LocationService;
22
use eZ\Publish\API\Repository\SectionService;
23
use eZ\Publish\API\Repository\Repository;
24
use eZ\Publish\API\Repository\Values\User\UserRoleAssignment;
25
use eZ\Publish\API\Repository\Values\User\UserGroupRoleAssignment;
26
use eZ\Publish\API\Repository\Values\User\User as RepositoryUser;
27
use eZ\Publish\API\Repository\Exceptions as ApiExceptions;
28
use eZ\Publish\Core\REST\Common\Exceptions\NotFoundException as RestNotFoundException;
29
use eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException;
30
use eZ\Publish\Core\REST\Common\Exceptions\NotFoundException;
31
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
32
use Symfony\Component\DependencyInjection\ContainerInterface;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
35
use Symfony\Component\Security\Core\Exception\AuthenticationException;
36
use Symfony\Component\Security\Core\Exception\SessionUnavailableException;
37
use Symfony\Component\Security\Csrf\CsrfToken;
38
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
39
40
/**
41
 * User controller.
42
 */
43
class User extends RestController
44
{
45
    /**
46
     * User service.
47
     *
48
     * @var \eZ\Publish\API\Repository\UserService
49
     */
50
    protected $userService;
51
52
    /**
53
     * Role service.
54
     *
55
     * @var \eZ\Publish\API\Repository\RoleService
56
     */
57
    protected $roleService;
58
59
    /**
60
     * Content service.
61
     *
62
     * @var \eZ\Publish\API\Repository\ContentService
63
     */
64
    protected $contentService;
65
66
    /**
67
     * Content service.
68
     *
69
     * @var \eZ\Publish\API\Repository\ContentTypeService
70
     */
71
    protected $contentTypeService;
72
73
    /**
74
     * Location service.
75
     *
76
     * @var \eZ\Publish\API\Repository\LocationService
77
     */
78
    protected $locationService;
79
80
    /**
81
     * Section service.
82
     *
83
     * @var \eZ\Publish\API\Repository\SectionService
84
     */
85
    protected $sectionService;
86
87
    /**
88
     * Repository.
89
     *
90
     * @var \eZ\Publish\API\Repository\Repository
91
     */
92
    protected $repository;
93
94
    /**
95
     * @var \Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface
96
     */private $csrfTokenStorage;
97
98
    /**
99
     * Construct controller.
100
     *
101
     * @param \eZ\Publish\API\Repository\UserService $userService
102
     * @param \eZ\Publish\API\Repository\RoleService $roleService
103
     * @param \eZ\Publish\API\Repository\ContentService $contentService
104
     * @param \eZ\Publish\API\Repository\LocationService $locationService
105
     * @param \eZ\Publish\API\Repository\SectionService $sectionService
106
     * @param \eZ\Publish\API\Repository\Repository $repository
107
     */
108
    public function __construct(
109
        UserService $userService,
110
        RoleService $roleService,
111
        ContentService $contentService,
112
        ContentTypeService $contentTypeService,
113
        LocationService $locationService,
114
        SectionService $sectionService,
115
        Repository $repository
116
    ) {
117
        $this->userService = $userService;
118
        $this->roleService = $roleService;
119
        $this->contentService = $contentService;
120
        $this->contentTypeService = $contentTypeService;
121
        $this->locationService = $locationService;
122
        $this->sectionService = $sectionService;
123
        $this->repository = $repository;
124
    }
125
126
    /**
127
     * Redirects to the root user group.
128
     *
129
     * @return \eZ\Publish\Core\REST\Server\Values\PermanentRedirect
130
     */
131
    public function loadRootUserGroup()
132
    {
133
        //@todo Replace hardcoded value with one loaded from settings
134
        return new Values\PermanentRedirect(
135
            $this->router->generate('ezpublish_rest_loadUserGroup', array('groupPath' => '/1/5'))
136
        );
137
    }
138
139
    /**
140
     * Loads a user group for the given path.
141
     *
142
     * @param $groupPath
143
     *
144
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup
145
     */
146
    public function loadUserGroup($groupPath)
147
    {
148
        $userGroupLocation = $this->locationService->loadLocation(
149
            $this->extractLocationIdFromPath($groupPath)
150
        );
151
152
        if (trim($userGroupLocation->pathString, '/') != $groupPath) {
153
            throw new NotFoundException(
154
                "Could not find location with path string $groupPath"
155
            );
156
        }
157
158
        $userGroup = $this->userService->loadUserGroup(
159
            $userGroupLocation->contentId
160
        );
161
        $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
162
        $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
163
164
        return new Values\CachedValue(
165
            new Values\RestUserGroup(
166
                $userGroup,
167
                $contentType,
168
                $userGroupContentInfo,
169
                $userGroupLocation,
170
                $this->contentService->loadRelations($userGroup->getVersionInfo())
171
            ),
172
            array('locationId' => $userGroupLocation->id)
173
        );
174
    }
175
176
    /**
177
     * Loads a user for the given ID.
178
     *
179
     * @param $userId
180
     *
181
     * @return \eZ\Publish\Core\REST\Server\Values\RestUser
182
     */
183
    public function loadUser($userId)
184
    {
185
        $user = $this->userService->loadUser($userId);
186
187
        $userContentInfo = $user->getVersionInfo()->getContentInfo();
188
        $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
189
190
        try {
191
            $userMainLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
192
            $relations = $this->contentService->loadRelations($user->getVersionInfo());
193
        } catch (UnauthorizedException $e) {
194
            // TODO: Hack for special case to allow current logged in user to load him/here self (but not relations)
195
            if ($user->id == $this->repository->getCurrentUser()->id) {
196
                $userMainLocation = $this->repository->sudo(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\API\Repository\Repository as the method sudo() does only exist in the following implementations of said interface: eZ\Publish\Core\Repository\Repository, eZ\Publish\Core\SignalSlot\Repository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
197
                    function () use ($userContentInfo) {
198
                        return $this->locationService->loadLocation($userContentInfo->mainLocationId);
199
                    }
200
                );
201
                // user may not have permissions to read related content, for security reasons do not use sudo().
202
                $relations = array();
203
            } else {
204
                throw $e;
205
            }
206
        }
207
208
        return new Values\CachedValue(
209
            new Values\RestUser(
210
                $user,
211
                $contentType,
212
                $userContentInfo,
213
                $userMainLocation,
214
                $relations
215
            ),
216
            array('locationId' => $userContentInfo->mainLocationId)
217
        );
218
    }
219
220
    /**
221
     * Create a new user group under the given parent
222
     * To create a top level group use /user/groups/1/5/subgroups.
223
     *
224
     * @param $groupPath
225
     *
226
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\BadRequestException
227
     *
228
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedUserGroup
229
     */
230
    public function createUserGroup($groupPath, Request $request)
231
    {
232
        $userGroupLocation = $this->locationService->loadLocation(
233
            $this->extractLocationIdFromPath($groupPath)
234
        );
235
236
        $createdUserGroup = $this->userService->createUserGroup(
237
            $this->inputDispatcher->parse(
0 ignored issues
show
Compatibility introduced by
$this->inputDispatcher->...request->getContent())) of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...\UserGroupCreateStruct>. It seems like you assume a child class of the class eZ\Publish\API\Repository\Values\ValueObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
238
                new Message(
239
                    array('Content-Type' => $request->headers->get('Content-Type')),
240
                    $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
241
                )
242
            ),
243
            $this->userService->loadUserGroup(
244
                $userGroupLocation->contentId
245
            )
246
        );
247
248
        $createdContentInfo = $createdUserGroup->getVersionInfo()->getContentInfo();
249
        $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
250
        $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
251
252
        return new Values\CreatedUserGroup(
253
            array(
254
                'userGroup' => new Values\RestUserGroup(
255
                    $createdUserGroup,
256
                    $contentType,
257
                    $createdContentInfo,
258
                    $createdLocation,
259
                    $this->contentService->loadRelations($createdUserGroup->getVersionInfo())
260
                ),
261
            )
262
        );
263
    }
264
265
    /**
266
     * Create a new user group in the given group.
267
     *
268
     * @param $groupPath
269
     *
270
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
271
     *
272
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedUser
273
     */
274
    public function createUser($groupPath, Request $request)
275
    {
276
        $userGroupLocation = $this->locationService->loadLocation(
277
            $this->extractLocationIdFromPath($groupPath)
278
        );
279
        $userGroup = $this->userService->loadUserGroup($userGroupLocation->contentId);
280
281
        $userCreateStruct = $this->inputDispatcher->parse(
282
            new Message(
283
                array('Content-Type' => $request->headers->get('Content-Type')),
284
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
285
            )
286
        );
287
288
        try {
289
            $createdUser = $this->userService->createUser($userCreateStruct, array($userGroup));
0 ignored issues
show
Compatibility introduced by
$userCreateStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...\User\UserCreateStruct>. It seems like you assume a child class of the class eZ\Publish\API\Repository\Values\ValueObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
290
        } catch (ApiExceptions\InvalidArgumentException $e) {
291
            throw new ForbiddenException($e->getMessage());
292
        }
293
294
        $createdContentInfo = $createdUser->getVersionInfo()->getContentInfo();
295
        $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
296
        $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
297
298
        return new Values\CreatedUser(
299
            array(
300
                'user' => new Values\RestUser(
301
                    $createdUser,
302
                    $contentType,
303
                    $createdContentInfo,
304
                    $createdLocation,
305
                    $this->contentService->loadRelations($createdUser->getVersionInfo())
306
                ),
307
            )
308
        );
309
    }
310
311
    /**
312
     * Updates a user group.
313
     *
314
     * @param $groupPath
315
     *
316
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup
317
     */
318
    public function updateUserGroup($groupPath, Request $request)
319
    {
320
        $userGroupLocation = $this->locationService->loadLocation(
321
            $this->extractLocationIdFromPath($groupPath)
322
        );
323
324
        $userGroup = $this->userService->loadUserGroup(
325
            $userGroupLocation->contentId
326
        );
327
328
        $updateStruct = $this->inputDispatcher->parse(
329
            new Message(
330
                array(
331
                    'Content-Type' => $request->headers->get('Content-Type'),
332
                    // @todo Needs refactoring! Temporary solution so parser has access to URL
333
                    'Url' => $request->getPathInfo(),
334
                ),
335
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
336
            )
337
        );
338
339 View Code Duplication
        if ($updateStruct->sectionId !== null) {
0 ignored issues
show
Documentation introduced by
The property sectionId 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...
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...
340
            $section = $this->sectionService->loadSection($updateStruct->sectionId);
0 ignored issues
show
Documentation introduced by
The property sectionId 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...
341
            $this->sectionService->assignSection(
342
                $userGroup->getVersionInfo()->getContentInfo(),
343
                $section
344
            );
345
        }
346
347
        $updatedGroup = $this->userService->updateUserGroup($userGroup, $updateStruct->userGroupUpdateStruct);
0 ignored issues
show
Documentation introduced by
The property userGroupUpdateStruct 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...
348
        $contentType = $this->contentTypeService->loadContentType(
349
            $updatedGroup->getVersionInfo()->getContentInfo()->contentTypeId
350
        );
351
352
        return new Values\RestUserGroup(
353
            $updatedGroup,
354
            $contentType,
355
            $updatedGroup->getVersionInfo()->getContentInfo(),
356
            $userGroupLocation,
357
            $this->contentService->loadRelations($updatedGroup->getVersionInfo())
358
        );
359
    }
360
361
    /**
362
     * Updates a user.
363
     *
364
     * @param $userId
365
     *
366
     * @return \eZ\Publish\Core\REST\Server\Values\RestUser
367
     */
368
    public function updateUser($userId, Request $request)
369
    {
370
        $user = $this->userService->loadUser($userId);
371
372
        $updateStruct = $this->inputDispatcher->parse(
373
            new Message(
374
                array(
375
                    'Content-Type' => $request->headers->get('Content-Type'),
376
                    // @todo Needs refactoring! Temporary solution so parser has access to URL
377
                    'Url' => $request->getPathInfo(),
378
                ),
379
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
380
            )
381
        );
382
383 View Code Duplication
        if ($updateStruct->sectionId !== null) {
0 ignored issues
show
Documentation introduced by
The property sectionId 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...
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...
384
            $section = $this->sectionService->loadSection($updateStruct->sectionId);
0 ignored issues
show
Documentation introduced by
The property sectionId 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...
385
            $this->sectionService->assignSection(
386
                $user->getVersionInfo()->getContentInfo(),
387
                $section
388
            );
389
        }
390
391
        $updatedUser = $this->userService->updateUser($user, $updateStruct->userUpdateStruct);
0 ignored issues
show
Documentation introduced by
The property userUpdateStruct 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...
392
        $updatedContentInfo = $updatedUser->getVersionInfo()->getContentInfo();
393
        $mainLocation = $this->locationService->loadLocation($updatedContentInfo->mainLocationId);
394
        $contentType = $this->contentTypeService->loadContentType($updatedContentInfo->contentTypeId);
395
396
        return new Values\RestUser(
397
            $updatedUser,
398
            $contentType,
399
            $updatedContentInfo,
400
            $mainLocation,
401
            $this->contentService->loadRelations($updatedUser->getVersionInfo())
402
        );
403
    }
404
405
    /**
406
     * Given user group is deleted.
407
     *
408
     * @param $groupPath
409
     *
410
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
411
     *
412
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
413
     */
414
    public function deleteUserGroup($groupPath)
415
    {
416
        $userGroupLocation = $this->locationService->loadLocation(
417
            $this->extractLocationIdFromPath($groupPath)
418
        );
419
420
        $userGroup = $this->userService->loadUserGroup(
421
            $userGroupLocation->contentId
422
        );
423
424
        // Load one user to see if user group is empty or not
425
        $users = $this->userService->loadUsersOfUserGroup($userGroup, 0, 1);
426
        if (!empty($users)) {
427
            throw new Exceptions\ForbiddenException('Non-empty user groups cannot be deleted');
428
        }
429
430
        $this->userService->deleteUserGroup($userGroup);
431
432
        return new Values\NoContent();
433
    }
434
435
    /**
436
     * Given user is deleted.
437
     *
438
     * @param $userId
439
     *
440
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
441
     *
442
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
443
     */
444
    public function deleteUser($userId)
445
    {
446
        $user = $this->userService->loadUser($userId);
447
448
        if ($user->id == $this->repository->getCurrentUser()->id) {
449
            throw new Exceptions\ForbiddenException('Currently authenticated user cannot be deleted');
450
        }
451
452
        $this->userService->deleteUser($user);
453
454
        return new Values\NoContent();
455
    }
456
457
    /**
458
     * Loads users.
459
     *
460
     * @return \eZ\Publish\Core\REST\Server\Values\UserList|\eZ\Publish\Core\REST\Server\Values\UserRefList
461
     */
462
    public function loadUsers(Request $request)
463
    {
464
        $restUsers = array();
465
466
        try {
467
            if ($request->query->has('roleId')) {
468
                $restUsers = $this->loadUsersAssignedToRole(
469
                    $this->requestParser->parseHref($request->query->get('roleId'), 'roleId')
470
                );
471
            } elseif ($request->query->has('remoteId')) {
472
                $restUsers = array(
473
                    $this->buildRestUserObject(
474
                        $this->userService->loadUser(
475
                            $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'))->id
476
                        )
477
                    ),
478
                );
479
            } elseif ($request->query->has('login')) {
480
                $restUsers = array(
481
                    $this->buildRestUserObject(
482
                        $this->userService->loadUserByLogin($request->query->get('login'))
483
                    ),
484
                );
485
            } elseif ($request->query->has('email')) {
486
                foreach ($this->userService->loadUsersByEmail($request->query->get('email')) as $user) {
487
                    $restUsers[] = $this->buildRestUserObject($user);
488
                }
489
            }
490
        } catch (ApiExceptions\UnauthorizedException $e) {
491
            $restUsers = [];
492
        }
493
494
        if (empty($restUsers)) {
495
            throw new NotFoundException('No users were found with the given filter');
496
        }
497
498
        if ($this->getMediaType($request) === 'application/vnd.ez.api.userlist') {
499
            return new Values\UserList($restUsers, $request->getPathInfo());
500
        }
501
502
        return new Values\UserRefList($restUsers, $request->getPathInfo());
503
    }
504
505
    public function verifyUsers(Request $request)
506
    {
507
        // We let the NotFoundException loadUsers throws if there are no results pass.
508
        $this->loadUsers($request)->users;
509
510
        return new Values\OK();
511
    }
512
513
    /**
514
     * Loads a list of users assigned to role.
515
     *
516
     * @param mixed $roleId
517
     *
518
     * @return \eZ\Publish\Core\REST\Server\Values\RestUser[]
519
     */
520
    public function loadUsersAssignedToRole($roleId)
521
    {
522
        $role = $this->roleService->loadRole($roleId);
523
        $roleAssignments = $this->roleService->getRoleAssignments($role);
524
525
        $restUsers = array();
526
527
        foreach ($roleAssignments as $roleAssignment) {
528
            if ($roleAssignment instanceof UserRoleAssignment) {
529
                $restUsers[] = $this->buildRestUserObject($roleAssignment->getUser());
530
            }
531
        }
532
533
        return $restUsers;
534
    }
535
536
    /**
537
     * @return Values\RestUser
538
     */
539
    private function buildRestUserObject(RepositoryUser $user)
540
    {
541
        return new Values\RestUser(
542
            $user,
543
            $this->contentTypeService->loadContentType($user->contentInfo->contentTypeId),
544
            $user->contentInfo,
545
            $this->locationService->loadLocation($user->contentInfo->mainLocationId),
546
            $this->contentService->loadRelations($user->getVersionInfo())
547
        );
548
    }
549
550
    /**
551
     * Loads user groups.
552
     *
553
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupList|\eZ\Publish\Core\REST\Server\Values\UserGroupRefList
554
     */
555
    public function loadUserGroups(Request $request)
556
    {
557
        $restUserGroups = array();
558
        if ($request->query->has('id')) {
559
            $userGroup = $this->userService->loadUserGroup($request->query->get('id'));
560
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
561
            $userGroupMainLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
562
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
563
564
            $restUserGroups = array(
565
                new Values\RestUserGroup(
566
                    $userGroup,
567
                    $contentType,
568
                    $userGroupContentInfo,
569
                    $userGroupMainLocation,
570
                    $this->contentService->loadRelations($userGroup->getVersionInfo())
571
                ),
572
            );
573
        } elseif ($request->query->has('roleId')) {
574
            $restUserGroups = $this->loadUserGroupsAssignedToRole($request->query->get('roleId'));
575
        } elseif ($request->query->has('remoteId')) {
576
            $restUserGroups = array(
577
                $this->loadUserGroupByRemoteId($request),
578
            );
579
        }
580
581
        if ($this->getMediaType($request) === 'application/vnd.ez.api.usergrouplist') {
582
            return new Values\UserGroupList($restUserGroups, $request->getPathInfo());
583
        }
584
585
        return new Values\UserGroupRefList($restUserGroups, $request->getPathInfo());
586
    }
587
588
    /**
589
     * Loads a user group by its remote ID.
590
     *
591
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup
592
     */
593
    public function loadUserGroupByRemoteId(Request $request)
594
    {
595
        $contentInfo = $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'));
596
        $userGroup = $this->userService->loadUserGroup($contentInfo->id);
597
        $userGroupLocation = $this->locationService->loadLocation($contentInfo->mainLocationId);
598
        $contentType = $this->contentTypeService->loadContentType($contentInfo->contentTypeId);
599
600
        return new Values\RestUserGroup(
601
            $userGroup,
602
            $contentType,
603
            $contentInfo,
604
            $userGroupLocation,
605
            $this->contentService->loadRelations($userGroup->getVersionInfo())
606
        );
607
    }
608
609
    /**
610
     * Loads a list of user groups assigned to role.
611
     *
612
     * @param mixed $roleId
613
     *
614
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup[]
615
     */
616
    public function loadUserGroupsAssignedToRole($roleId)
617
    {
618
        $role = $this->roleService->loadRole($roleId);
619
        $roleAssignments = $this->roleService->getRoleAssignments($role);
620
621
        $restUserGroups = array();
622
623
        foreach ($roleAssignments as $roleAssignment) {
624
            if ($roleAssignment instanceof UserGroupRoleAssignment) {
625
                $userGroup = $roleAssignment->getUserGroup();
626
                $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
627
                $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
628
                $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
629
630
                $restUserGroups[] = new Values\RestUserGroup(
631
                    $userGroup,
632
                    $contentType,
633
                    $userGroupContentInfo,
634
                    $userGroupLocation,
635
                    $this->contentService->loadRelations($userGroup->getVersionInfo())
636
                );
637
            }
638
        }
639
640
        return $restUserGroups;
641
    }
642
643
    /**
644
     * Loads drafts assigned to user.
645
     *
646
     * @param $userId
647
     *
648
     * @return \eZ\Publish\Core\REST\Server\Values\VersionList
649
     */
650
    public function loadUserDrafts($userId, Request $request)
651
    {
652
        $contentDrafts = $this->contentService->loadContentDrafts(
653
            $this->userService->loadUser($userId)
654
        );
655
656
        return new Values\VersionList($contentDrafts, $request->getPathInfo());
657
    }
658
659
    /**
660
     * Moves the user group to another parent.
661
     *
662
     * @param $groupPath
663
     *
664
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
665
     *
666
     * @return \eZ\Publish\Core\REST\Server\Values\ResourceCreated
667
     */
668
    public function moveUserGroup($groupPath, Request $request)
669
    {
670
        $userGroupLocation = $this->locationService->loadLocation(
671
            $this->extractLocationIdFromPath($groupPath)
672
        );
673
674
        $userGroup = $this->userService->loadUserGroup(
675
            $userGroupLocation->contentId
676
        );
677
678
        $locationPath = $this->requestParser->parseHref(
679
            $request->headers->get('Destination'),
680
            'groupPath'
681
        );
682
683
        try {
684
            $destinationGroupLocation = $this->locationService->loadLocation(
685
                $this->extractLocationIdFromPath($locationPath)
686
            );
687
        } catch (ApiExceptions\NotFoundException $e) {
688
            throw new Exceptions\ForbiddenException($e->getMessage());
689
        }
690
691
        try {
692
            $destinationGroup = $this->userService->loadUserGroup($destinationGroupLocation->contentId);
693
        } catch (ApiExceptions\NotFoundException $e) {
694
            throw new Exceptions\ForbiddenException($e->getMessage());
695
        }
696
697
        $this->userService->moveUserGroup($userGroup, $destinationGroup);
698
699
        return new Values\ResourceCreated(
700
            $this->router->generate(
701
                'ezpublish_rest_loadUserGroup',
702
                array(
703
                    'groupPath' => trim($destinationGroupLocation->pathString, '/') . '/' . $userGroupLocation->id,
704
                )
705
            )
706
        );
707
    }
708
709
    /**
710
     * Returns a list of the sub groups.
711
     *
712
     * @param $groupPath
713
     *
714
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupList|\eZ\Publish\Core\REST\Server\Values\UserGroupRefList
715
     */
716 View Code Duplication
    public function loadSubUserGroups($groupPath, Request $request)
717
    {
718
        $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
719
        $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
720
721
        $userGroupLocation = $this->locationService->loadLocation(
722
            $this->extractLocationIdFromPath($groupPath)
723
        );
724
725
        $userGroup = $this->userService->loadUserGroup(
726
            $userGroupLocation->contentId
727
        );
728
729
        $subGroups = $this->userService->loadSubUserGroups(
730
            $userGroup,
731
            $offset >= 0 ? $offset : 0,
732
            $limit >= 0 ? $limit : 25
733
        );
734
735
        $restUserGroups = array();
736
        foreach ($subGroups as $subGroup) {
737
            $subGroupContentInfo = $subGroup->getVersionInfo()->getContentInfo();
738
            $subGroupLocation = $this->locationService->loadLocation($subGroupContentInfo->mainLocationId);
739
            $contentType = $this->contentTypeService->loadContentType($subGroupContentInfo->contentTypeId);
740
741
            $restUserGroups[] = new Values\RestUserGroup(
742
                $subGroup,
743
                $contentType,
744
                $subGroupContentInfo,
745
                $subGroupLocation,
746
                $this->contentService->loadRelations($subGroup->getVersionInfo())
747
            );
748
        }
749
750
        if ($this->getMediaType($request) === 'application/vnd.ez.api.usergrouplist') {
751
            return new Values\CachedValue(
752
                new Values\UserGroupList($restUserGroups, $request->getPathInfo()),
753
                array('locationId' => $userGroupLocation->id)
754
            );
755
        }
756
757
        return new Values\CachedValue(
758
            new Values\UserGroupRefList($restUserGroups, $request->getPathInfo()),
759
            array('locationId' => $userGroupLocation->id)
760
        );
761
    }
762
763
    /**
764
     * Returns a list of user groups the user belongs to.
765
     * The returned list includes the resources for unassigning
766
     * a user group if the user is in multiple groups.
767
     *
768
     * @param $userId
769
     *
770
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupRefList
771
     */
772
    public function loadUserGroupsOfUser($userId, Request $request)
773
    {
774
        $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
775
        $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
776
777
        $user = $this->userService->loadUser($userId);
778
        $userGroups = $this->userService->loadUserGroupsOfUser(
779
            $user,
780
            $offset >= 0 ? $offset : 0,
781
            $limit >= 0 ? $limit : 25
782
        );
783
784
        $restUserGroups = array();
785
        foreach ($userGroups as $userGroup) {
786
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
787
            $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
788
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
789
790
            $restUserGroups[] = new Values\RestUserGroup(
791
                $userGroup,
792
                $contentType,
793
                $userGroupContentInfo,
794
                $userGroupLocation,
795
                $this->contentService->loadRelations($userGroup->getVersionInfo())
796
            );
797
        }
798
799
        return new Values\CachedValue(
800
            new Values\UserGroupRefList($restUserGroups, $request->getPathInfo(), $userId),
801
            array('locationId' => $user->contentInfo->mainLocationId)
802
        );
803
    }
804
805
    /**
806
     * Loads the users of the group with the given path.
807
     *
808
     * @param $groupPath
809
     *
810
     * @return \eZ\Publish\Core\REST\Server\Values\UserList|\eZ\Publish\Core\REST\Server\Values\UserRefList
811
     */
812 View Code Duplication
    public function loadUsersFromGroup($groupPath, Request $request)
813
    {
814
        $userGroupLocation = $this->locationService->loadLocation(
815
            $this->extractLocationIdFromPath($groupPath)
816
        );
817
818
        $userGroup = $this->userService->loadUserGroup(
819
            $userGroupLocation->contentId
820
        );
821
822
        $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
823
        $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
824
825
        $users = $this->userService->loadUsersOfUserGroup(
826
            $userGroup,
827
            $offset >= 0 ? $offset : 0,
828
            $limit >= 0 ? $limit : 25
829
        );
830
831
        $restUsers = array();
832
        foreach ($users as $user) {
833
            $userContentInfo = $user->getVersionInfo()->getContentInfo();
834
            $userLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
835
            $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
836
837
            $restUsers[] = new Values\RestUser(
838
                $user,
839
                $contentType,
840
                $userContentInfo,
841
                $userLocation,
842
                $this->contentService->loadRelations($user->getVersionInfo())
843
            );
844
        }
845
846
        if ($this->getMediaType($request) === 'application/vnd.ez.api.userlist') {
847
            return new Values\CachedValue(
848
                new Values\UserList($restUsers, $request->getPathInfo()),
849
                array('locationId' => $userGroupLocation->id)
850
            );
851
        }
852
853
        return new Values\CachedValue(
854
            new Values\UserRefList($restUsers, $request->getPathInfo()),
855
            array('locationId' => $userGroupLocation->id)
856
        );
857
    }
858
859
    /**
860
     * Unassigns the user from a user group.
861
     *
862
     * @param $userId
863
     * @param $groupPath
864
     *
865
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
866
     *
867
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupRefList
868
     */
869
    public function unassignUserFromUserGroup($userId, $groupPath)
870
    {
871
        $user = $this->userService->loadUser($userId);
872
        $userGroupLocation = $this->locationService->loadLocation(trim($groupPath, '/'));
873
874
        $userGroup = $this->userService->loadUserGroup(
875
            $userGroupLocation->contentId
876
        );
877
878
        try {
879
            $this->userService->unAssignUserFromUserGroup($user, $userGroup);
880
        } catch (ApiExceptions\InvalidArgumentException $e) {
881
            // User is not in the group
882
            throw new Exceptions\ForbiddenException($e->getMessage());
883
        }
884
885
        $userGroups = $this->userService->loadUserGroupsOfUser($user);
886
        $restUserGroups = array();
887
        foreach ($userGroups as $userGroup) {
888
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
889
            $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
890
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
891
892
            $restUserGroups[] = new Values\RestUserGroup(
893
                $userGroup,
894
                $contentType,
895
                $userGroupContentInfo,
896
                $userGroupLocation,
897
                $this->contentService->loadRelations($userGroup->getVersionInfo())
898
            );
899
        }
900
901
        return new Values\UserGroupRefList(
902
            $restUserGroups,
903
            $this->router->generate(
904
                'ezpublish_rest_loadUserGroupsOfUser',
905
                array('userId' => $userId)
906
            ),
907
            $userId
908
        );
909
    }
910
911
    /**
912
     * Assigns the user to a user group.
913
     *
914
     * @param $userId
915
     *
916
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
917
     *
918
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupRefList
919
     */
920
    public function assignUserToUserGroup($userId, Request $request)
921
    {
922
        $user = $this->userService->loadUser($userId);
923
924
        try {
925
            $userGroupLocation = $this->locationService->loadLocation(
926
                $this->extractLocationIdFromPath($request->query->get('group'))
927
            );
928
        } catch (ApiExceptions\NotFoundException $e) {
929
            throw new Exceptions\ForbiddenException($e->getMessage());
930
        }
931
932
        try {
933
            $userGroup = $this->userService->loadUserGroup(
934
                $userGroupLocation->contentId
935
            );
936
        } catch (ApiExceptions\NotFoundException $e) {
937
            throw new Exceptions\ForbiddenException($e->getMessage());
938
        }
939
940
        try {
941
            $this->userService->assignUserToUserGroup($user, $userGroup);
942
        } catch (ApiExceptions\NotFoundException $e) {
943
            throw new Exceptions\ForbiddenException($e->getMessage());
944
        }
945
946
        $userGroups = $this->userService->loadUserGroupsOfUser($user);
947
        $restUserGroups = array();
948
        foreach ($userGroups as $userGroup) {
949
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
950
            $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
951
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
952
953
            $restUserGroups[] = new Values\RestUserGroup(
954
                $userGroup,
955
                $contentType,
956
                $userGroupContentInfo,
957
                $userGroupLocation,
958
                $this->contentService->loadRelations($userGroup->getVersionInfo())
959
            );
960
        }
961
962
        return new Values\UserGroupRefList(
963
            $restUserGroups,
964
            $this->router->generate(
965
                'ezpublish_rest_loadUserGroupsOfUser',
966
                array('userId' => $userId)
967
            ),
968
            $userId
969
        );
970
    }
971
972
    /**
973
     * Creates a new session based on the credentials provided as POST parameters.
974
     *
975
     * @throws \eZ\Publish\Core\Base\Exceptions\UnauthorizedException If the login or password are incorrect or invalid CSRF
976
     *
977
     * @return Values\UserSession|Values\Conflict
978
     */
979
    public function createSession(Request $request)
980
    {
981
        /** @var $sessionInput \eZ\Publish\Core\REST\Server\Values\SessionInput */
982
        $sessionInput = $this->inputDispatcher->parse(
983
            new Message(
984
                array('Content-Type' => $request->headers->get('Content-Type')),
985
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
986
            )
987
        );
988
        $request->attributes->set('username', $sessionInput->login);
989
        $request->attributes->set('password', $sessionInput->password);
990
991
        try {
992
            $csrfToken = '';
993
            $csrfTokenManager = $this->container->get('security.csrf.token_manager', ContainerInterface::NULL_ON_INVALID_REFERENCE);
994
            $session = $request->getSession();
995
            if ($session->isStarted()) {
996
                if ($csrfTokenManager) {
997
                    $csrfToken = $request->headers->get('X-CSRF-Token');
998
                    if (
999
                        !$csrfTokenManager->isTokenValid(
1000
                            new CsrfToken(
1001
                                $this->container->getParameter('ezpublish_rest.csrf_token_intention'),
1002
                                $csrfToken
0 ignored issues
show
Bug introduced by
It seems like $csrfToken defined by $request->headers->get('X-CSRF-Token') on line 997 can also be of type array; however, Symfony\Component\Securi...srfToken::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1003
                            )
1004
                        )
1005
                    ) {
1006
                        throw new UnauthorizedException('Missing or invalid CSRF token', $csrfToken);
0 ignored issues
show
Bug introduced by
It seems like $csrfToken defined by $request->headers->get('X-CSRF-Token') on line 997 can also be of type array; however, eZ\Publish\Core\Base\Exc...xception::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1007
                    }
1008
                }
1009
            }
1010
1011
            $authenticator = $this->container->get('ezpublish_rest.session_authenticator');
1012
            $token = $authenticator->authenticate($request);
1013
            // If CSRF token has not been generated yet (i.e. session not started), we generate it now.
1014
            // This will seamlessly start the session.
1015
            if ($csrfTokenManager && !$csrfToken) {
1016
                $csrfToken = $csrfTokenManager->getToken(
1017
                    $this->container->getParameter('ezpublish_rest.csrf_token_intention')
1018
                )->getValue();
1019
            }
1020
1021
            return new Values\UserSession(
1022
                $token->getUser()->getAPIUser(),
1023
                $session->getName(),
1024
                $session->getId(),
1025
                $csrfToken,
1026
                !$token->hasAttribute('isFromSession')
1027
            );
1028
        } catch (Exceptions\UserConflictException $e) {
1029
            // Already logged in with another user, this will be converted to HTTP status 409
1030
            return new Values\Conflict();
1031
        } catch (AuthenticationException $e) {
1032
            throw new UnauthorizedException('Invalid login or password', $request->getPathInfo());
1033
        } catch (AccessDeniedException $e) {
1034
            throw new UnauthorizedException($e->getMessage(), $request->getPathInfo());
1035
        }
1036
    }
1037
1038
    /**
1039
     * Refresh given session.
1040
     *
1041
     * @param string $sessionId
1042
     *
1043
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
1044
     *
1045
     * @return \eZ\Publish\Core\REST\Server\Values\UserSession
1046
     */
1047
    public function refreshSession($sessionId, Request $request)
1048
    {
1049
        try {
1050
            $session = $request->getSession();
1051
            if ($session === null || !$session->isStarted() || $session->getId() != $sessionId) {
1052
                throw new SessionUnavailableException();
1053
            }
1054
1055
            if (!$this->hasStoredCsrfToken($request)) {
1056
                throw new SessionUnavailableException();
1057
            }
1058
1059
            return new Values\UserSession(
1060
                $this->repository->getCurrentUser(),
1061
                $session->getName(),
1062
                $session->getId(),
1063
                $request->headers->get('X-CSRF-Token'),
1064
                false
1065
            );
1066
        } catch (SessionUnavailableException $e) {
1067
            $response = $this->container->get('ezpublish_rest.session_authenticator')->logout($request);
1068
            $response->setStatusCode(404);
1069
1070
            return $response;
1071
        }
1072
    }
1073
1074
    /**
1075
     * Deletes given session.
1076
     *
1077
     * @param string $sessionId
1078
     *
1079
     * @return Values\DeletedUserSession
1080
     *
1081
     * @throws RestNotFoundException
1082
     */
1083
    public function deleteSession($sessionId, Request $request)
1084
    {
1085
        /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
1086
        $session = $this->container->get('session');
1087
        if (!$session->isStarted() || $session->getId() != $sessionId) {
1088
            throw new RestNotFoundException("Session not found: '{$sessionId}'.");
1089
        }
1090
1091
        return new Values\DeletedUserSession(
1092
            $this->container->get('ezpublish_rest.session_authenticator')->logout($request)
1093
        );
1094
    }
1095
1096
    /**
1097
     * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
1098
     *
1099
     * @param string $path
1100
     *
1101
     * @return mixed
1102
     */
1103
    private function extractLocationIdFromPath($path)
1104
    {
1105
        $pathParts = explode('/', $path);
1106
1107
        return array_pop($pathParts);
1108
    }
1109
1110
    /**
1111
     * Uses the csrfTokenManager if it was set. Falls back to the token manager if we don't.
1112
     *
1113
     * @param Request $request
1114
     *
1115
     * @return bool
1116
     */
1117
    private function hasStoredCsrfToken(Request $request)
1118
    {
1119
        $csrfIntention = $this->container->getParameter('ezpublish_rest.csrf_token_intention');
1120
1121
        if (isset($this->csrfTokenStorage)) {
1122
            return $this->csrfTokenStorage->hasToken($csrfIntention);
1123
        } else {
1124
            $csrfTokenManager = $this->container->get('security.csrf.token_manager');
1125
1126
            return $csrfTokenManager->isTokenValid(
1127
                new CsrfToken($csrfIntention, $request->headers->get('X-CSRF-Token'))
1128
            );
1129
        }
1130
1131
    }
1132
1133
    public function setTokenStorage(TokenStorageInterface $csrfTokenStorage)
1134
    {
1135
        $this->csrfTokenStorage = $csrfTokenStorage;
1136
    }
1137
}
1138