Completed
Push — master ( a6f9cf...437d73 )
by André
38:59 queued 26:12
created

BaseTest::createRoleWithPolicies()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 3
nop 2
dl 0
loc 27
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the BaseTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use EzSystems\EzPlatformSolrSearchEngine\Tests\SetupFactory\LegacySetupFactory as LegacySolrSetupFactory;
12
use PHPUnit\Framework\TestCase;
13
use eZ\Publish\API\Repository\Repository;
14
use eZ\Publish\API\Repository\Values\ValueObject;
15
use eZ\Publish\API\Repository\Values\User\Limitation\RoleLimitation;
16
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
17
use eZ\Publish\API\Repository\Values\User\UserGroup;
18
use eZ\Publish\Core\REST\Client\Sessionable;
19
use DateTime;
20
use ArrayObject;
21
use Exception;
22
use PDOException;
23
24
/**
25
 * Base class for api specific tests.
26
 */
27
abstract class BaseTest extends TestCase
28
{
29
    /**
30
     * Maximum integer number accepted by the different backends.
31
     */
32
    const DB_INT_MAX = 2147483647;
33
34
    /**
35
     * @var \eZ\Publish\API\Repository\Tests\SetupFactory
36
     */
37
    private $setupFactory;
38
39
    /**
40
     * @var \eZ\Publish\API\Repository\Repository
41
     */
42
    private $repository;
43
44
    protected function setUp()
45
    {
46
        parent::setUp();
47
48
        try {
49
            // Use setup factory instance here w/o clearing data in case test don't need to
50
            $repository = $this->getSetupFactory()->getRepository(false);
51
52
            // Set session if we are testing the REST backend to make it
53
            // possible to persist data in the memory backend during multiple
54
            // requests.
55
            if ($repository instanceof Sessionable) {
56
                $repository->setSession($id = md5(microtime()));
57
            }
58
        } catch (PDOException $e) {
59
            $this->fail(
60
                'The communication with the database cannot be established. ' .
61
                "This is required in order to perform the tests.\n\n" .
62
                'Exception: ' . $e
63
            );
64
        } catch (Exception $e) {
65
            $this->fail(
66
                'Cannot create a repository with predefined user. ' .
67
                'Check the UserService or RoleService implementation. ' .
68
                PHP_EOL . PHP_EOL .
69
                'Exception: ' . $e
70
            );
71
        }
72
    }
73
74
    /**
75
     * Resets the temporary used repository between each test run.
76
     */
77
    protected function tearDown()
78
    {
79
        $this->repository = null;
80
        parent::tearDown();
81
    }
82
83
    /**
84
     * Returns the ID generator, fitting to the repository implementation.
85
     *
86
     * @return \eZ\Publish\API\Repository\Tests\IdManager
87
     */
88
    protected function getIdManager()
89
    {
90
        return $this->getSetupFactory()->getIdManager();
91
    }
92
93
    /**
94
     * Generates a repository specific ID value.
95
     *
96
     * @param string $type
97
     * @param mixed $rawId
98
     *
99
     * @return mixed
100
     */
101
    protected function generateId($type, $rawId)
102
    {
103
        return $this->getIdManager()->generateId($type, $rawId);
104
    }
105
106
    /**
107
     * Parses a repository specific ID value.
108
     *
109
     * @param string $type
110
     * @param mixed $id
111
     *
112
     * @return mixed
113
     */
114
    protected function parseId($type, $id)
115
    {
116
        return $this->getIdManager()->parseId($type, $id);
117
    }
118
119
    /**
120
     * Returns a config setting provided by the setup factory.
121
     *
122
     * @param string $configKey
123
     *
124
     * @return mixed
125
     */
126
    protected function getConfigValue($configKey)
127
    {
128
        return $this->getSetupFactory()->getConfigValue($configKey);
129
    }
130
131
    /**
132
     * Tests if the currently tested api is based on a V4 implementation.
133
     *
134
     * @return bool
135
     */
136
    protected function isVersion4()
137
    {
138
        return isset($_ENV['backendVersion']) && '4' === $_ENV['backendVersion'];
139
    }
140
141
    /**
142
     * @param bool $initialInitializeFromScratch Only has an effect if set in first call within a test
143
     *
144
     * @return \eZ\Publish\API\Repository\Repository
145
     */
146
    protected function getRepository($initialInitializeFromScratch = true)
147
    {
148
        if (null === $this->repository) {
149
            $this->repository = $this->getSetupFactory()->getRepository($initialInitializeFromScratch);
150
        }
151
152
        return $this->repository;
153
    }
154
155
    /**
156
     * @return \eZ\Publish\API\Repository\Tests\SetupFactory
157
     */
158
    protected function getSetupFactory()
159
    {
160
        if (null === $this->setupFactory) {
161
            if (false === isset($_ENV['setupFactory'])) {
162
                throw new \ErrorException(
163
                    'Missing mandatory setting $_ENV["setupFactory"], this should normally be set in the relevant phpunit-integration-*.xml file and refer to a setupFactory for the given StorageEngine/SearchEngine in use'
164
                );
165
            }
166
167
            $setupClass = $_ENV['setupFactory'];
168
            if (false === class_exists($setupClass)) {
169
                throw new \ErrorException(
170
                    sprintf(
171
                        '$_ENV["setupFactory"] does not reference an existing class: %s. Did you forget to install an package dependency?',
172
                        $setupClass
173
                    )
174
                );
175
            }
176
177
            $this->setupFactory = new $setupClass();
178
        }
179
180
        return $this->setupFactory;
181
    }
182
183
    /**
184
     * Asserts that properties given in $expectedValues are correctly set in
185
     * $actualObject.
186
     *
187
     * @param mixed[] $expectedValues
188
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
189
     */
190
    protected function assertPropertiesCorrect(array $expectedValues, ValueObject $actualObject)
191
    {
192
        foreach ($expectedValues as $propertyName => $propertyValue) {
193
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
194
        }
195
    }
196
197
    /**
198
     * Asserts that properties given in $expectedValues are correctly set in
199
     * $actualObject.
200
     *
201
     * If the property type is array, it will be sorted before comparison.
202
     *
203
     * @TODO: introduced because of randomly failing tests, ref: https://jira.ez.no/browse/EZP-21734
204
     *
205
     * @param mixed[] $expectedValues
206
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
207
     */
208
    protected function assertPropertiesCorrectUnsorted(array $expectedValues, ValueObject $actualObject)
209
    {
210
        foreach ($expectedValues as $propertyName => $propertyValue) {
211
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName, true);
212
        }
213
    }
214
215
    /**
216
     * Asserts all properties from $expectedValues are correctly set in
217
     * $actualObject. Additional (virtual) properties can be asserted using
218
     * $additionalProperties.
219
     *
220
     * @param \eZ\Publish\API\Repository\Values\ValueObject $expectedValues
221
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
222
     * @param array $propertyNames
0 ignored issues
show
Bug introduced by
There is no parameter named $propertyNames. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
223
     */
224
    protected function assertStructPropertiesCorrect(ValueObject $expectedValues, ValueObject $actualObject, array $additionalProperties = array())
225
    {
226
        foreach ($expectedValues as $propertyName => $propertyValue) {
0 ignored issues
show
Bug introduced by
The expression $expectedValues of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not traversable.
Loading history...
227
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
228
        }
229
230
        foreach ($additionalProperties as $propertyName) {
231
            $this->assertPropertiesEqual($propertyName, $expectedValues->$propertyName, $actualObject->$propertyName);
232
        }
233
    }
234
235
    /**
236
     * @see \eZ\Publish\API\Repository\Tests\BaseTest::assertPropertiesCorrectUnsorted()
237
     *
238
     * @param array $items An array of scalar values
239
     */
240
    private function sortItems(array &$items)
241
    {
242
        $sorter = function ($a, $b) {
243
            if (!is_scalar($a) || !is_scalar($b)) {
244
                $this->fail('Wrong usage: method ' . __METHOD__ . ' accepts only an array of scalar values');
245
            }
246
247
            return strcmp($a, $b);
248
        };
249
        usort($items, $sorter);
250
    }
251
252
    private function assertPropertiesEqual($propertyName, $expectedValue, $actualValue, $sortArray = false)
253
    {
254
        if ($expectedValue instanceof ArrayObject) {
255
            $expectedValue = $expectedValue->getArrayCopy();
256
        } elseif ($expectedValue instanceof DateTime) {
257
            $expectedValue = $expectedValue->format(DateTime::RFC850);
258
        }
259
        if ($actualValue instanceof ArrayObject) {
260
            $actualValue = $actualValue->getArrayCopy();
261
        } elseif ($actualValue instanceof DateTime) {
262
            $actualValue = $actualValue->format(DateTime::RFC850);
263
        }
264
265
        if ($sortArray && is_array($actualValue) && is_array($expectedValue)) {
266
            $this->sortItems($actualValue);
267
            $this->sortItems($expectedValue);
268
        }
269
270
        $this->assertEquals(
271
            $expectedValue,
272
            $actualValue,
273
            sprintf('Object property "%s" incorrect.', $propertyName)
274
        );
275
    }
276
277
    /**
278
     * Create a user in editor user group.
279
     *
280
     * @param string $login
281
     *
282
     * @return \eZ\Publish\API\Repository\Values\User\User
283
     */
284
    protected function createUserVersion1($login = 'user')
285
    {
286
        $repository = $this->getRepository();
287
288
        /* BEGIN: Inline */
289
        // ID of the "Editors" user group in an eZ Publish demo installation
290
        $editorsGroupId = 13;
291
292
        $userService = $repository->getUserService();
293
294
        // Instantiate a create struct with mandatory properties
295
        $userCreate = $userService->newUserCreateStruct(
296
            $login,
297
            "{$login}@example.com",
298
            'secret',
299
            'eng-US'
300
        );
301
        $userCreate->enabled = true;
302
303
        // Set some fields required by the user ContentType
304
        $userCreate->setField('first_name', 'Example');
305
        $userCreate->setField('last_name', 'User');
306
307
        // Load parent group for the user
308
        $group = $userService->loadUserGroup($editorsGroupId);
309
310
        // Create a new user instance.
311
        $user = $userService->createUser($userCreate, array($group));
312
        /* END: Inline */
313
314
        return $user;
315
    }
316
317
    /**
318
     * Create a user in new user group with editor rights limited to Media Library (/1/48/).
319
     *
320
     * @uses ::createCustomUserVersion1()
321
     *
322
     * @return \eZ\Publish\API\Repository\Values\User\User
323
     */
324
    protected function createMediaUserVersion1()
325
    {
326
        return $this->createCustomUserVersion1(
327
            'Media Editor',
328
            'Editor',
329
            new SubtreeLimitation(array('limitationValues' => array('/1/43/')))
330
        );
331
    }
332
333
    /**
334
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
335
     *
336
     * @param string $userGroupName Name of the new user group to create
337
     * @param string $roleIdentifier Role identifier to assign to the new group
338
     * @param RoleLimitation|null $roleLimitation
339
     *
340
     * @return \eZ\Publish\API\Repository\Values\User\User
341
     */
342
    protected function createCustomUserVersion1($userGroupName, $roleIdentifier, RoleLimitation $roleLimitation = null)
343
    {
344
        return $this->createCustomUserWithLogin(
345
            'user',
346
            '[email protected]',
347
            $userGroupName,
348
            $roleIdentifier,
349
            $roleLimitation
350
        );
351
    }
352
353
    /**
354
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
355
     *
356
     * @param string $login User login
357
     * @param string $email User e-mail
358
     * @param string $userGroupName Name of the new user group to create
359
     * @param string $roleIdentifier Role identifier to assign to the new group
360
     * @param RoleLimitation|null $roleLimitation
361
     * @return \eZ\Publish\API\Repository\Values\User\User
362
     */
363
    protected function createCustomUserWithLogin(
364
        $login,
365
        $email,
366
        $userGroupName,
367
        $roleIdentifier,
368
        RoleLimitation $roleLimitation = null
369
    ) {
370
        $repository = $this->getRepository();
371
372
        /* BEGIN: Inline */
373
        // ID of the "Users" user group in an eZ Publish demo installation
374
        $rootUsersGroupId = $this->generateId('location', 4);
375
376
        $roleService = $repository->getRoleService();
377
        $userService = $repository->getUserService();
378
379
        // Get a group create struct
380
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
381
        $userGroupCreate->setField('name', $userGroupName);
382
383
        // Create new group with media editor rights
384
        $userGroup = $userService->createUserGroup(
385
            $userGroupCreate,
386
            $userService->loadUserGroup($rootUsersGroupId)
387
        );
388
        $roleService->assignRoleToUserGroup(
389
            $roleService->loadRoleByIdentifier($roleIdentifier),
390
            $userGroup,
391
            $roleLimitation
392
        );
393
394
        // Instantiate a create struct with mandatory properties
395
        $userCreate = $userService->newUserCreateStruct(
396
            $login,
397
            $email,
398
            'secret',
399
            'eng-US'
400
        );
401
        $userCreate->enabled = true;
402
403
        // Set some fields required by the user ContentType
404
        $userCreate->setField('first_name', 'Example');
405
        $userCreate->setField('last_name', ucfirst($login));
406
407
        // Create a new user instance.
408
        $user = $userService->createUser($userCreate, array($userGroup));
409
        /* END: Inline */
410
411
        return $user;
412
    }
413
414
    /**
415
     * Create a user using given data.
416
     *
417
     * @param string $login
418
     * @param string $firstName
419
     * @param string $lastName
420
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup|null $userGroup optional user group, Editor by default
421
     *
422
     * @return \eZ\Publish\API\Repository\Values\User\User
423
     */
424
    protected function createUser($login, $firstName, $lastName, UserGroup $userGroup = null)
425
    {
426
        $repository = $this->getRepository();
427
428
        $userService = $repository->getUserService();
429
        if (null === $userGroup) {
430
            $userGroup = $userService->loadUserGroup(13);
431
        }
432
433
        // Instantiate a create struct with mandatory properties
434
        $userCreate = $userService->newUserCreateStruct(
435
            $login,
436
            "{$login}@example.com",
437
            'secret',
438
            'eng-US'
439
        );
440
        $userCreate->enabled = true;
441
442
        // Set some fields required by the user ContentType
443
        $userCreate->setField('first_name', $firstName);
444
        $userCreate->setField('last_name', $lastName);
445
446
        // Create a new user instance.
447
        $user = $userService->createUser($userCreate, array($userGroup));
448
449
        return $user;
450
    }
451
452
    /**
453
     * Only for internal use.
454
     *
455
     * Creates a \DateTime object for $timestamp in the current time zone
456
     *
457
     * @param int $timestamp
458
     *
459
     * @return \DateTime
460
     */
461
    public function createDateTime($timestamp = null)
462
    {
463
        $dateTime = new \DateTime();
464
        if ($timestamp !== null) {
465
            $dateTime->setTimestamp($timestamp);
466
        }
467
468
        return $dateTime;
469
    }
470
471
    /**
472
     * Calls given Repository's aggregated SearchHandler::refresh().
473
     *
474
     * Currently implemented only in Solr search engine.
475
     *
476
     * @param \eZ\Publish\API\Repository\Repository $repository
477
     */
478
    protected function refreshSearch(Repository $repository)
479
    {
480
        $setupFactory = $this->getSetupFactory();
481
482
        if (!$setupFactory instanceof LegacySolrSetupFactory) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
483
            return;
484
        }
485
486
        while (true) {
487
            $repositoryReflection = new \ReflectionObject($repository);
488
            // If the repository is decorated, we need to recurse in the "repository" property
489
            if (!$repositoryReflection->hasProperty('repository')) {
490
                break;
491
            }
492
493
            $repositoryProperty = $repositoryReflection->getProperty('repository');
494
            $repositoryProperty->setAccessible(true);
495
            $repository = $repositoryProperty->getValue($repository);
496
        }
497
498
        $searchHandlerProperty = new \ReflectionProperty($repository, 'searchHandler');
499
        $searchHandlerProperty->setAccessible(true);
500
501
        /** @var \EzSystems\EzPlatformSolrSearchEngine\Handler $searchHandler */
502
        $searchHandler = $searchHandlerProperty->getValue($repository);
503
504
        $searchHandler->commit();
505
    }
506
507
    /**
508
     * Create role of a given name with the given policies described by an array.
509
     *
510
     * @param $roleName
511
     * @param array $policiesData [['module' => 'content', 'function' => 'read', 'limitations' => []]
512
     *
513
     * @return \eZ\Publish\API\Repository\Values\User\Role
514
     *
515
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
516
     * @throws \eZ\Publish\API\Repository\Exceptions\LimitationValidationException
517
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
518
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
519
     */
520
    public function createRoleWithPolicies($roleName, array $policiesData)
521
    {
522
        $repository = $this->getRepository(false);
523
        $roleService = $repository->getRoleService();
524
525
        $roleCreateStruct = $roleService->newRoleCreateStruct($roleName);
526
        foreach ($policiesData as $policyData) {
527
            $policyCreateStruct = $roleService->newPolicyCreateStruct(
528
                $policyData['module'],
529
                $policyData['function']
530
            );
531
532
            if (isset($policyData['limitations'])) {
533
                foreach ($policyData['limitations'] as $limitation) {
534
                    $policyCreateStruct->addLimitation($limitation);
535
                }
536
            }
537
538
            $roleCreateStruct->addPolicy($policyCreateStruct);
539
        }
540
541
        $roleDraft = $roleService->createRole($roleCreateStruct);
542
543
        $roleService->publishRoleDraft($roleDraft);
544
545
        return $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...
546
    }
547
}
548