Completed
Push — master ( cc4152...a16046 )
by
unknown
44:04 queued 16:02
created

BaseTest   F

Complexity

Total Complexity 71

Size/Duplication

Total Lines 743
Duplicated Lines 1.88 %

Coupling/Cohesion

Components 1
Dependencies 23

Importance

Changes 0
Metric Value
wmc 71
lcom 1
cbo 23
dl 14
loc 743
rs 2.577
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 29 4
A tearDown() 0 5 1
A getIdManager() 0 4 1
A generateId() 0 4 1
A parseId() 0 4 1
A getConfigValue() 0 4 1
A isVersion4() 0 4 2
A getRepository() 0 8 2
A getSetupFactory() 0 26 5
A assertPropertiesCorrect() 0 18 6
A assertPropertiesCorrectUnsorted() 7 10 3
A assertStructPropertiesCorrect() 7 14 4
A sortItems() 0 11 3
B assertPropertiesEqual() 0 24 8
A createUserVersion1() 0 32 1
A createMediaUserVersion1() 0 8 1
A createCustomUserVersion1() 0 10 1
A createCustomUserWithLogin() 0 50 1
A createUser() 0 27 2
A createDateTime() 0 9 2
A refreshSearch() 0 28 4
A createRoleWithPolicies() 0 27 4
A createUserWithPolicies() 0 29 2
A getRawDatabaseConnection() 0 14 2
A performRawDatabaseOperation() 0 21 2
A assertValidationErrorOccurs() 0 8 1
A createFolder() 0 26 3
A updateFolder() 0 15 2
A createLanguage() 0 12 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BaseTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseTest, and based on these observations, apply Extract Interface, too.

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
            if ($propertyValue instanceof ValueObject) {
232
                $this->assertStructPropertiesCorrect($propertyValue, $actualObject->$propertyName);
233
            } else {
234
                $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName, true);
235
            }
236
        }
237
    }
238
239
    /**
240
     * Asserts all properties from $expectedValues are correctly set in
241
     * $actualObject. Additional (virtual) properties can be asserted using
242
     * $additionalProperties.
243
     *
244
     * @param \eZ\Publish\API\Repository\Values\ValueObject $expectedValues
245
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
246
     * @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...
247
     */
248
    protected function assertStructPropertiesCorrect(ValueObject $expectedValues, ValueObject $actualObject, array $additionalProperties = array())
249
    {
250 View Code Duplication
        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...
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...
251
            if ($propertyValue instanceof ValueObject) {
252
                $this->assertStructPropertiesCorrect($propertyValue, $actualObject->$propertyName);
253
            } else {
254
                $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
255
            }
256
        }
257
258
        foreach ($additionalProperties as $propertyName) {
259
            $this->assertPropertiesEqual($propertyName, $expectedValues->$propertyName, $actualObject->$propertyName);
260
        }
261
    }
262
263
    /**
264
     * @see \eZ\Publish\API\Repository\Tests\BaseTest::assertPropertiesCorrectUnsorted()
265
     *
266
     * @param array $items An array of scalar values
267
     */
268
    private function sortItems(array &$items)
269
    {
270
        $sorter = function ($a, $b) {
271
            if (!is_scalar($a) || !is_scalar($b)) {
272
                $this->fail('Wrong usage: method ' . __METHOD__ . ' accepts only an array of scalar values');
273
            }
274
275
            return strcmp($a, $b);
276
        };
277
        usort($items, $sorter);
278
    }
279
280
    private function assertPropertiesEqual($propertyName, $expectedValue, $actualValue, $sortArray = false)
281
    {
282
        if ($expectedValue instanceof ArrayObject) {
283
            $expectedValue = $expectedValue->getArrayCopy();
284
        } elseif ($expectedValue instanceof DateTime) {
285
            $expectedValue = $expectedValue->format(DateTime::RFC850);
286
        }
287
        if ($actualValue instanceof ArrayObject) {
288
            $actualValue = $actualValue->getArrayCopy();
289
        } elseif ($actualValue instanceof DateTime) {
290
            $actualValue = $actualValue->format(DateTime::RFC850);
291
        }
292
293
        if ($sortArray && is_array($actualValue) && is_array($expectedValue)) {
294
            $this->sortItems($actualValue);
295
            $this->sortItems($expectedValue);
296
        }
297
298
        $this->assertEquals(
299
            $expectedValue,
300
            $actualValue,
301
            sprintf('Object property "%s" incorrect.', $propertyName)
302
        );
303
    }
304
305
    /**
306
     * Create a user in editor user group.
307
     *
308
     * @param string $login
309
     *
310
     * @return \eZ\Publish\API\Repository\Values\User\User
311
     */
312
    protected function createUserVersion1($login = 'user')
313
    {
314
        $repository = $this->getRepository();
315
316
        /* BEGIN: Inline */
317
        // ID of the "Editors" user group in an eZ Publish demo installation
318
        $editorsGroupId = 13;
319
320
        $userService = $repository->getUserService();
321
322
        // Instantiate a create struct with mandatory properties
323
        $userCreate = $userService->newUserCreateStruct(
324
            $login,
325
            "{$login}@example.com",
326
            'secret',
327
            'eng-US'
328
        );
329
        $userCreate->enabled = true;
330
331
        // Set some fields required by the user ContentType
332
        $userCreate->setField('first_name', 'Example');
333
        $userCreate->setField('last_name', 'User');
334
335
        // Load parent group for the user
336
        $group = $userService->loadUserGroup($editorsGroupId);
337
338
        // Create a new user instance.
339
        $user = $userService->createUser($userCreate, array($group));
340
        /* END: Inline */
341
342
        return $user;
343
    }
344
345
    /**
346
     * Create a user in new user group with editor rights limited to Media Library (/1/48/).
347
     *
348
     * @uses ::createCustomUserVersion1()
349
     *
350
     * @return \eZ\Publish\API\Repository\Values\User\User
351
     */
352
    protected function createMediaUserVersion1()
353
    {
354
        return $this->createCustomUserVersion1(
355
            'Media Editor',
356
            'Editor',
357
            new SubtreeLimitation(array('limitationValues' => array('/1/43/')))
358
        );
359
    }
360
361
    /**
362
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
363
     *
364
     * @param string $userGroupName Name of the new user group to create
365
     * @param string $roleIdentifier Role identifier to assign to the new group
366
     * @param RoleLimitation|null $roleLimitation
367
     *
368
     * @return \eZ\Publish\API\Repository\Values\User\User
369
     */
370
    protected function createCustomUserVersion1($userGroupName, $roleIdentifier, RoleLimitation $roleLimitation = null)
371
    {
372
        return $this->createCustomUserWithLogin(
373
            'user',
374
            '[email protected]',
375
            $userGroupName,
376
            $roleIdentifier,
377
            $roleLimitation
378
        );
379
    }
380
381
    /**
382
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
383
     *
384
     * @param string $login User login
385
     * @param string $email User e-mail
386
     * @param string $userGroupName Name of the new user group to create
387
     * @param string $roleIdentifier Role identifier to assign to the new group
388
     * @param RoleLimitation|null $roleLimitation
389
     * @return \eZ\Publish\API\Repository\Values\User\User
390
     */
391
    protected function createCustomUserWithLogin(
392
        $login,
393
        $email,
394
        $userGroupName,
395
        $roleIdentifier,
396
        RoleLimitation $roleLimitation = null
397
    ) {
398
        $repository = $this->getRepository();
399
400
        /* BEGIN: Inline */
401
        // ID of the "Users" user group in an eZ Publish demo installation
402
        $rootUsersGroupId = $this->generateId('location', 4);
403
404
        $roleService = $repository->getRoleService();
405
        $userService = $repository->getUserService();
406
407
        // Get a group create struct
408
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
409
        $userGroupCreate->setField('name', $userGroupName);
410
411
        // Create new group with media editor rights
412
        $userGroup = $userService->createUserGroup(
413
            $userGroupCreate,
414
            $userService->loadUserGroup($rootUsersGroupId)
415
        );
416
        $roleService->assignRoleToUserGroup(
417
            $roleService->loadRoleByIdentifier($roleIdentifier),
418
            $userGroup,
419
            $roleLimitation
420
        );
421
422
        // Instantiate a create struct with mandatory properties
423
        $userCreate = $userService->newUserCreateStruct(
424
            $login,
425
            $email,
426
            'secret',
427
            'eng-US'
428
        );
429
        $userCreate->enabled = true;
430
431
        // Set some fields required by the user ContentType
432
        $userCreate->setField('first_name', 'Example');
433
        $userCreate->setField('last_name', ucfirst($login));
434
435
        // Create a new user instance.
436
        $user = $userService->createUser($userCreate, array($userGroup));
437
        /* END: Inline */
438
439
        return $user;
440
    }
441
442
    /**
443
     * Create a user using given data.
444
     *
445
     * @param string $login
446
     * @param string $firstName
447
     * @param string $lastName
448
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup|null $userGroup optional user group, Editor by default
449
     *
450
     * @return \eZ\Publish\API\Repository\Values\User\User
451
     */
452
    protected function createUser($login, $firstName, $lastName, UserGroup $userGroup = null)
453
    {
454
        $repository = $this->getRepository();
455
456
        $userService = $repository->getUserService();
457
        if (null === $userGroup) {
458
            $userGroup = $userService->loadUserGroup(13);
459
        }
460
461
        // Instantiate a create struct with mandatory properties
462
        $userCreate = $userService->newUserCreateStruct(
463
            $login,
464
            "{$login}@example.com",
465
            'secret',
466
            'eng-US'
467
        );
468
        $userCreate->enabled = true;
469
470
        // Set some fields required by the user ContentType
471
        $userCreate->setField('first_name', $firstName);
472
        $userCreate->setField('last_name', $lastName);
473
474
        // Create a new user instance.
475
        $user = $userService->createUser($userCreate, array($userGroup));
476
477
        return $user;
478
    }
479
480
    /**
481
     * Only for internal use.
482
     *
483
     * Creates a \DateTime object for $timestamp in the current time zone
484
     *
485
     * @param int $timestamp
486
     *
487
     * @return \DateTime
488
     */
489
    public function createDateTime($timestamp = null)
490
    {
491
        $dateTime = new \DateTime();
492
        if ($timestamp !== null) {
493
            $dateTime->setTimestamp($timestamp);
494
        }
495
496
        return $dateTime;
497
    }
498
499
    /**
500
     * Calls given Repository's aggregated SearchHandler::refresh().
501
     *
502
     * Currently implemented only in Solr search engine.
503
     *
504
     * @param \eZ\Publish\API\Repository\Repository $repository
505
     */
506
    protected function refreshSearch(Repository $repository)
507
    {
508
        $setupFactory = $this->getSetupFactory();
509
510
        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...
511
            return;
512
        }
513
514
        while (true) {
515
            $repositoryReflection = new \ReflectionObject($repository);
516
            // If the repository is decorated, we need to recurse in the "repository" property
517
            if (!$repositoryReflection->hasProperty('repository')) {
518
                break;
519
            }
520
521
            $repositoryProperty = $repositoryReflection->getProperty('repository');
522
            $repositoryProperty->setAccessible(true);
523
            $repository = $repositoryProperty->getValue($repository);
524
        }
525
526
        $searchHandlerProperty = new \ReflectionProperty($repository, 'searchHandler');
527
        $searchHandlerProperty->setAccessible(true);
528
529
        /** @var \EzSystems\EzPlatformSolrSearchEngine\Handler $searchHandler */
530
        $searchHandler = $searchHandlerProperty->getValue($repository);
531
532
        $searchHandler->commit();
533
    }
534
535
    /**
536
     * Create role of a given name with the given policies described by an array.
537
     *
538
     * @param $roleName
539
     * @param array $policiesData [['module' => 'content', 'function' => 'read', 'limitations' => []]
540
     *
541
     * @return \eZ\Publish\API\Repository\Values\User\Role
542
     *
543
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
544
     * @throws \eZ\Publish\API\Repository\Exceptions\LimitationValidationException
545
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
546
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
547
     */
548
    public function createRoleWithPolicies($roleName, array $policiesData)
549
    {
550
        $repository = $this->getRepository(false);
551
        $roleService = $repository->getRoleService();
552
553
        $roleCreateStruct = $roleService->newRoleCreateStruct($roleName);
554
        foreach ($policiesData as $policyData) {
555
            $policyCreateStruct = $roleService->newPolicyCreateStruct(
556
                $policyData['module'],
557
                $policyData['function']
558
            );
559
560
            if (isset($policyData['limitations'])) {
561
                foreach ($policyData['limitations'] as $limitation) {
562
                    $policyCreateStruct->addLimitation($limitation);
563
                }
564
            }
565
566
            $roleCreateStruct->addPolicy($policyCreateStruct);
567
        }
568
569
        $roleDraft = $roleService->createRole($roleCreateStruct);
570
571
        $roleService->publishRoleDraft($roleDraft);
572
573
        return $roleService->loadRole($roleDraft->id);
574
    }
575
576
    /**
577
     * Create user and assign new role with the given policies.
578
     *
579
     * @param string $login
580
     * @param array $policiesData list of policies in the form of <code>[ [ 'module' => 'name', 'function' => 'name'] ]</code>
581
     *
582
     * @return \eZ\Publish\API\Repository\Values\User\User
583
     *
584
     * @throws \Exception
585
     */
586
    public function createUserWithPolicies($login, array $policiesData)
587
    {
588
        $repository = $this->getRepository(false);
589
        $roleService = $repository->getRoleService();
590
        $userService = $repository->getUserService();
591
592
        $repository->beginTransaction();
593
        try {
594
            $userCreateStruct = $userService->newUserCreateStruct(
595
                $login,
596
                "{$login}@test.local",
597
                $login,
598
                'eng-GB'
599
            );
600
            $userCreateStruct->setField('first_name', $login);
601
            $userCreateStruct->setField('last_name', $login);
602
            $user = $userService->createUser($userCreateStruct, [$userService->loadUserGroup(4)]);
603
604
            $role = $this->createRoleWithPolicies(uniqid('role_for_' . $login . '_', true), $policiesData);
605
            $roleService->assignRoleToUser($role, $user);
606
607
            $repository->commit();
608
609
            return $user;
610
        } catch (\Exception $ex) {
611
            $repository->rollback();
612
            throw $ex;
613
        }
614
    }
615
616
    /**
617
     * @return \Doctrine\DBAL\Connection
618
     *
619
     * @throws \ErrorException
620
     */
621
    protected function getRawDatabaseConnection()
622
    {
623
        $connection = $this
624
            ->getSetupFactory()
625
            ->getServiceContainer()->get('ezpublish.api.storage_engine.legacy.connection');
626
627
        if (!$connection instanceof Connection) {
628
            throw new \RuntimeException(
629
                sprintf('Expected %s got %s', Connection::class, get_class($connection))
630
            );
631
        }
632
633
        return $connection;
634
    }
635
636
    /**
637
     * Executes the given callback passing raw Database Connection (\Doctrine\DBAL\Connection).
638
     * Returns the result returned by the given callback.
639
     *
640
     * **Note**: The method clears the entire persistence cache pool.
641
     *
642
     * @throws \Exception
643
     *
644
     * @param callable $callback
645
     *
646
     * @return mixed the return result of the given callback
647
     */
648
    public function performRawDatabaseOperation(callable $callback)
649
    {
650
        $repository = $this->getRepository(false);
651
        $repository->beginTransaction();
652
        try {
653
            $callback(
654
                $this->getRawDatabaseConnection()
655
            );
656
            $repository->commit();
657
        } catch (Exception $e) {
658
            $repository->rollback();
659
            throw $e;
660
        }
661
662
        /** @var \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface $cachePool */
663
        $cachePool = $this
664
            ->getSetupFactory()
665
            ->getServiceContainer()->get('ezpublish.cache_pool');
666
667
        $cachePool->clear();
668
    }
669
670
    /**
671
     * Traverse all errors for all fields in all Translations to find expected one.
672
     *
673
     * @param \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException $exception
674
     * @param string $expectedValidationErrorMessage
675
     */
676
    protected function assertValidationErrorOccurs(
677
        ContentFieldValidationException $exception,
678
        $expectedValidationErrorMessage
679
    ) {
680
        $constraint = new PHPUnitConstraintValidationErrorOccurs($expectedValidationErrorMessage);
681
682
        self::assertThat($exception, $constraint);
683
    }
684
685
    /**
686
     * Create 'folder' Content.
687
     *
688
     * @param array $names Folder names in the form of <code>['&lt;language_code&gt;' => '&lt;name&gt;']</code>
689
     * @param int $parentLocationId
690
     *
691
     * @return \eZ\Publish\API\Repository\Values\Content\Content published Content
692
     *
693
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
694
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
695
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
696
     */
697
    protected function createFolder(array $names, $parentLocationId)
698
    {
699
        $repository = $this->getRepository(false);
700
        $contentService = $repository->getContentService();
701
        $contentTypeService = $repository->getContentTypeService();
702
        $locationService = $repository->getLocationService();
703
704
        if (empty($names)) {
705
            throw new \RuntimeException(sprintf('%s expects non-empty names list', __METHOD__));
706
        }
707
        $mainLanguageCode = array_keys($names)[0];
708
709
        $struct = $contentService->newContentCreateStruct(
710
            $contentTypeService->loadContentTypeByIdentifier('folder'),
711
            $mainLanguageCode
712
        );
713
        foreach ($names as $languageCode => $translatedName) {
714
            $struct->setField('name', $translatedName, $languageCode);
715
        }
716
        $contentDraft = $contentService->createContent(
717
            $struct,
718
            [$locationService->newLocationCreateStruct($parentLocationId)]
719
        );
720
721
        return $contentService->publishVersion($contentDraft->versionInfo);
722
    }
723
724
    /**
725
     * Update 'folder' Content.
726
     *
727
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
728
     * @param array $names Folder names in the form of <code>['&lt;language_code&gt;' => '&lt;name&gt;']</code>
729
     *
730
     * @return \eZ\Publish\API\Repository\Values\Content\Content
731
     *
732
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
733
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
734
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException
735
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
736
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
737
     */
738
    protected function updateFolder(Content $content, array $names)
739
    {
740
        $repository = $this->getRepository(false);
741
        $contentService = $repository->getContentService();
742
743
        $draft = $contentService->createContentDraft($content->contentInfo);
744
        $struct = $contentService->newContentUpdateStruct();
745
        $struct->initialLanguageCode = array_keys($names)[0];
0 ignored issues
show
Documentation Bug introduced by
It seems like array_keys($names)[0] can also be of type integer. However, the property $initialLanguageCode is declared as type string. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
746
747
        foreach ($names as $languageCode => $translatedName) {
748
            $struct->setField('name', $translatedName, $languageCode);
749
        }
750
751
        return $contentService->updateContent($draft->versionInfo, $struct);
752
    }
753
754
    /**
755
     * Add new Language to the Repository.
756
     *
757
     * @param string $languageCode
758
     * @param string $name
759
     * @param bool $enabled
760
     *
761
     * @return \eZ\Publish\API\Repository\Values\Content\Language
762
     */
763
    protected function createLanguage(string $languageCode, string $name, bool $enabled = true): Language
764
    {
765
        $repository = $this->getRepository(false);
766
767
        $languageService = $repository->getContentLanguageService();
768
        $languageStruct = $languageService->newLanguageCreateStruct();
769
        $languageStruct->name = $name;
770
        $languageStruct->languageCode = $languageCode;
771
        $languageStruct->enabled = $enabled;
772
773
        return $languageService->createLanguage($languageStruct);
774
    }
775
}
776