Completed
Push — ezp-24830_REST_for_role_drafts ( 6879a7...588d71 )
by
unknown
113:35 queued 67:39
created

Role::createRoleDraft()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 18
rs 8.8571
cc 5
eloc 13
nc 5
nop 2
1
<?php
2
3
/**
4
 * File containing the Role 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\API\Repository\Exceptions\LimitationValidationException;
14
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
15
use eZ\Publish\Core\Base\Exceptions\ForbiddenException;
16
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
17
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
18
use eZ\Publish\Core\REST\Common\Message;
19
use eZ\Publish\Core\REST\Common\Exceptions;
20
use eZ\Publish\Core\REST\Server\Exceptions\BadRequestException;
21
use eZ\Publish\Core\REST\Server\Values;
22
use eZ\Publish\Core\REST\Server\Controller as RestController;
23
use eZ\Publish\API\Repository\RoleService;
24
use eZ\Publish\API\Repository\UserService;
25
use eZ\Publish\API\Repository\LocationService;
26
use eZ\Publish\API\Repository\Values\User\RoleCreateStruct;
27
use eZ\Publish\API\Repository\Values\User\RoleUpdateStruct;
28
use eZ\Publish\API\Repository\Exceptions\NotFoundException as APINotFoundException;
29
use Symfony\Component\HttpFoundation\Request;
30
31
/**
32
 * Role controller.
33
 */
34
class Role extends RestController
35
{
36
    /**
37
     * Role service.
38
     *
39
     * @var \eZ\Publish\API\Repository\RoleService
40
     */
41
    protected $roleService;
42
43
    /**
44
     * User service.
45
     *
46
     * @var \eZ\Publish\API\Repository\UserService
47
     */
48
    protected $userService;
49
50
    /**
51
     * Location service.
52
     *
53
     * @var \eZ\Publish\API\Repository\LocationService
54
     */
55
    protected $locationService;
56
57
    /**
58
     * Construct controller.
59
     *
60
     * @param \eZ\Publish\API\Repository\RoleService $roleService
61
     * @param \eZ\Publish\API\Repository\UserService $userService
62
     * @param \eZ\Publish\API\Repository\LocationService $locationService
63
     */
64
    public function __construct(
65
        RoleService $roleService,
66
        UserService $userService,
67
        LocationService $locationService
68
    ) {
69
        $this->roleService = $roleService;
70
        $this->userService = $userService;
71
        $this->locationService = $locationService;
72
    }
73
74
    /**
75
     * Create new role.
76
     *
77
     * Defaults to publishing the role, but you can create a draft instead by setting the POST parameter publish=false
78
     *
79
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedRole
80
     */
81
    public function createRole(Request $request)
82
    {
83
        $publish = (
84
            !$request->query->has('publish') ||
85
            ($request->query->has('publish') && $request->query->get('publish') === 'true')
86
        );
87
88
        try {
89
            $roleDraft = $this->roleService->createRole(
90
                $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...\User\RoleCreateStruct>. 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...
91
                    new Message(
92
                        [
93
                            'Content-Type' => $request->headers->get('Content-Type'),
94
                            // @todo Needs refactoring! Temporary solution so parser has access to get parameters
95
                            '__publish' => $publish,
96
                        ],
97
                        $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...
98
                    )
99
                )
100
            );
101
        } catch (InvalidArgumentException $e) {
102
            throw new ForbiddenException($e->getMessage());
103
        } catch (UnauthorizedException $e) {
104
            throw new ForbiddenException($e->getMessage());
105
        } catch (LimitationValidationException $e) {
106
            throw new BadRequestException($e->getMessage());
107
        } catch (Exceptions\Parser $e) {
108
            throw new BadRequestException($e->getMessage());
109
        }
110
111
        if ($publish) {
112
            @trigger_error(
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...
113
                "Create and publish role in the same operation is deprecated, and will be removed in the future.\n" .
114
                'Instead, publish the role draft using Role::publishRoleDraft().',
115
                E_USER_DEPRECATED
116
            );
117
118
            $this->roleService->publishRoleDraft($roleDraft);
119
120
            $role = $this->roleService->loadRole($roleDraft->id);
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\User\Role. 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...
121
122
            return new Values\CreatedRole(['role' => new Values\RestRole($role)]);
123
        }
124
125
        return new Values\CreatedRole(['role' => new Values\RestRole($roleDraft)]);
126
    }
127
128
    /**
129
     * Creates a new RoleDraft for an existing Role.
130
     *
131
     * @since 6.2
132
     *
133
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException if the Role already has a Role Draft that will need to be removed first,
134
     *                                                                  or if the authenticated user is not allowed to create a role
135
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\BadRequestException if a policy limitation in the $roleCreateStruct is not valid
136
     *
137
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedRole
138
     */
139
    public function createRoleDraft($roleId, Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
140
    {
141
        try {
142
            $roleDraft = $this->roleService->createRoleDraft(
143
                $this->roleService->loadRole($roleId)
144
            );
145
        } catch (InvalidArgumentException $e) {
146
            throw new ForbiddenException($e->getMessage());
147
        } catch (UnauthorizedException $e) {
148
            throw new ForbiddenException($e->getMessage());
149
        } catch (LimitationValidationException $e) {
150
            throw new BadRequestException($e->getMessage());
151
        } catch (Exceptions\Parser $e) {
152
            throw new BadRequestException($e->getMessage());
153
        }
154
155
        return new Values\CreatedRole(['role' => new Values\RestRole($roleDraft)]);
156
    }
157
158
    /**
159
     * Loads list of roles.
160
     *
161
     * @return \eZ\Publish\Core\REST\Server\Values\RoleList
162
     */
163
    public function listRoles(Request $request)
164
    {
165
        $roles = array();
166
        if ($request->query->has('identifier')) {
167
            try {
168
                $role = $this->roleService->loadRoleByIdentifier($request->query->get('identifier'));
169
                $roles[] = $role;
170
            } catch (APINotFoundException $e) {
171
                // Do nothing
172
            }
173
        } else {
174
            $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
175
            $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : -1;
176
177
            $roles = array_slice(
178
                $this->roleService->loadRoles(),
179
                $offset >= 0 ? $offset : 0,
180
                $limit >= 0 ? $limit : null
181
            );
182
        }
183
184
        return new Values\RoleList($roles, $request->getPathInfo());
185
    }
186
187
    /**
188
     * Loads role.
189
     *
190
     * @param $roleId
191
     *
192
     * @return \eZ\Publish\API\Repository\Values\User\Role
193
     */
194
    public function loadRole($roleId)
195
    {
196
        return $this->roleService->loadRole($roleId);
197
    }
198
199
    /**
200
     * Loads a role draft.
201
     *
202
     * @param mixed $roleId Original role ID, or ID of the role draft itself
203
     *
204
     * @return \eZ\Publish\API\Repository\Values\User\RoleDraft
205
     */
206
    public function loadRoleDraft($roleId)
207
    {
208
        try {
209
            // First try to load the draft for given role.
210
            return $this->roleService->loadRoleDraftByRoleId($roleId);
211
        } catch (NotFoundException $e) {
212
            // We might want a newly created role, so try to load it by its ID.
213
            // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
214
            return $this->roleService->loadRoleDraft($roleId);
215
        }
216
    }
217
218
    /**
219
     * Updates a role.
220
     *
221
     * @param $roleId
222
     *
223
     * @return \eZ\Publish\API\Repository\Values\User\Role
224
     */
225
    public function updateRole($roleId, Request $request)
226
    {
227
        $createStruct = $this->inputDispatcher->parse(
228
            new Message(
229
                array('Content-Type' => $request->headers->get('Content-Type')),
230
                $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...
231
            )
232
        );
233
234
        return $this->roleService->updateRole(
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...leService::updateRole() has been deprecated with message: since 6.0, use {@see updateRoleDraft}

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...
235
            $this->roleService->loadRole($roleId),
236
            $this->mapToUpdateStruct($createStruct)
0 ignored issues
show
Compatibility introduced by
$createStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...\User\RoleCreateStruct>. 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...
237
        );
238
    }
239
240
    /**
241
     * Updates a role draft.
242
     *
243
     * @param mixed $roleId Original role ID, or ID of the role draft itself
244
     *
245
     * @return \eZ\Publish\API\Repository\Values\User\RoleDraft
246
     */
247
    public function updateRoleDraft($roleId, Request $request)
248
    {
249
        $createStruct = $this->inputDispatcher->parse(
250
            new Message(
251
                array('Content-Type' => $request->headers->get('Content-Type')),
252
                $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...
253
            )
254
        );
255
256
        try {
257
            // First try to load the draft for given role.
258
            $roleDraft = $this->roleService->loadRoleDraftByRoleId($roleId);
259
        } catch (NotFoundException $e) {
260
            // We might want a newly created role, so try to load it by its ID.
261
            // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
262
            $roleDraft = $this->roleService->loadRoleDraft($roleId);
263
        }
264
265
        return $this->roleService->updateRoleDraft($roleDraft, $this->mapToUpdateStruct($createStruct));
0 ignored issues
show
Compatibility introduced by
$createStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...\User\RoleCreateStruct>. 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...
266
    }
267
268
    /**
269
     * Publishes a role draft.
270
     *
271
     * @param mixed $roleId Original role ID, or ID of the role draft itself
272
     * @return Values\RestRole
273
     */
274
    public function publishRoleDraft($roleId)
275
    {
276
        try {
277
            // First try to load the draft for given role.
278
            $roleDraft = $this->roleService->loadRoleDraftByRoleId($roleId);
279
        } catch (NotFoundException $e) {
280
            // We might want a newly created role, so try to load it by its ID.
281
            // loadRoleDraft() might throw a NotFoundException (wrong $roleId). If so, let it bubble up.
282
            $roleDraft = $this->roleService->loadRoleDraft($roleId);
283
        }
284
285
        $this->roleService->publishRoleDraft($roleDraft);
286
        $publishedRole = $this->roleService->loadRole($roleDraft->id);
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\User\Role. 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...
287
288
        return new Values\CreatedRole(['role' => new Values\RestRole($publishedRole)]);
289
    }
290
291
    /**
292
     * Delete a role by ID.
293
     *
294
     * @param $roleId
295
     *
296
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
297
     */
298
    public function deleteRole($roleId)
299
    {
300
        $this->roleService->deleteRole(
301
            $this->roleService->loadRole($roleId)
302
        );
303
304
        return new Values\NoContent();
305
    }
306
307
    /**
308
     * Delete a role draft by ID.
309
     *
310
     * @since 6.2
311
     *
312
     * @param $roleId
313
     *
314
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
315
     */
316
    public function deleteRoleDraft($roleId)
317
    {
318
        $this->roleService->deleteRoleDraft(
319
            $this->roleService->loadRoleDraft($roleId)
320
        );
321
322
        return new Values\NoContent();
323
    }
324
325
    /**
326
     * Loads the policies for the role.
327
     *
328
     * @param $roleId
329
     *
330
     * @return \eZ\Publish\Core\REST\Server\Values\PolicyList
331
     */
332
    public function loadPolicies($roleId, Request $request)
333
    {
334
        $loadedRole = $this->roleService->loadRole($roleId);
335
336
        return new Values\PolicyList($loadedRole->getPolicies(), $request->getPathInfo());
337
    }
338
339
    /**
340
     * Deletes all policies from a role.
341
     *
342
     * @param $roleId
343
     *
344
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
345
     */
346
    public function deletePolicies($roleId)
347
    {
348
        $loadedRole = $this->roleService->loadRole($roleId);
349
350
        foreach ($loadedRole->getPolicies() as $policy) {
351
            $this->roleService->deletePolicy($policy);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...Service::deletePolicy() has been deprecated with message: since 6.0, use {@link removePolicyByRoleDraft()} instead.

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...
352
        }
353
354
        return new Values\NoContent();
355
    }
356
357
    /**
358
     * Loads a policy.
359
     *
360
     * @param $roleId
361
     * @param $policyId
362
     *
363
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
364
     *
365
     * @return \eZ\Publish\API\Repository\Values\User\Policy
366
     */
367
    public function loadPolicy($roleId, $policyId, Request $request)
368
    {
369
        $loadedRole = $this->roleService->loadRole($roleId);
370
        foreach ($loadedRole->getPolicies() as $policy) {
371
            if ($policy->id == $policyId) {
372
                return $policy;
373
            }
374
        }
375
376
        throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
377
    }
378
379
    /**
380
     * Adds a policy to role.
381
     *
382
     * @param $roleId
383
     *
384
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedPolicy
385
     */
386 View Code Duplication
    public function addPolicy($roleId, Request $request)
387
    {
388
        $createStruct = $this->inputDispatcher->parse(
389
            new Message(
390
                array('Content-Type' => $request->headers->get('Content-Type')),
391
                $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...
392
            )
393
        );
394
395
        try {
396
            $role = $this->roleService->addPolicy(
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\RoleService::addPolicy() has been deprecated with message: since 6.0, use {@see addPolicyByRoleDraft}

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...
397
                $this->roleService->loadRole($roleId),
398
                $createStruct
0 ignored issues
show
Compatibility introduced by
$createStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...ser\PolicyCreateStruct>. 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...
399
            );
400
        } catch (LimitationValidationException $e) {
401
            throw new BadRequestException($e->getMessage());
402
        }
403
404
        return new Values\CreatedPolicy(
405
            array(
406
                'policy' => $this->getLastAddedPolicy($role),
407
            )
408
        );
409
    }
410
411
    /**
412
     * Adds a policy to a role draft.
413
     *
414
     * @since 6.2
415
     *
416
     * @param $roleId
417
     *
418
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedPolicy
419
     */
420 View Code Duplication
    public function addPolicyByRoleDraft($roleId, Request $request)
421
    {
422
        $createStruct = $this->inputDispatcher->parse(
423
            new Message(
424
                array('Content-Type' => $request->headers->get('Content-Type')),
425
                $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...
426
            )
427
        );
428
429
        try {
430
            $role = $this->roleService->addPolicyByRoleDraft(
431
                $this->roleService->loadRoleDraft($roleId),
432
                $createStruct
0 ignored issues
show
Compatibility introduced by
$createStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...ser\PolicyCreateStruct>. 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...
433
            );
434
        } catch (LimitationValidationException $e) {
435
            throw new BadRequestException($e->getMessage());
436
        }
437
438
        return new Values\CreatedPolicy(
439
            array(
440
                'policy' => $this->getLastAddedPolicy($role),
441
            )
442
        );
443
    }
444
445
    /**
446
     * Get the last added policy for $role.
447
     *
448
     * This is needed because the RoleService addPolicy() and addPolicyByRoleDraft() methods return the role,
449
     * not the policy.
450
     *
451
     * @param $role \eZ\Publish\API\Repository\Values\User\Role
452
     *
453
     * @return \eZ\Publish\API\Repository\Values\User\Policy
454
     */
455
    private function getLastAddedPolicy($role)
456
    {
457
        $policies = $role->getPolicies();
458
459
        $policyToReturn = $policies[0];
460
        for ($i = 1, $count = count($policies); $i < $count; ++$i) {
461
            if ($policies[$i]->id > $policyToReturn->id) {
462
                $policyToReturn = $policies[$i];
463
            }
464
        }
465
466
        return $policyToReturn;
467
    }
468
469
    /**
470
     * Updates a policy.
471
     *
472
     * @param $roleId
473
     * @param $policyId
474
     *
475
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
476
     *
477
     * @return \eZ\Publish\API\Repository\Values\User\Policy
478
     */
479 View Code Duplication
    public function updatePolicy($roleId, $policyId, Request $request)
480
    {
481
        $updateStruct = $this->inputDispatcher->parse(
482
            new Message(
483
                array('Content-Type' => $request->headers->get('Content-Type')),
484
                $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...
485
            )
486
        );
487
488
        $role = $this->roleService->loadRole($roleId);
489
        foreach ($role->getPolicies() as $policy) {
490
            if ($policy->id == $policyId) {
491
                try {
492
                    return $this->roleService->updatePolicy(
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...Service::updatePolicy() has been deprecated with message: since 6.0, use {@link updatePolicyByRoleDraft()} instead.

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...
493
                        $policy,
494
                        $updateStruct
0 ignored issues
show
Compatibility introduced by
$updateStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...ser\PolicyUpdateStruct>. 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...
495
                    );
496
                } catch (LimitationValidationException $e) {
497
                    throw new BadRequestException($e->getMessage());
498
                }
499
            }
500
        }
501
502
        throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
503
    }
504
505
    /**
506
     * Updates a policy.
507
     *
508
     * @since 6.2
509
     *
510
     * @param $roleId
511
     * @param $policyId
512
     *
513
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
514
     *
515
     * @return \eZ\Publish\API\Repository\Values\User\Policy
516
     */
517 View Code Duplication
    public function updatePolicyByRoleDraft($roleId, $policyId, Request $request)
518
    {
519
        $updateStruct = $this->inputDispatcher->parse(
520
            new Message(
521
                array('Content-Type' => $request->headers->get('Content-Type')),
522
                $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...
523
            )
524
        );
525
526
        $role = $this->roleService->loadRoleDraft($roleId);
527
        foreach ($role->getPolicies() as $policy) {
528
            if ($policy->id == $policyId) {
529
                try {
530
                    return $this->roleService->updatePolicy(
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...Service::updatePolicy() has been deprecated with message: since 6.0, use {@link updatePolicyByRoleDraft()} instead.

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...
531
                        $policy,
532
                        $updateStruct
0 ignored issues
show
Compatibility introduced by
$updateStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...ser\PolicyUpdateStruct>. 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...
533
                    );
534
                } catch (LimitationValidationException $e) {
535
                    throw new BadRequestException($e->getMessage());
536
                }
537
            }
538
        }
539
540
        throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
541
    }
542
543
    /**
544
     * Delete a policy from role.
545
     *
546
     * @param $roleId
547
     * @param $policyId
548
     *
549
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
550
     *
551
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
552
     */
553 View Code Duplication
    public function deletePolicy($roleId, $policyId, Request $request)
554
    {
555
        $role = $this->roleService->loadRole($roleId);
556
557
        $policy = null;
558
        foreach ($role->getPolicies() as $rolePolicy) {
559
            if ($rolePolicy->id == $policyId) {
560
                $policy = $rolePolicy;
561
                break;
562
            }
563
        }
564
565
        if ($policy !== null) {
566
            $this->roleService->deletePolicy($policy);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...Service::deletePolicy() has been deprecated with message: since 6.0, use {@link removePolicyByRoleDraft()} instead.

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...
567
568
            return new Values\NoContent();
569
        }
570
571
        throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
572
    }
573
574
    /**
575
     * Remove a policy from a role draft.
576
     *
577
     * @since 6.2
578
     *
579
     * @param $roleId
580
     * @param $policyId
581
     *
582
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
583
     *
584
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
585
     */
586 View Code Duplication
    public function removePolicyByRoleDraft($roleId, $policyId, Request $request)
587
    {
588
        $roleDraft = $this->roleService->loadRoleDraft($roleId);
589
590
        $policy = null;
591
        foreach ($roleDraft->getPolicies() as $rolePolicy) {
592
            if ($rolePolicy->id == $policyId) {
593
                $policy = $rolePolicy;
594
                break;
595
            }
596
        }
597
598
        if ($policy !== null) {
599
            $this->roleService->removePolicyByRoleDraft($roleDraft, $policy);
0 ignored issues
show
Compatibility introduced by
$policy of type object<eZ\Publish\API\Re...ory\Values\User\Policy> is not a sub-type of object<eZ\Publish\API\Re...alues\User\PolicyDraft>. It seems like you assume a child class of the class eZ\Publish\API\Repository\Values\User\Policy 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...
600
601
            return new Values\NoContent();
602
        }
603
604
        throw new Exceptions\NotFoundException("Policy not found: '{$request->getPathInfo()}'.");
605
    }
606
607
    /**
608
     * Assigns role to user.
609
     *
610
     * @param $userId
611
     *
612
     * @return \eZ\Publish\Core\REST\Server\Values\RoleAssignmentList
613
     */
614
    public function assignRoleToUser($userId, Request $request)
615
    {
616
        $roleAssignment = $this->inputDispatcher->parse(
617
            new Message(
618
                array('Content-Type' => $request->headers->get('Content-Type')),
619
                $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...
620
            )
621
        );
622
623
        $user = $this->userService->loadUser($userId);
624
        $role = $this->roleService->loadRole($roleAssignment->roleId);
0 ignored issues
show
Documentation introduced by
The property roleId 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...
625
626
        try {
627
            $this->roleService->assignRoleToUser($role, $user, $roleAssignment->limitation);
0 ignored issues
show
Documentation introduced by
The property limitation 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...
628
        } catch (LimitationValidationException $e) {
629
            throw new BadRequestException($e->getMessage());
630
        }
631
632
        $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
633
634
        return new Values\RoleAssignmentList($roleAssignments, $user->id);
635
    }
636
637
    /**
638
     * Assigns role to user group.
639
     *
640
     * @param $groupPath
641
     *
642
     * @return \eZ\Publish\Core\REST\Server\Values\RoleAssignmentList
643
     */
644
    public function assignRoleToUserGroup($groupPath, Request $request)
645
    {
646
        $roleAssignment = $this->inputDispatcher->parse(
647
            new Message(
648
                array('Content-Type' => $request->headers->get('Content-Type')),
649
                $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...
650
            )
651
        );
652
653
        $groupLocationParts = explode('/', $groupPath);
654
        $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
655
        $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
656
657
        $role = $this->roleService->loadRole($roleAssignment->roleId);
0 ignored issues
show
Documentation introduced by
The property roleId 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...
658
659
        try {
660
            $this->roleService->assignRoleToUserGroup($role, $userGroup, $roleAssignment->limitation);
0 ignored issues
show
Documentation introduced by
The property limitation 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...
661
        } catch (LimitationValidationException $e) {
662
            throw new BadRequestException($e->getMessage());
663
        }
664
665
        $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
666
667
        return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
668
    }
669
670
    /**
671
     * Un-assigns role from user.
672
     *
673
     * @param $userId
674
     * @param $roleId
675
     *
676
     * @return \eZ\Publish\Core\REST\Server\Values\RoleAssignmentList
677
     */
678
    public function unassignRoleFromUser($userId, $roleId)
679
    {
680
        $user = $this->userService->loadUser($userId);
681
        $role = $this->roleService->loadRole($roleId);
682
683
        $this->roleService->unassignRoleFromUser($role, $user);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...:unassignRoleFromUser() has been deprecated with message: since 6.0, use {@see removeRoleAssignment} instead.

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...
684
685
        $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
686
687
        return new Values\RoleAssignmentList($roleAssignments, $user->id);
688
    }
689
690
    /**
691
     * Un-assigns role from user group.
692
     *
693
     * @param $groupPath
694
     * @param $roleId
695
     *
696
     * @return \eZ\Publish\Core\REST\Server\Values\RoleAssignmentList
697
     */
698
    public function unassignRoleFromUserGroup($groupPath, $roleId)
699
    {
700
        $groupLocationParts = explode('/', $groupPath);
701
        $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
702
        $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
703
704
        $role = $this->roleService->loadRole($roleId);
705
        $this->roleService->unassignRoleFromUserGroup($role, $userGroup);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...signRoleFromUserGroup() has been deprecated with message: since 6.0, use {@see removeRoleAssignment} instead.

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...
706
707
        $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
708
709
        return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
710
    }
711
712
    /**
713
     * Loads role assignments for user.
714
     *
715
     * @param $userId
716
     *
717
     * @return \eZ\Publish\Core\REST\Server\Values\RoleAssignmentList
718
     */
719
    public function loadRoleAssignmentsForUser($userId)
720
    {
721
        $user = $this->userService->loadUser($userId);
722
723
        $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
724
725
        return new Values\RoleAssignmentList($roleAssignments, $user->id);
726
    }
727
728
    /**
729
     * Loads role assignments for user group.
730
     *
731
     * @param $groupPath
732
     *
733
     * @return \eZ\Publish\Core\REST\Server\Values\RoleAssignmentList
734
     */
735
    public function loadRoleAssignmentsForUserGroup($groupPath)
736
    {
737
        $groupLocationParts = explode('/', $groupPath);
738
        $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
739
        $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
740
741
        $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
742
743
        return new Values\RoleAssignmentList($roleAssignments, $groupPath, true);
744
    }
745
746
    /**
747
     * Returns a role assignment to the given user.
748
     *
749
     * @param $userId
750
     * @param $roleId
751
     *
752
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
753
     *
754
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserRoleAssignment
755
     */
756
    public function loadRoleAssignmentForUser($userId, $roleId, Request $request)
757
    {
758
        $user = $this->userService->loadUser($userId);
759
        $roleAssignments = $this->roleService->getRoleAssignmentsForUser($user);
760
761
        foreach ($roleAssignments as $roleAssignment) {
762
            if ($roleAssignment->getRole()->id == $roleId) {
763
                return new Values\RestUserRoleAssignment($roleAssignment, $userId);
0 ignored issues
show
Bug introduced by
It seems like $roleAssignment defined by $roleAssignment on line 761 can also be of type object<eZ\Publish\API\Re...serGroupRoleAssignment>; however, eZ\Publish\Core\REST\Ser...signment::__construct() does only seem to accept object<eZ\Publish\API\Re...ser\UserRoleAssignment>, 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...
764
            }
765
        }
766
767
        throw new Exceptions\NotFoundException("Role assignment not found: '{$request->getPathInfo()}'.");
768
    }
769
770
    /**
771
     * Returns a role assignment to the given user group.
772
     *
773
     * @param $groupPath
774
     * @param $roleId
775
     *
776
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
777
     *
778
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroupRoleAssignment
779
     */
780
    public function loadRoleAssignmentForUserGroup($groupPath, $roleId, Request $request)
781
    {
782
        $groupLocationParts = explode('/', $groupPath);
783
        $groupLocation = $this->locationService->loadLocation(array_pop($groupLocationParts));
784
        $userGroup = $this->userService->loadUserGroup($groupLocation->contentId);
785
786
        $roleAssignments = $this->roleService->getRoleAssignmentsForUserGroup($userGroup);
787
        foreach ($roleAssignments as $roleAssignment) {
788
            if ($roleAssignment->getRole()->id == $roleId) {
789
                return new Values\RestUserGroupRoleAssignment($roleAssignment, $groupPath);
790
            }
791
        }
792
793
        throw new Exceptions\NotFoundException("Role assignment not found: '{$request->getPathInfo()}'.");
794
    }
795
796
    /**
797
     * Search all policies which are applied to a given user.
798
     *
799
     * @return \eZ\Publish\Core\REST\Server\Values\PolicyList
800
     */
801
    public function listPoliciesForUser(Request $request)
802
    {
803
        return new Values\PolicyList(
804
            $this->roleService->loadPoliciesByUserId(
805
                $request->query->get('userId')
806
            ),
807
            $request->getPathInfo()
808
        );
809
    }
810
811
    /**
812
     * Maps a RoleCreateStruct to a RoleUpdateStruct.
813
     *
814
     * Needed since both structs are encoded into the same media type on input.
815
     *
816
     * @param \eZ\Publish\API\Repository\Values\User\RoleCreateStruct $createStruct
817
     *
818
     * @return \eZ\Publish\API\Repository\Values\User\RoleUpdateStruct
819
     */
820
    protected function mapToUpdateStruct(RoleCreateStruct $createStruct)
821
    {
822
        return new RoleUpdateStruct(
823
            array(
824
                'identifier' => $createStruct->identifier,
825
            )
826
        );
827
    }
828
}
829