Completed
Push — 7.5 ( 06837d...777d30 )
by
unknown
22:36 queued 12s
created

testUpdateContentMainTranslation()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 57
rs 8.9381
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * File containing the ContentServiceTest 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 eZ\Publish\API\Repository\Exceptions\BadStateException;
12
use eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException;
13
use eZ\Publish\API\Repository\Exceptions\InvalidArgumentException as APIInvalidArgumentException;
14
use eZ\Publish\API\Repository\Values\Content\Content;
15
use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
16
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
17
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
18
use eZ\Publish\API\Repository\Values\Content\ContentMetadataUpdateStruct;
19
use eZ\Publish\API\Repository\Values\Content\Field;
20
use eZ\Publish\API\Repository\Values\Content\Location;
21
use eZ\Publish\API\Repository\Values\Content\DraftList\Item\UnauthorizedContentDraftListItem;
22
use eZ\Publish\API\Repository\Values\Content\URLAlias;
23
use eZ\Publish\API\Repository\Values\Content\Relation;
24
use eZ\Publish\API\Repository\Values\Content\VersionInfo;
25
use eZ\Publish\API\Repository\Values\User\Limitation\SectionLimitation;
26
use eZ\Publish\API\Repository\Values\User\Limitation\LocationLimitation;
27
use eZ\Publish\API\Repository\Values\User\Limitation\ContentTypeLimitation;
28
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
29
use DOMDocument;
30
use Exception;
31
use eZ\Publish\API\Repository\Values\User\User;
32
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException as CoreUnauthorizedException;
33
use eZ\Publish\Core\Repository\Values\Content\ContentUpdateStruct;
34
use InvalidArgumentException;
35
36
/**
37
 * Test case for operations in the ContentService using in memory storage.
38
 *
39
 * @see \eZ\Publish\API\Repository\ContentService
40
 * @group content
41
 */
42
class ContentServiceTest extends BaseContentServiceTest
43
{
44
    private const ADMINISTRATORS_USER_GROUP_NAME = 'Administrators';
45
    private const ADMINISTRATORS_USER_GROUP_ID = 12;
46
    private const ADMINISTRATORS_USER_GROUP_LOCATION_ID = 13;
47
48
    private const WRITERS_USER_GROUP_NAME = 'Writers';
49
50
    private const MEMBERS_USER_GROUP_ID = 11;
51
52
    private const MEDIA_CONTENT_ID = 41;
53
54
    private const MEDIA_REMOTE_ID = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
55
    private const DEMO_DESIGN_REMOTE_ID = '8b8b22fe3c6061ed500fbd2b377b885f';
56
57
    private const FORUM_IDENTIFIER = 'forum';
58
59
    private const ENG_US = 'eng-US';
60
    private const GER_DE = 'ger-DE';
61
    private const ENG_GB = 'eng-GB';
62
63
    /** @var \eZ\Publish\API\Repository\PermissionResolver */
64
    private $permissionResolver;
65
66
    /** @var \eZ\Publish\API\Repository\ContentService */
67
    private $contentService;
68
69
    /** @var \eZ\Publish\API\Repository\LocationService */
70
    private $locationService;
71
72
    public function setUp(): void
73
    {
74
        parent::setUp();
75
76
        $repository = $this->getRepository();
77
        $this->permissionResolver = $repository->getPermissionResolver();
78
        $this->contentService = $repository->getContentService();
79
        $this->locationService = $repository->getLocationService();
80
    }
81
82
    /**
83
     * Test for the newContentCreateStruct() method.
84
     *
85
     * @see \eZ\Publish\API\Repository\ContentService::newContentCreateStruct()
86
     * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier
87
     * @group user
88
     * @group field-type
89
     */
90
    public function testNewContentCreateStruct()
91
    {
92
        $contentTypeService = $this->getRepository()->getContentTypeService();
93
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
94
95
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
96
97
        $this->assertInstanceOf(ContentCreateStruct::class, $contentCreate);
98
    }
99
100
    /**
101
     * Test for the createContent() method.
102
     *
103
     * @return \eZ\Publish\API\Repository\Values\Content\Content
104
     *
105
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
106
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentCreateStruct
107
     * @group user
108
     * @group field-type
109
     */
110
    public function testCreateContent()
111
    {
112
        if ($this->isVersion4()) {
113
            $this->markTestSkipped('This test requires eZ Publish 5');
114
        }
115
116
        $contentTypeService = $this->getRepository()->getContentTypeService();
117
118
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
119
120
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
121
        $contentCreate->setField('name', 'My awesome forum');
122
123
        $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
124
        $contentCreate->alwaysAvailable = true;
125
126
        $content = $this->contentService->createContent($contentCreate);
127
128
        $this->assertInstanceOf(Content::class, $content);
129
130
        return $content;
131
    }
132
133
    /**
134
     * Test for the createContent() method.
135
     *
136
     * Tests made for issue #EZP-20955 where Anonymous user is granted access to create content
137
     * and should have access to do that.
138
     *
139
     * @return \eZ\Publish\API\Repository\Values\Content\Content
140
     *
141
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
142
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentCreateStruct
143
     * @group user
144
     * @group field-type
145
     */
146
    public function testCreateContentAndPublishWithPrivilegedAnonymousUser()
147
    {
148
        if ($this->isVersion4()) {
149
            $this->markTestSkipped('This test requires eZ Publish 5');
150
        }
151
152
        $anonymousUserId = $this->generateId('user', 10);
153
154
        $repository = $this->getRepository();
155
        $contentTypeService = $this->getRepository()->getContentTypeService();
156
        $roleService = $repository->getRoleService();
157
158
        // Give Anonymous user role additional rights
159
        $role = $roleService->loadRoleByIdentifier('Anonymous');
160
        $roleDraft = $roleService->createRoleDraft($role);
161
        $policyCreateStruct = $roleService->newPolicyCreateStruct('content', 'create');
162
        $policyCreateStruct->addLimitation(new SectionLimitation(['limitationValues' => [1]]));
163
        $policyCreateStruct->addLimitation(new LocationLimitation(['limitationValues' => [2]]));
164
        $policyCreateStruct->addLimitation(new ContentTypeLimitation(['limitationValues' => [1]]));
165
        $roleDraft = $roleService->addPolicyByRoleDraft($roleDraft, $policyCreateStruct);
166
167
        $policyCreateStruct = $roleService->newPolicyCreateStruct('content', 'publish');
168
        $policyCreateStruct->addLimitation(new SectionLimitation(['limitationValues' => [1]]));
169
        $policyCreateStruct->addLimitation(new LocationLimitation(['limitationValues' => [2]]));
170
        $policyCreateStruct->addLimitation(new ContentTypeLimitation(['limitationValues' => [1]]));
171
        $roleDraft = $roleService->addPolicyByRoleDraft($roleDraft, $policyCreateStruct);
172
        $roleService->publishRoleDraft($roleDraft);
173
174
        // Set Anonymous user as current
175
        $repository->getPermissionResolver()->setCurrentUserReference($repository->getUserService()->loadUser($anonymousUserId));
176
177
        // Create a new content object:
178
        $contentCreate = $this->contentService->newContentCreateStruct(
179
            $contentTypeService->loadContentTypeByIdentifier('folder'),
180
            self::ENG_GB
181
        );
182
183
        $contentCreate->setField('name', 'Folder 1');
184
185
        $content = $this->contentService->createContent(
186
            $contentCreate,
187
            [$this->locationService->newLocationCreateStruct(2)]
188
        );
189
190
        $this->contentService->publishVersion(
191
            $content->getVersionInfo()
192
        );
193
    }
194
195
    /**
196
     * Test for the createContent() method.
197
     *
198
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
199
     *
200
     * @return \eZ\Publish\API\Repository\Values\Content\Content
201
     *
202
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
203
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
204
     */
205
    public function testCreateContentSetsContentInfo($content)
206
    {
207
        $this->assertInstanceOf(ContentInfo::class, $content->contentInfo);
208
209
        return $content;
210
    }
211
212
    /**
213
     * Test for the createContent() method.
214
     *
215
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
216
     *
217
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
218
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentSetsContentInfo
219
     */
220
    public function testCreateContentSetsExpectedContentInfo($content)
221
    {
222
        $this->assertEquals(
223
            [
224
                $content->id,
225
                28, // id of content type "forum"
226
                true,
227
                1,
228
                'abcdef0123456789abcdef0123456789',
229
                self::ENG_US,
230
                $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
231
                false,
232
                null,
233
                // Main Location id for unpublished Content should be null
234
                null,
235
            ],
236
            [
237
                $content->contentInfo->id,
238
                $content->contentInfo->contentTypeId,
239
                $content->contentInfo->alwaysAvailable,
240
                $content->contentInfo->currentVersionNo,
241
                $content->contentInfo->remoteId,
242
                $content->contentInfo->mainLanguageCode,
243
                $content->contentInfo->ownerId,
244
                $content->contentInfo->published,
245
                $content->contentInfo->publishedDate,
246
                $content->contentInfo->mainLocationId,
247
            ]
248
        );
249
    }
250
251
    /**
252
     * Test for the createContent() method.
253
     *
254
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
255
     *
256
     * @return \eZ\Publish\API\Repository\Values\Content\Content
257
     *
258
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
259
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
260
     */
261
    public function testCreateContentSetsVersionInfo($content)
262
    {
263
        $this->assertInstanceOf(VersionInfo::class, $content->getVersionInfo());
264
265
        return $content;
266
    }
267
268
    /**
269
     * Test for the createContent() method.
270
     *
271
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
272
     *
273
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
274
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentSetsVersionInfo
275
     */
276
    public function testCreateContentSetsExpectedVersionInfo($content)
277
    {
278
        $this->assertEquals(
279
            [
280
                'status' => VersionInfo::STATUS_DRAFT,
281
                'versionNo' => 1,
282
                'creatorId' => $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
283
                'initialLanguageCode' => self::ENG_US,
284
            ],
285
            [
286
                'status' => $content->getVersionInfo()->status,
287
                'versionNo' => $content->getVersionInfo()->versionNo,
288
                'creatorId' => $content->getVersionInfo()->creatorId,
289
                'initialLanguageCode' => $content->getVersionInfo()->initialLanguageCode,
290
            ]
291
        );
292
        $this->assertTrue($content->getVersionInfo()->isDraft());
293
        $this->assertFalse($content->getVersionInfo()->isPublished());
294
        $this->assertFalse($content->getVersionInfo()->isArchived());
295
    }
296
297
    /**
298
     * Test for the createContent() method.
299
     *
300
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
301
     *
302
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
303
     * @depends testCreateContent
304
     */
305
    public function testCreateContentSetsExpectedContentType($content)
306
    {
307
        $contentType = $content->getContentType();
308
309
        $this->assertEquals(
310
            [
311
                $contentType->id,
312
                // Won't match as it's set to true in createContentDraftVersion1()
313
                //$contentType->defaultAlwaysAvailable,
314
                //$contentType->defaultSortField,
315
                //$contentType->defaultSortOrder,
316
            ],
317
            [
318
                $content->contentInfo->contentTypeId,
319
                //$content->contentInfo->alwaysAvailable,
320
                //$location->sortField,
321
                //$location->sortOrder,
322
            ]
323
        );
324
    }
325
326
    /**
327
     * Test for the createContent() method.
328
     *
329
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
330
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
331
     */
332
    public function testCreateContentThrowsInvalidArgumentException()
333
    {
334
        if ($this->isVersion4()) {
335
            $this->markTestSkipped('This test requires eZ Publish 5');
336
        }
337
338
        $contentTypeService = $this->getRepository()->getContentTypeService();
339
340
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
341
342
        $contentCreate1 = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
343
        $contentCreate1->setField('name', 'An awesome Sidelfingen forum');
344
345
        $contentCreate1->remoteId = 'abcdef0123456789abcdef0123456789';
346
        $contentCreate1->alwaysAvailable = true;
347
348
        $draft = $this->contentService->createContent($contentCreate1);
349
        $this->contentService->publishVersion($draft->versionInfo);
350
351
        $contentCreate2 = $this->contentService->newContentCreateStruct($contentType, self::ENG_GB);
352
        $contentCreate2->setField('name', 'An awesome Bielefeld forum');
353
354
        $contentCreate2->remoteId = 'abcdef0123456789abcdef0123456789';
355
        $contentCreate2->alwaysAvailable = false;
356
357
        $this->expectException(APIInvalidArgumentException::class);
358
        $this->contentService->createContent($contentCreate2);
359
    }
360
361
    /**
362
     * Test for the createContent() method.
363
     *
364
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
365
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
366
     */
367
    public function testCreateContentThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
368
    {
369
        $contentTypeService = $this->getRepository()->getContentTypeService();
370
371
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
372
373
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
374
        // The name field does only accept strings and null as its values
375
        $contentCreate->setField('name', new \stdClass());
376
377
        $this->expectException(APIInvalidArgumentException::class);
378
        $this->contentService->createContent($contentCreate);
379
    }
380
381
    /**
382
     * Test for the createContent() method.
383
     *
384
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
385
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
386
     */
387
    public function testCreateContentThrowsContentFieldValidationException()
388
    {
389
        $contentTypeService = $this->getRepository()->getContentTypeService();
390
391
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
392
393
        $contentCreate1 = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
394
        $contentCreate1->setField('name', 'An awesome Sidelfingen folder');
395
        // Violates string length constraint
396
        $contentCreate1->setField('short_name', str_repeat('a', 200));
397
398
        $this->expectException(ContentFieldValidationException::class);
399
400
        // Throws ContentFieldValidationException, since short_name does not pass validation of the string length validator
401
        $this->contentService->createContent($contentCreate1);
402
    }
403
404
    /**
405
     * Test for the createContent() method.
406
     *
407
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
408
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
409
     */
410
    public function testCreateContentRequiredFieldMissing()
411
    {
412
        $contentTypeService = $this->getRepository()->getContentTypeService();
413
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
414
415
        $contentCreate1 = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
416
        // Required field "name" is not set
417
418
        $this->expectException(ContentFieldValidationException::class);
419
420
        // Throws a ContentFieldValidationException, since a required field is missing
421
        $this->contentService->createContent($contentCreate1);
422
    }
423
424
    /**
425
     * Test for the createContent() method.
426
     *
427
     * NOTE: We have bidirectional dependencies between the ContentService and
428
     * the LocationService, so that we cannot use PHPUnit's test dependencies
429
     * here.
430
     *
431
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
432
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
433
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationByRemoteId
434
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
435
     * @group user
436
     */
437
    public function testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately()
438
    {
439
        $this->createContentDraftVersion1();
440
441
        $this->expectException(NotFoundException::class);
442
443
        // The location will not have been created, yet, so this throws an exception
444
        $this->locationService->loadLocationByRemoteId('0123456789abcdef0123456789abcdef');
445
    }
446
447
    /**
448
     * Test for the createContent() method.
449
     *
450
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
451
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
452
     */
453
    public function testCreateContentThrowsInvalidArgumentExceptionWithLocationCreateParameter()
454
    {
455
        $parentLocationId = $this->generateId('location', 56);
456
        // $parentLocationId is a valid location ID
457
458
        $contentTypeService = $this->getRepository()->getContentTypeService();
459
460
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
461
462
        // Configure new locations
463
        $locationCreate1 = $this->locationService->newLocationCreateStruct($parentLocationId);
464
465
        $locationCreate1->priority = 23;
466
        $locationCreate1->hidden = true;
467
        $locationCreate1->remoteId = '0123456789abcdef0123456789aaaaaa';
468
        $locationCreate1->sortField = Location::SORT_FIELD_NODE_ID;
469
        $locationCreate1->sortOrder = Location::SORT_ORDER_DESC;
470
471
        $locationCreate2 = $this->locationService->newLocationCreateStruct($parentLocationId);
472
473
        $locationCreate2->priority = 42;
474
        $locationCreate2->hidden = true;
475
        $locationCreate2->remoteId = '0123456789abcdef0123456789bbbbbb';
476
        $locationCreate2->sortField = Location::SORT_FIELD_NODE_ID;
477
        $locationCreate2->sortOrder = Location::SORT_ORDER_DESC;
478
479
        // Configure new content object
480
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
481
482
        $contentCreate->setField('name', 'A awesome Sindelfingen forum');
483
        $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
484
        $contentCreate->alwaysAvailable = true;
485
486
        // Create new content object under the specified location
487
        $draft = $this->contentService->createContent(
488
            $contentCreate,
489
            [$locationCreate1]
490
        );
491
        $this->contentService->publishVersion($draft->versionInfo);
492
493
        $this->expectException(APIInvalidArgumentException::class);
494
        // Content remoteId already exists,
495
        $this->contentService->createContent(
496
            $contentCreate,
497
            [$locationCreate2]
498
        );
499
    }
500
501
    /**
502
     * Test for the loadContentInfo() method.
503
     *
504
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfo()
505
     * @group user
506
     */
507
    public function testLoadContentInfo()
508
    {
509
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
510
511
        // Load the ContentInfo for "Media" folder
512
        $contentInfo = $this->contentService->loadContentInfo($mediaFolderId);
513
514
        $this->assertInstanceOf(ContentInfo::class, $contentInfo);
515
516
        return $contentInfo;
517
    }
518
519
    /**
520
     * Test for the returned value of the loadContentInfo() method.
521
     *
522
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
523
     * @covers \eZ\Publish\API\Repository\ContentService::loadContentInfo
524
     *
525
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
526
     */
527
    public function testLoadContentInfoSetsExpectedContentInfo(ContentInfo $contentInfo)
528
    {
529
        $this->assertPropertiesCorrectUnsorted(
530
            $this->getExpectedMediaContentInfoProperties(),
531
            $contentInfo
532
        );
533
    }
534
535
    /**
536
     * Test for the loadContentInfo() method.
537
     *
538
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfo()
539
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
540
     */
541
    public function testLoadContentInfoThrowsNotFoundException()
542
    {
543
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
544
545
        $this->expectException(NotFoundException::class);
546
547
        $this->contentService->loadContentInfo($nonExistentContentId);
548
    }
549
550
    /**
551
     * Test for the loadContentInfoList() method.
552
     *
553
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoList()
554
     */
555
    public function testLoadContentInfoList()
556
    {
557
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
558
        $list = $this->contentService->loadContentInfoList([$mediaFolderId]);
559
560
        $this->assertCount(1, $list);
561
        $this->assertEquals([$mediaFolderId], array_keys($list), 'Array key was not content id');
562
        $this->assertInstanceOf(
563
            ContentInfo::class,
564
            $list[$mediaFolderId]
565
        );
566
    }
567
568
    /**
569
     * Test for the loadContentInfoList() method.
570
     *
571
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoList()
572
     * @depends testLoadContentInfoList
573
     */
574
    public function testLoadContentInfoListSkipsNotFoundItems()
575
    {
576
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
577
        $list = $this->contentService->loadContentInfoList([$nonExistentContentId]);
578
579
        $this->assertCount(0, $list);
580
    }
581
582
    /**
583
     * Test for the loadContentInfoByRemoteId() method.
584
     *
585
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoByRemoteId()
586
     */
587
    public function testLoadContentInfoByRemoteId()
588
    {
589
        // Load the ContentInfo for "Media" folder
590
        $contentInfo = $this->contentService->loadContentInfoByRemoteId('faaeb9be3bd98ed09f606fc16d144eca');
591
592
        $this->assertInstanceOf(ContentInfo::class, $contentInfo);
593
594
        return $contentInfo;
595
    }
596
597
    /**
598
     * Test for the returned value of the loadContentInfoByRemoteId() method.
599
     *
600
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfoByRemoteId
601
     * @covers \eZ\Publish\API\Repository\ContentService::loadContentInfoByRemoteId
602
     *
603
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
604
     */
605
    public function testLoadContentInfoByRemoteIdSetsExpectedContentInfo(ContentInfo $contentInfo)
606
    {
607
        $this->assertPropertiesCorrectUnsorted(
608
            [
609
                'id' => 10,
610
                'contentTypeId' => 4,
611
                'name' => 'Anonymous User',
612
                'sectionId' => 2,
613
                'currentVersionNo' => 2,
614
                'published' => true,
615
                'ownerId' => 14,
616
                'modificationDate' => $this->createDateTime(1072180405),
617
                'publishedDate' => $this->createDateTime(1033920665),
618
                'alwaysAvailable' => 1,
619
                'remoteId' => 'faaeb9be3bd98ed09f606fc16d144eca',
620
                'mainLanguageCode' => self::ENG_US,
621
                'mainLocationId' => 45,
622
            ],
623
            $contentInfo
624
        );
625
    }
626
627
    /**
628
     * Test for the loadContentInfoByRemoteId() method.
629
     *
630
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoByRemoteId()
631
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfoByRemoteId
632
     */
633
    public function testLoadContentInfoByRemoteIdThrowsNotFoundException()
634
    {
635
        $this->expectException(NotFoundException::class);
636
637
        $this->contentService->loadContentInfoByRemoteId('abcdefghijklmnopqrstuvwxyz0123456789');
638
    }
639
640
    /**
641
     * Test for the loadVersionInfo() method.
642
     *
643
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo()
644
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
645
     * @group user
646
     */
647
    public function testLoadVersionInfo()
648
    {
649
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
650
        // $mediaFolderId contains the ID of the "Media" folder
651
652
        // Load the ContentInfo for "Media" folder
653
        $contentInfo = $this->contentService->loadContentInfo($mediaFolderId);
654
655
        // Now load the current version info of the "Media" folder
656
        $versionInfo = $this->contentService->loadVersionInfo($contentInfo);
657
658
        $this->assertInstanceOf(
659
            VersionInfo::class,
660
            $versionInfo
661
        );
662
    }
663
664
    /**
665
     * Test for the loadVersionInfoById() method.
666
     *
667
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById()
668
     */
669
    public function testLoadVersionInfoById()
670
    {
671
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
672
        // $mediaFolderId contains the ID of the "Media" folder
673
674
        // Load the VersionInfo for "Media" folder
675
        $versionInfo = $this->contentService->loadVersionInfoById($mediaFolderId);
676
677
        $this->assertInstanceOf(
678
            VersionInfo::class,
679
            $versionInfo
680
        );
681
682
        return $versionInfo;
683
    }
684
685
    /**
686
     * Test for the returned value of the loadVersionInfoById() method.
687
     *
688
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoById
689
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
690
     *
691
     * @param \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo
692
     */
693
    public function testLoadVersionInfoByIdSetsExpectedVersionInfo(VersionInfo $versionInfo)
694
    {
695
        $this->assertPropertiesCorrect(
696
            [
697
                'names' => [
698
                    self::ENG_US => 'Media',
699
                ],
700
                'contentInfo' => new ContentInfo($this->getExpectedMediaContentInfoProperties()),
701
                'id' => 472,
702
                'versionNo' => 1,
703
                'modificationDate' => $this->createDateTime(1060695457),
704
                'creatorId' => 14,
705
                'creationDate' => $this->createDateTime(1060695450),
706
                'status' => VersionInfo::STATUS_PUBLISHED,
707
                'initialLanguageCode' => self::ENG_US,
708
                'languageCodes' => [
709
                    self::ENG_US,
710
                ],
711
            ],
712
            $versionInfo
713
        );
714
        $this->assertTrue($versionInfo->isPublished());
715
        $this->assertFalse($versionInfo->isDraft());
716
        $this->assertFalse($versionInfo->isArchived());
717
    }
718
719
    /**
720
     * Test for the loadVersionInfoById() method.
721
     *
722
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById()
723
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoById
724
     */
725
    public function testLoadVersionInfoByIdThrowsNotFoundException()
726
    {
727
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
728
729
        $this->expectException(NotFoundException::class);
730
731
        $this->contentService->loadVersionInfoById($nonExistentContentId);
732
    }
733
734
    /**
735
     * Test for the loadContentByContentInfo() method.
736
     *
737
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo()
738
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
739
     */
740
    public function testLoadContentByContentInfo()
741
    {
742
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
743
        // $mediaFolderId contains the ID of the "Media" folder
744
745
        // Load the ContentInfo for "Media" folder
746
        $contentInfo = $this->contentService->loadContentInfo($mediaFolderId);
747
748
        // Now load the current content version for the info instance
749
        $content = $this->contentService->loadContentByContentInfo($contentInfo);
750
751
        $this->assertInstanceOf(
752
            Content::class,
753
            $content
754
        );
755
    }
756
757
    /**
758
     * Test for the loadContentByVersionInfo() method.
759
     *
760
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByVersionInfo()
761
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
762
     */
763
    public function testLoadContentByVersionInfo()
764
    {
765
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
766
        // $mediaFolderId contains the ID of the "Media" folder
767
768
        // Load the ContentInfo for "Media" folder
769
        $contentInfo = $this->contentService->loadContentInfo($mediaFolderId);
770
771
        // Load the current VersionInfo
772
        $versionInfo = $this->contentService->loadVersionInfo($contentInfo);
773
774
        // Now load the current content version for the info instance
775
        $content = $this->contentService->loadContentByVersionInfo($versionInfo);
776
777
        $this->assertInstanceOf(
778
            Content::class,
779
            $content
780
        );
781
    }
782
783
    /**
784
     * Test for the loadContent() method.
785
     *
786
     * @see \eZ\Publish\API\Repository\ContentService::loadContent()
787
     * @group user
788
     * @group field-type
789
     */
790
    public function testLoadContent()
791
    {
792
        $mediaFolderId = $this->generateId('object', self::MEDIA_CONTENT_ID);
793
        // $mediaFolderId contains the ID of the "Media" folder
794
795
        // Load the Content for "Media" folder, any language and current version
796
        $content = $this->contentService->loadContent($mediaFolderId);
797
798
        $this->assertInstanceOf(
799
            Content::class,
800
            $content
801
        );
802
    }
803
804
    /**
805
     * Test for the loadContent() method.
806
     *
807
     * @see \eZ\Publish\API\Repository\ContentService::loadContent()
808
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
809
     */
810
    public function testLoadContentThrowsNotFoundException()
811
    {
812
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
813
814
        $this->expectException(NotFoundException::class);
815
816
        $this->contentService->loadContent($nonExistentContentId);
817
    }
818
819
    /**
820
     * Data provider for testLoadContentByRemoteId().
821
     *
822
     * @return array
823
     */
824
    public function contentRemoteIdVersionLanguageProvider()
825
    {
826
        return [
827
            ['f5c88a2209584891056f987fd965b0ba', null, null],
828
            ['f5c88a2209584891056f987fd965b0ba', [self::ENG_US], null],
829
            ['f5c88a2209584891056f987fd965b0ba', null, 1],
830
            ['f5c88a2209584891056f987fd965b0ba', [self::ENG_US], 1],
831
            [self::MEDIA_REMOTE_ID, null, null],
832
            [self::MEDIA_REMOTE_ID, [self::ENG_US], null],
833
            [self::MEDIA_REMOTE_ID, null, 1],
834
            [self::MEDIA_REMOTE_ID, [self::ENG_US], 1],
835
        ];
836
    }
837
838
    /**
839
     * Test for the loadContentByRemoteId() method.
840
     *
841
     * @covers \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId
842
     * @dataProvider contentRemoteIdVersionLanguageProvider
843
     *
844
     * @param string $remoteId
845
     * @param array|null $languages
846
     * @param int $versionNo
847
     */
848
    public function testLoadContentByRemoteId($remoteId, $languages, $versionNo)
849
    {
850
        $content = $this->contentService->loadContentByRemoteId($remoteId, $languages, $versionNo);
851
852
        $this->assertInstanceOf(
853
            Content::class,
854
            $content
855
        );
856
857
        $this->assertEquals($remoteId, $content->contentInfo->remoteId);
858
        if ($languages !== null) {
859
            $this->assertEquals($languages, $content->getVersionInfo()->languageCodes);
860
        }
861
        $this->assertEquals($versionNo ?: 1, $content->getVersionInfo()->versionNo);
862
    }
863
864
    /**
865
     * Test for the loadContentByRemoteId() method.
866
     *
867
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId()
868
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteId
869
     */
870
    public function testLoadContentByRemoteIdThrowsNotFoundException()
871
    {
872
        $this->expectException(NotFoundException::class);
873
874
        // This call will fail with a "NotFoundException", because no content object exists for the given remoteId
875
        $this->contentService->loadContentByRemoteId('a1b1c1d1e1f1a2b2c2d2e2f2a3b3c3d3');
876
    }
877
878
    /**
879
     * Test for the publishVersion() method.
880
     *
881
     * @return \eZ\Publish\API\Repository\Values\Content\Content
882
     *
883
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
884
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
885
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
886
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
887
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
888
     * @group user
889
     * @group field-type
890
     */
891
    public function testPublishVersion()
892
    {
893
        $time = time();
894
        $content = $this->createContentVersion1();
895
896
        $this->assertInstanceOf(Content::class, $content);
897
        $this->assertTrue($content->contentInfo->published);
898
        $this->assertEquals(VersionInfo::STATUS_PUBLISHED, $content->versionInfo->status);
899
        $this->assertGreaterThanOrEqual($time, $content->contentInfo->publishedDate->getTimestamp());
900
        $this->assertGreaterThanOrEqual($time, $content->contentInfo->modificationDate->getTimestamp());
901
        $this->assertTrue($content->versionInfo->isPublished());
902
        $this->assertFalse($content->versionInfo->isDraft());
903
        $this->assertFalse($content->versionInfo->isArchived());
904
905
        return $content;
906
    }
907
908
    /**
909
     * Test for the publishVersion() method.
910
     *
911
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
912
     *
913
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
914
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
915
     */
916
    public function testPublishVersionSetsExpectedContentInfo($content)
917
    {
918
        $this->assertEquals(
919
            [
920
                $content->id,
921
                true,
922
                1,
923
                'abcdef0123456789abcdef0123456789',
924
                self::ENG_US,
925
                $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
926
                true,
927
            ],
928
            [
929
                $content->contentInfo->id,
930
                $content->contentInfo->alwaysAvailable,
931
                $content->contentInfo->currentVersionNo,
932
                $content->contentInfo->remoteId,
933
                $content->contentInfo->mainLanguageCode,
934
                $content->contentInfo->ownerId,
935
                $content->contentInfo->published,
936
            ]
937
        );
938
939
        $this->assertNotNull($content->contentInfo->mainLocationId);
940
        $date = new \DateTime('1984/01/01');
941
        $this->assertGreaterThan(
942
            $date->getTimestamp(),
943
            $content->contentInfo->publishedDate->getTimestamp()
944
        );
945
    }
946
947
    /**
948
     * Test for the publishVersion() method.
949
     *
950
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
951
     *
952
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
953
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
954
     */
955
    public function testPublishVersionSetsExpectedVersionInfo($content)
956
    {
957
        $this->assertEquals(
958
            [
959
                $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
960
                self::ENG_US,
961
                VersionInfo::STATUS_PUBLISHED,
962
                1,
963
            ],
964
            [
965
                $content->getVersionInfo()->creatorId,
966
                $content->getVersionInfo()->initialLanguageCode,
967
                $content->getVersionInfo()->status,
968
                $content->getVersionInfo()->versionNo,
969
            ]
970
        );
971
972
        $date = new \DateTime('1984/01/01');
973
        $this->assertGreaterThan(
974
            $date->getTimestamp(),
975
            $content->getVersionInfo()->modificationDate->getTimestamp()
976
        );
977
978
        $this->assertNotNull($content->getVersionInfo()->modificationDate);
979
        $this->assertTrue($content->getVersionInfo()->isPublished());
980
        $this->assertFalse($content->getVersionInfo()->isDraft());
981
        $this->assertFalse($content->getVersionInfo()->isArchived());
982
    }
983
984
    /**
985
     * Test for the publishVersion() method.
986
     *
987
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
988
     *
989
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
990
     * @depends testPublishVersion
991
     */
992
    public function testPublishVersionSetsExpectedContentType($content)
993
    {
994
        $contentType = $content->getContentType();
995
996
        $this->assertEquals(
997
            [
998
                $contentType->id,
999
                // won't be a match as it's set to true in createContentDraftVersion1()
1000
                //$contentType->defaultAlwaysAvailable,
1001
                //$contentType->defaultSortField,
1002
                //$contentType->defaultSortOrder,
1003
            ],
1004
            [
1005
                $content->contentInfo->contentTypeId,
1006
                //$content->contentInfo->alwaysAvailable,
1007
                //$location->sortField,
1008
                //$location->sortOrder,
1009
            ]
1010
        );
1011
    }
1012
1013
    /**
1014
     * Test for the publishVersion() method.
1015
     *
1016
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1017
     *
1018
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1019
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
1020
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1021
     */
1022
    public function testPublishVersionCreatesLocationsDefinedOnCreate()
1023
    {
1024
        $content = $this->createContentVersion1();
1025
1026
        $location = $this->locationService->loadLocationByRemoteId(
1027
            '0123456789abcdef0123456789abcdef'
1028
        );
1029
1030
        $this->assertEquals(
1031
            $location->getContentInfo(),
1032
            $content->getVersionInfo()->getContentInfo()
1033
        );
1034
1035
        return [$content, $location];
1036
    }
1037
1038
    /**
1039
     * Test for the publishVersion() method.
1040
     *
1041
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1042
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionCreatesLocationsDefinedOnCreate
1043
     */
1044
    public function testCreateContentWithLocationCreateParameterCreatesExpectedLocation(array $testData)
1045
    {
1046
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $content */
1047
        /** @var \eZ\Publish\API\Repository\Values\Content\Location $location */
1048
        list($content, $location) = $testData;
1049
1050
        $parentLocationId = $this->generateId('location', 56);
1051
        $parentLocation = $this->getRepository()->getLocationService()->loadLocation($parentLocationId);
1052
        $mainLocationId = $content->getVersionInfo()->getContentInfo()->mainLocationId;
1053
1054
        $this->assertPropertiesCorrect(
1055
            [
1056
                'id' => $mainLocationId,
1057
                'priority' => 23,
1058
                'hidden' => true,
1059
                'invisible' => true,
1060
                'remoteId' => '0123456789abcdef0123456789abcdef',
1061
                'parentLocationId' => $parentLocationId,
1062
                'pathString' => $parentLocation->pathString . $mainLocationId . '/',
1063
                'depth' => $parentLocation->depth + 1,
1064
                'sortField' => Location::SORT_FIELD_NODE_ID,
1065
                'sortOrder' => Location::SORT_ORDER_DESC,
1066
            ],
1067
            $location
1068
        );
1069
    }
1070
1071
    /**
1072
     * Test for the publishVersion() method.
1073
     *
1074
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1075
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1076
     */
1077
    public function testPublishVersionThrowsBadStateException()
1078
    {
1079
        $draft = $this->createContentDraftVersion1();
1080
1081
        // Publish the content draft
1082
        $this->contentService->publishVersion($draft->getVersionInfo());
1083
1084
        $this->expectException(BadStateException::class);
1085
1086
        // This call will fail with a "BadStateException", because the version is already published.
1087
        $this->contentService->publishVersion($draft->getVersionInfo());
1088
    }
1089
1090
    /**
1091
     * Test that publishVersion() does not affect publishedDate (assuming previous version exists).
1092
     *
1093
     * @covers \eZ\Publish\API\Repository\ContentService::publishVersion
1094
     */
1095
    public function testPublishVersionDoesNotChangePublishedDate()
1096
    {
1097
        $publishedContent = $this->createContentVersion1();
1098
1099
        // force timestamps to differ
1100
        sleep(1);
1101
1102
        $contentDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
1103
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1104
        $contentUpdateStruct->setField('name', 'New name');
1105
        $contentDraft = $this->contentService->updateContent($contentDraft->versionInfo, $contentUpdateStruct);
1106
        $republishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
1107
1108
        $this->assertEquals(
1109
            $publishedContent->contentInfo->publishedDate->getTimestamp(),
1110
            $republishedContent->contentInfo->publishedDate->getTimestamp()
1111
        );
1112
        $this->assertGreaterThan(
1113
            $publishedContent->contentInfo->modificationDate->getTimestamp(),
1114
            $republishedContent->contentInfo->modificationDate->getTimestamp()
1115
        );
1116
    }
1117
1118
    /**
1119
     * Test for the createContentDraft() method.
1120
     *
1121
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1122
     *
1123
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1124
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1125
     * @group user
1126
     */
1127
    public function testCreateContentDraft()
1128
    {
1129
        $content = $this->createContentVersion1();
1130
1131
        // Now we create a new draft from the published content
1132
        $draftedContent = $this->contentService->createContentDraft($content->contentInfo);
1133
1134
        $this->assertInstanceOf(
1135
            Content::class,
1136
            $draftedContent
1137
        );
1138
1139
        return $draftedContent;
1140
    }
1141
1142
    /**
1143
     * Test for the createContentDraft() method with given language for new draft.
1144
     *
1145
     * @covers \eZ\Publish\API\Repository\ContentService::createContentDraft
1146
     */
1147
    public function testCreateContentDraftInOtherLanguage()
1148
    {
1149
        $content = $this->createContentVersion1();
1150
1151
        $language = $this->getRepository()->getContentLanguageService()->loadLanguage('eng-GB');
1152
1153
        // Now we create a new draft from the published content
1154
        $draftedContent = $this->contentService->createContentDraft(
1155
            $content->contentInfo,
1156
            null,
1157
            null,
1158
            $language
1159
        );
1160
1161
        $this->assertEquals('eng-US', $content->versionInfo->initialLanguageCode);
1162
        $this->assertEquals('eng-GB', $draftedContent->versionInfo->initialLanguageCode);
1163
    }
1164
1165
    /**
1166
     * Test for the createContentDraft() method.
1167
     *
1168
     * Test that editor has access to edit own draft.
1169
     * Note: Editors have access to version_read, which is needed to load content drafts.
1170
     *
1171
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1172
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1173
     * @group user
1174
     */
1175
    public function testCreateContentDraftAndLoadAccess()
1176
    {
1177
        $user = $this->createUserVersion1();
1178
1179
        // Set new editor as user
1180
        $this->permissionResolver->setCurrentUserReference($user);
1181
1182
        // Create draft
1183
        $draft = $this->createContentDraftVersion1(2, 'folder');
1184
1185
        // Try to load the draft
1186
        $loadedDraft = $this->contentService->loadContent($draft->id);
1187
1188
        $this->assertEquals($draft->id, $loadedDraft->id);
1189
    }
1190
1191
    /**
1192
     * Test for the createContentDraft() method.
1193
     *
1194
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1195
     *
1196
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1197
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1198
     */
1199
    public function testCreateContentDraftSetsExpectedProperties($draft)
1200
    {
1201
        $this->assertEquals(
1202
            [
1203
                'fieldCount' => 2,
1204
                'relationCount' => 0,
1205
            ],
1206
            [
1207
                'fieldCount' => count($draft->getFields()),
1208
                'relationCount' => count($this->getRepository()->getContentService()->loadRelations($draft->getVersionInfo())),
1209
            ]
1210
        );
1211
    }
1212
1213
    /**
1214
     * Test for the createContentDraft() method.
1215
     *
1216
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1217
     *
1218
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1219
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1220
     */
1221
    public function testCreateContentDraftSetsContentInfo($draft)
1222
    {
1223
        $contentInfo = $draft->contentInfo;
1224
1225
        $this->assertEquals(
1226
            [
1227
                $draft->id,
1228
                true,
1229
                1,
1230
                self::ENG_US,
1231
                $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
1232
                'abcdef0123456789abcdef0123456789',
1233
                1,
1234
            ],
1235
            [
1236
                $contentInfo->id,
1237
                $contentInfo->alwaysAvailable,
1238
                $contentInfo->currentVersionNo,
1239
                $contentInfo->mainLanguageCode,
1240
                $contentInfo->ownerId,
1241
                $contentInfo->remoteId,
1242
                $contentInfo->sectionId,
1243
            ]
1244
        );
1245
    }
1246
1247
    /**
1248
     * Test for the createContentDraft() method.
1249
     *
1250
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1251
     *
1252
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1253
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1254
     */
1255
    public function testCreateContentDraftSetsVersionInfo($draft)
1256
    {
1257
        $versionInfo = $draft->getVersionInfo();
1258
1259
        $this->assertEquals(
1260
            [
1261
                'creatorId' => $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
1262
                'initialLanguageCode' => self::ENG_US,
1263
                'languageCodes' => [0 => self::ENG_US],
1264
                'status' => VersionInfo::STATUS_DRAFT,
1265
                'versionNo' => 2,
1266
            ],
1267
            [
1268
                'creatorId' => $versionInfo->creatorId,
1269
                'initialLanguageCode' => $versionInfo->initialLanguageCode,
1270
                'languageCodes' => $versionInfo->languageCodes,
1271
                'status' => $versionInfo->status,
1272
                'versionNo' => $versionInfo->versionNo,
1273
            ]
1274
        );
1275
        $this->assertTrue($versionInfo->isDraft());
1276
        $this->assertFalse($versionInfo->isPublished());
1277
        $this->assertFalse($versionInfo->isArchived());
1278
    }
1279
1280
    /**
1281
     * Test for the createContentDraft() method.
1282
     *
1283
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1284
     *
1285
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1286
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1287
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
1288
     */
1289
    public function testCreateContentDraftLoadVersionInfoStillLoadsPublishedVersion($draft)
0 ignored issues
show
Unused Code introduced by
The parameter $draft 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...
1290
    {
1291
        $content = $this->createContentVersion1();
1292
1293
        // Now we create a new draft from the published content
1294
        $this->contentService->createContentDraft($content->contentInfo);
1295
1296
        // This call will still load the published version
1297
        $versionInfoPublished = $this->contentService->loadVersionInfo($content->contentInfo);
1298
1299
        $this->assertEquals(1, $versionInfoPublished->versionNo);
1300
    }
1301
1302
    /**
1303
     * Test for the createContentDraft() method.
1304
     *
1305
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1306
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
1307
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1308
     */
1309
    public function testCreateContentDraftLoadContentStillLoadsPublishedVersion()
1310
    {
1311
        $content = $this->createContentVersion1();
1312
1313
        // Now we create a new draft from the published content
1314
        $this->contentService->createContentDraft($content->contentInfo);
1315
1316
        // This call will still load the published content version
1317
        $contentPublished = $this->contentService->loadContent($content->id);
1318
1319
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1320
    }
1321
1322
    /**
1323
     * Test for the createContentDraft() method.
1324
     *
1325
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1326
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteId
1327
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1328
     */
1329
    public function testCreateContentDraftLoadContentByRemoteIdStillLoadsPublishedVersion()
1330
    {
1331
        $content = $this->createContentVersion1();
1332
1333
        // Now we create a new draft from the published content
1334
        $this->contentService->createContentDraft($content->contentInfo);
1335
1336
        // This call will still load the published content version
1337
        $contentPublished = $this->contentService->loadContentByRemoteId('abcdef0123456789abcdef0123456789');
1338
1339
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1340
    }
1341
1342
    /**
1343
     * Test for the createContentDraft() method.
1344
     *
1345
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1346
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
1347
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1348
     */
1349
    public function testCreateContentDraftLoadContentByContentInfoStillLoadsPublishedVersion()
1350
    {
1351
        $content = $this->createContentVersion1();
1352
1353
        // Now we create a new draft from the published content
1354
        $this->contentService->createContentDraft($content->contentInfo);
1355
1356
        // This call will still load the published content version
1357
        $contentPublished = $this->contentService->loadContentByContentInfo($content->contentInfo);
1358
1359
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1360
    }
1361
1362
    /**
1363
     * Test for the newContentUpdateStruct() method.
1364
     *
1365
     * @covers \eZ\Publish\API\Repository\ContentService::newContentUpdateStruct
1366
     * @group user
1367
     */
1368
    public function testNewContentUpdateStruct()
1369
    {
1370
        $updateStruct = $this->contentService->newContentUpdateStruct();
1371
1372
        $this->assertInstanceOf(
1373
            ContentUpdateStruct::class,
1374
            $updateStruct
1375
        );
1376
1377
        $this->assertPropertiesCorrect(
1378
            [
1379
                'initialLanguageCode' => null,
1380
                'fields' => [],
1381
            ],
1382
            $updateStruct
1383
        );
1384
    }
1385
1386
    /**
1387
     * Test for the updateContent() method.
1388
     *
1389
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1390
     *
1391
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1392
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentUpdateStruct
1393
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1394
     * @group user
1395
     * @group field-type
1396
     */
1397
    public function testUpdateContent()
1398
    {
1399
        $draftVersion2 = $this->createUpdatedDraftVersion2();
1400
1401
        $this->assertInstanceOf(
1402
            Content::class,
1403
            $draftVersion2
1404
        );
1405
1406
        $this->assertEquals(
1407
            $this->generateId('user', 10),
1408
            $draftVersion2->versionInfo->creatorId,
1409
            'creatorId is not properly set on new Version'
1410
        );
1411
1412
        return $draftVersion2;
1413
    }
1414
1415
    /**
1416
     * Test for the updateContent_WithDifferentUser() method.
1417
     *
1418
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1419
     *
1420
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1421
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentUpdateStruct
1422
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1423
     * @group user
1424
     * @group field-type
1425
     */
1426
    public function testUpdateContentWithDifferentUser()
1427
    {
1428
        $arrayWithDraftVersion2 = $this->createUpdatedDraftVersion2NotAdmin();
1429
1430
        $this->assertInstanceOf(
1431
            Content::class,
1432
            $arrayWithDraftVersion2[0]
1433
        );
1434
1435
        $this->assertEquals(
1436
            $this->generateId('user', $arrayWithDraftVersion2[1]),
1437
            $arrayWithDraftVersion2[0]->versionInfo->creatorId,
1438
            'creatorId is not properly set on new Version'
1439
        );
1440
1441
        return $arrayWithDraftVersion2[0];
1442
    }
1443
1444
    /**
1445
     * Test for the updateContent() method.
1446
     *
1447
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1448
     *
1449
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1450
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1451
     */
1452
    public function testUpdateContentSetsExpectedFields($content)
1453
    {
1454
        $actual = $this->normalizeFields($content->getFields());
1455
1456
        $expected = [
1457
            new Field(
1458
                [
1459
                    'id' => 0,
1460
                    'value' => true,
1461
                    'languageCode' => self::ENG_GB,
1462
                    'fieldDefIdentifier' => 'description',
1463
                    'fieldTypeIdentifier' => 'ezrichtext',
1464
                ]
1465
            ),
1466
            new Field(
1467
                [
1468
                    'id' => 0,
1469
                    'value' => true,
1470
                    'languageCode' => self::ENG_US,
1471
                    'fieldDefIdentifier' => 'description',
1472
                    'fieldTypeIdentifier' => 'ezrichtext',
1473
                ]
1474
            ),
1475
            new Field(
1476
                [
1477
                    'id' => 0,
1478
                    'value' => true,
1479
                    'languageCode' => self::ENG_GB,
1480
                    'fieldDefIdentifier' => 'name',
1481
                    'fieldTypeIdentifier' => 'ezstring',
1482
                ]
1483
            ),
1484
            new Field(
1485
                [
1486
                    'id' => 0,
1487
                    'value' => true,
1488
                    'languageCode' => self::ENG_US,
1489
                    'fieldDefIdentifier' => 'name',
1490
                    'fieldTypeIdentifier' => 'ezstring',
1491
                ]
1492
            ),
1493
        ];
1494
1495
        $this->assertEquals($expected, $actual);
1496
    }
1497
1498
    /**
1499
     * Test for the updateContent() method.
1500
     *
1501
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1502
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1503
     */
1504
    public function testUpdateContentThrowsBadStateException()
1505
    {
1506
        $content = $this->createContentVersion1();
1507
1508
        // Now create an update struct and modify some fields
1509
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1510
        $contentUpdateStruct->setField('title', 'An awesome² story about ezp.');
1511
        $contentUpdateStruct->setField('title', 'An awesome²³ story about ezp.', self::ENG_GB);
1512
1513
        $contentUpdateStruct->initialLanguageCode = self::ENG_US;
1514
1515
        $this->expectException(BadStateException::class);
1516
1517
        // This call will fail with a "BadStateException", because $publishedContent is not a draft.
1518
        $this->contentService->updateContent(
1519
            $content->getVersionInfo(),
1520
            $contentUpdateStruct
1521
        );
1522
    }
1523
1524
    /**
1525
     * Test for the updateContent() method.
1526
     *
1527
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1528
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1529
     */
1530
    public function testUpdateContentThrowsInvalidArgumentExceptionWhenFieldTypeDoesNotAccept()
1531
    {
1532
        $draft = $this->createContentDraftVersion1();
1533
1534
        // Now create an update struct and modify some fields
1535
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1536
        // The name field does not accept a stdClass object as its input
1537
        $contentUpdateStruct->setField('name', new \stdClass(), self::ENG_US);
1538
1539
        $this->expectException(APIInvalidArgumentException::class);
1540
        // is not accepted
1541
        $this->contentService->updateContent(
1542
            $draft->getVersionInfo(),
1543
            $contentUpdateStruct
1544
        );
1545
    }
1546
1547
    /**
1548
     * Test for the updateContent() method.
1549
     *
1550
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1551
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1552
     */
1553
    public function testUpdateContentWhenMandatoryFieldIsEmpty()
1554
    {
1555
        $draft = $this->createContentDraftVersion1();
1556
1557
        // Now create an update struct and set a mandatory field to null
1558
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1559
        $contentUpdateStruct->setField('name', null);
1560
1561
        // Don't set this, then the above call without languageCode will fail
1562
        $contentUpdateStruct->initialLanguageCode = self::ENG_US;
1563
1564
        $this->expectException(ContentFieldValidationException::class);
1565
1566
        // This call will fail with a "ContentFieldValidationException", because the mandatory "name" field is empty.
1567
        $this->contentService->updateContent(
1568
            $draft->getVersionInfo(),
1569
            $contentUpdateStruct
1570
        );
1571
    }
1572
1573
    /**
1574
     * Test for the updateContent() method.
1575
     *
1576
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1577
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1578
     */
1579
    public function testUpdateContentThrowsContentFieldValidationException()
1580
    {
1581
        $contentTypeService = $this->getRepository()->getContentTypeService();
1582
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1583
1584
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
1585
        $contentCreate->setField('name', 'An awesome Sidelfingen folder');
1586
1587
        $draft = $this->contentService->createContent($contentCreate);
1588
1589
        $contentUpdate = $this->contentService->newContentUpdateStruct();
1590
        // Violates string length constraint
1591
        $contentUpdate->setField('short_name', str_repeat('a', 200), self::ENG_US);
1592
1593
        $this->expectException(ContentFieldValidationException::class);
1594
1595
        // Throws ContentFieldValidationException because the string length validation of the field "short_name" fails
1596
        $this->contentService->updateContent($draft->getVersionInfo(), $contentUpdate);
1597
    }
1598
1599
    /**
1600
     * Test for the updateContent() method.
1601
     *
1602
     * @covers \eZ\Publish\API\Repository\ContentService::updateContent()
1603
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1604
     */
1605
    public function testUpdateContentValidatorIgnoresRequiredFieldsOfNotUpdatedLanguages()
1606
    {
1607
        $contentTypeService = $this->getRepository()->getContentTypeService();
1608
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1609
1610
        // Create multilangual content
1611
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
1612
        $contentCreate->setField('name', 'An awesome Sidelfingen folder', self::ENG_US);
1613
        $contentCreate->setField('name', 'An awesome Sidelfingen folder', self::ENG_GB);
1614
1615
        $contentDraft = $this->contentService->createContent($contentCreate);
1616
1617
        // 2. Update content type definition
1618
        $contentTypeDraft = $contentTypeService->createContentTypeDraft($contentType);
1619
1620
        $fieldDefinition = $contentType->getFieldDefinition('description');
1621
        $fieldDefinitionUpdate = $contentTypeService->newFieldDefinitionUpdateStruct();
1622
        $fieldDefinitionUpdate->identifier = 'description';
1623
        $fieldDefinitionUpdate->isRequired = true;
1624
1625
        $contentTypeService->updateFieldDefinition(
1626
            $contentTypeDraft,
1627
            $fieldDefinition,
1628
            $fieldDefinitionUpdate
1629
        );
1630
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1631
1632
        // 3. Update only eng-US translation
1633
        $description = new DOMDocument();
1634
        $description->loadXML(<<<XML
1635
<?xml version="1.0" encoding="UTF-8"?>
1636
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
1637
    <para>Lorem ipsum dolor</para>
1638
</section>
1639
XML
1640
        );
1641
1642
        $contentUpdate = $this->contentService->newContentUpdateStruct();
1643
        $contentUpdate->setField('name', 'An awesome Sidelfingen folder (updated)', self::ENG_US);
1644
        $contentUpdate->setField('description', $description);
1645
1646
        $this->contentService->updateContent($contentDraft->getVersionInfo(), $contentUpdate);
1647
    }
1648
1649
    /**
1650
     * Test for the updateContent() method.
1651
     *
1652
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1653
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1654
     */
1655
    public function testUpdateContentWithNotUpdatingMandatoryField()
1656
    {
1657
        $draft = $this->createContentDraftVersion1();
1658
1659
        // Now create an update struct which does not overwrite mandatory
1660
        // fields
1661
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1662
        $contentUpdateStruct->setField(
1663
            'description',
1664
            '<?xml version="1.0" encoding="UTF-8"?><section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>'
1665
        );
1666
1667
        // Don't set this, then the above call without languageCode will fail
1668
        $contentUpdateStruct->initialLanguageCode = self::ENG_US;
1669
1670
        // This will only update the "description" field in the "eng-US" language
1671
        $updatedDraft = $this->contentService->updateContent(
1672
            $draft->getVersionInfo(),
1673
            $contentUpdateStruct
1674
        );
1675
1676
        foreach ($updatedDraft->getFields() as $field) {
1677
            if ($field->languageCode === self::ENG_US && $field->fieldDefIdentifier === 'name' && $field->value !== null) {
1678
                // Found field
1679
                return;
1680
            }
1681
        }
1682
        $this->fail(
1683
            'Field with identifier "name" in language "eng-US" could not be found or has empty value.'
1684
        );
1685
    }
1686
1687
    /**
1688
     * Test for the createContentDraft() method.
1689
     *
1690
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft($contentInfo, $versionInfo)
1691
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1692
     */
1693
    public function testCreateContentDraftWithSecondParameter()
1694
    {
1695
        $contentVersion2 = $this->createContentVersion2();
1696
1697
        // Now we create a new draft from the initial version
1698
        $draftedContentReloaded = $this->contentService->createContentDraft(
1699
            $contentVersion2->contentInfo,
1700
            $contentVersion2->getVersionInfo()
1701
        );
1702
1703
        $this->assertEquals(3, $draftedContentReloaded->getVersionInfo()->versionNo);
1704
    }
1705
1706
    /**
1707
     * Test for the createContentDraft() method with third parameter.
1708
     *
1709
     * @covers \eZ\Publish\Core\Repository\ContentService::createContentDraft
1710
     */
1711
    public function testCreateContentDraftWithThirdParameter()
1712
    {
1713
        $content = $this->contentService->loadContent(4);
1714
        $user = $this->createUserVersion1();
1715
1716
        $draftContent = $this->contentService->createContentDraft(
1717
            $content->contentInfo,
1718
            $content->getVersionInfo(),
1719
            $user
1720
        );
1721
1722
        $this->assertInstanceOf(
1723
            Content::class,
1724
            $draftContent
1725
        );
1726
    }
1727
1728
    /**
1729
     * Test for the publishVersion() method.
1730
     *
1731
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1732
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1733
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1734
     */
1735
    public function testPublishVersionFromContentDraft()
1736
    {
1737
        $contentVersion2 = $this->createContentVersion2();
1738
1739
        $versionInfo = $this->contentService->loadVersionInfo($contentVersion2->contentInfo);
1740
1741
        $this->assertEquals(
1742
            [
1743
                'status' => VersionInfo::STATUS_PUBLISHED,
1744
                'versionNo' => 2,
1745
            ],
1746
            [
1747
                'status' => $versionInfo->status,
1748
                'versionNo' => $versionInfo->versionNo,
1749
            ]
1750
        );
1751
        $this->assertTrue($versionInfo->isPublished());
1752
        $this->assertFalse($versionInfo->isDraft());
1753
        $this->assertFalse($versionInfo->isArchived());
1754
    }
1755
1756
    /**
1757
     * Test for the publishVersion() method.
1758
     *
1759
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1760
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1761
     */
1762
    public function testPublishVersionFromContentDraftArchivesOldVersion()
1763
    {
1764
        $contentVersion2 = $this->createContentVersion2();
1765
1766
        $versionInfo = $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 1);
1767
1768
        $this->assertEquals(
1769
            [
1770
                'status' => VersionInfo::STATUS_ARCHIVED,
1771
                'versionNo' => 1,
1772
            ],
1773
            [
1774
                'status' => $versionInfo->status,
1775
                'versionNo' => $versionInfo->versionNo,
1776
            ]
1777
        );
1778
        $this->assertTrue($versionInfo->isArchived());
1779
        $this->assertFalse($versionInfo->isDraft());
1780
        $this->assertFalse($versionInfo->isPublished());
1781
    }
1782
1783
    /**
1784
     * Test for the publishVersion() method.
1785
     *
1786
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1787
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1788
     */
1789
    public function testPublishVersionFromContentDraftUpdatesContentInfoCurrentVersion()
1790
    {
1791
        $contentVersion2 = $this->createContentVersion2();
1792
1793
        $this->assertEquals(2, $contentVersion2->contentInfo->currentVersionNo);
1794
    }
1795
1796
    /**
1797
     * Test for the publishVersion() method.
1798
     *
1799
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1800
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1801
     */
1802
    public function testPublishVersionFromOldContentDraftArchivesNewerVersionNo()
1803
    {
1804
        $content = $this->createContentVersion1();
1805
1806
        // Create a new draft with versionNo = 2
1807
        $draftedContentVersion2 = $this->contentService->createContentDraft($content->contentInfo);
1808
1809
        // Create another new draft with versionNo = 3
1810
        $draftedContentVersion3 = $this->contentService->createContentDraft($content->contentInfo);
1811
1812
        // Publish draft with versionNo = 3
1813
        $this->contentService->publishVersion($draftedContentVersion3->getVersionInfo());
1814
1815
        // Publish the first draft with versionNo = 2
1816
        // currentVersionNo is now 2, versionNo 3 will be archived
1817
        $publishedDraft = $this->contentService->publishVersion($draftedContentVersion2->getVersionInfo());
1818
1819
        $this->assertEquals(2, $publishedDraft->contentInfo->currentVersionNo);
1820
    }
1821
1822
    /**
1823
     * Test for the publishVersion() method, and that it creates limited archives.
1824
     *
1825
     * @todo Adapt this when per content type archive limited is added on repository Content Type model.
1826
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1827
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1828
     */
1829
    public function testPublishVersionNotCreatingUnlimitedArchives()
1830
    {
1831
        $content = $this->createContentVersion1();
1832
1833
        // load first to make sure list gets updated also (cache)
1834
        $versionInfoList = $this->contentService->loadVersions($content->contentInfo);
1835
        $this->assertEquals(1, count($versionInfoList));
1836
        $this->assertEquals(1, $versionInfoList[0]->versionNo);
1837
1838
        // Create a new draft with versionNo = 2
1839
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1840
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1841
1842
        // Create a new draft with versionNo = 3
1843
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1844
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1845
1846
        // Create a new draft with versionNo = 4
1847
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1848
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1849
1850
        // Create a new draft with versionNo = 5
1851
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1852
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1853
1854
        // Create a new draft with versionNo = 6
1855
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1856
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1857
1858
        // Create a new draft with versionNo = 7
1859
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1860
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1861
1862
        $versionInfoList = $this->contentService->loadVersions($content->contentInfo);
1863
1864
        $this->assertEquals(6, count($versionInfoList));
1865
        $this->assertEquals(2, $versionInfoList[0]->versionNo);
1866
        $this->assertEquals(7, $versionInfoList[5]->versionNo);
1867
1868
        $this->assertEquals(
1869
            [
1870
                VersionInfo::STATUS_ARCHIVED,
1871
                VersionInfo::STATUS_ARCHIVED,
1872
                VersionInfo::STATUS_ARCHIVED,
1873
                VersionInfo::STATUS_ARCHIVED,
1874
                VersionInfo::STATUS_ARCHIVED,
1875
                VersionInfo::STATUS_PUBLISHED,
1876
            ],
1877
            [
1878
                $versionInfoList[0]->status,
1879
                $versionInfoList[1]->status,
1880
                $versionInfoList[2]->status,
1881
                $versionInfoList[3]->status,
1882
                $versionInfoList[4]->status,
1883
                $versionInfoList[5]->status,
1884
            ]
1885
        );
1886
    }
1887
1888
    /**
1889
     * Test for the newContentMetadataUpdateStruct() method.
1890
     *
1891
     * @covers \eZ\Publish\API\Repository\ContentService::newContentMetadataUpdateStruct
1892
     * @group user
1893
     */
1894
    public function testNewContentMetadataUpdateStruct()
1895
    {
1896
        // Creates a new metadata update struct
1897
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
1898
1899
        foreach ($metadataUpdate as $propertyName => $propertyValue) {
0 ignored issues
show
Bug introduced by
The expression $metadataUpdate of type object<eZ\Publish\API\Re...ntMetadataUpdateStruct> is not traversable.
Loading history...
1900
            $this->assertNull($propertyValue, "Property '{$propertyName}' initial value should be null'");
1901
        }
1902
1903
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
1904
        $metadataUpdate->mainLanguageCode = self::ENG_GB;
1905
        $metadataUpdate->alwaysAvailable = false;
1906
1907
        $this->assertInstanceOf(
1908
            ContentMetadataUpdateStruct::class,
1909
            $metadataUpdate
1910
        );
1911
    }
1912
1913
    /**
1914
     * Test for the updateContentMetadata() method.
1915
     *
1916
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1917
     *
1918
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1919
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1920
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentMetadataUpdateStruct
1921
     * @group user
1922
     */
1923
    public function testUpdateContentMetadata()
1924
    {
1925
        $content = $this->createContentVersion1();
1926
1927
        // Creates a metadata update struct
1928
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
1929
1930
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
1931
        $metadataUpdate->mainLanguageCode = self::ENG_GB;
1932
        $metadataUpdate->alwaysAvailable = false;
1933
        $metadataUpdate->publishedDate = $this->createDateTime(441759600); // 1984/01/01
1934
        $metadataUpdate->modificationDate = $this->createDateTime(441759600); // 1984/01/01
1935
1936
        // Update the metadata of the published content object
1937
        $content = $this->contentService->updateContentMetadata(
1938
            $content->contentInfo,
1939
            $metadataUpdate
1940
        );
1941
1942
        $this->assertInstanceOf(
1943
            Content::class,
1944
            $content
1945
        );
1946
1947
        return $content;
1948
    }
1949
1950
    /**
1951
     * Test for the updateContentMetadata() method.
1952
     *
1953
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1954
     *
1955
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1956
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1957
     */
1958
    public function testUpdateContentMetadataSetsExpectedProperties($content)
1959
    {
1960
        $contentInfo = $content->contentInfo;
1961
1962
        $this->assertEquals(
1963
            [
1964
                'remoteId' => 'aaaabbbbccccddddeeeeffff11112222',
1965
                'sectionId' => $this->generateId('section', 1),
1966
                'alwaysAvailable' => false,
1967
                'currentVersionNo' => 1,
1968
                'mainLanguageCode' => self::ENG_GB,
1969
                'modificationDate' => $this->createDateTime(441759600),
1970
                'ownerId' => $this->getRepository()->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

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...
1971
                'published' => true,
1972
                'publishedDate' => $this->createDateTime(441759600),
1973
            ],
1974
            [
1975
                'remoteId' => $contentInfo->remoteId,
1976
                'sectionId' => $contentInfo->sectionId,
1977
                'alwaysAvailable' => $contentInfo->alwaysAvailable,
1978
                'currentVersionNo' => $contentInfo->currentVersionNo,
1979
                'mainLanguageCode' => $contentInfo->mainLanguageCode,
1980
                'modificationDate' => $contentInfo->modificationDate,
1981
                'ownerId' => $contentInfo->ownerId,
1982
                'published' => $contentInfo->published,
1983
                'publishedDate' => $contentInfo->publishedDate,
1984
            ]
1985
        );
1986
    }
1987
1988
    /**
1989
     * Test for the updateContentMetadata() method.
1990
     *
1991
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1992
     *
1993
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1994
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1995
     */
1996
    public function testUpdateContentMetadataNotUpdatesContentVersion($content)
1997
    {
1998
        $this->assertEquals(1, $content->getVersionInfo()->versionNo);
1999
    }
2000
2001
    /**
2002
     * Test for the updateContentMetadata() method.
2003
     *
2004
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2005
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
2006
     */
2007
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnDuplicateRemoteId()
2008
    {
2009
        $content = $this->createContentVersion1();
2010
2011
        // Creates a metadata update struct
2012
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
2013
        $metadataUpdate->remoteId = self::MEDIA_REMOTE_ID;
2014
2015
        $this->expectException(APIInvalidArgumentException::class);
2016
        // specified remoteId is already used by the "Media" page.
2017
        $this->contentService->updateContentMetadata(
2018
            $content->contentInfo,
2019
            $metadataUpdate
2020
        );
2021
    }
2022
2023
    /**
2024
     * Test for the updateContentMetadata() method.
2025
     *
2026
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContentMetadata
2027
     */
2028
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnNoMetadataPropertiesSet()
2029
    {
2030
        $contentInfo = $this->contentService->loadContentInfo(4);
2031
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
2032
2033
        $this->expectException(APIInvalidArgumentException::class);
2034
        $this->contentService->updateContentMetadata($contentInfo, $contentMetadataUpdateStruct);
2035
    }
2036
2037
    /**
2038
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata
2039
     *
2040
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2041
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2042
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2043
     */
2044
    public function testUpdateContentAlwaysAvailable(): void
2045
    {
2046
        $repository = $this->getRepository();
2047
        $contentService = $repository->getContentService();
2048
2049
        $folder = $this->createFolder(['eng-GB' => 'Folder'], 2);
2050
2051
        $contentMetadataUpdate = $contentService->newContentMetadataUpdateStruct();
2052
        $contentMetadataUpdate->alwaysAvailable = !$folder->contentInfo->alwaysAvailable;
2053
        $contentService->updateContentMetadata($folder->contentInfo, $contentMetadataUpdate);
2054
2055
        $reloadedFolder = $contentService->loadContent($folder->id);
2056
        self::assertEquals(
2057
            $contentMetadataUpdate->alwaysAvailable,
2058
            $reloadedFolder->contentInfo->alwaysAvailable
2059
        );
2060
    }
2061
2062
    /**
2063
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata
2064
     *
2065
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2066
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2067
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2068
     */
2069
    public function testUpdateContentMainTranslation(): void
2070
    {
2071
        $repository = $this->getRepository();
2072
        $contentService = $repository->getContentService();
2073
        $locationService = $repository->getLocationService();
2074
2075
        // create a Content Type which is not always available by default
2076
        $contentType = $this->createSimpleContentType(
2077
            'test_t',
2078
            self::ENG_GB,
2079
            [
2080
                'name' => 'ezstring',
2081
            ],
2082
            false
2083
        );
2084
2085
        $contentCreate = $contentService->newContentCreateStruct(
2086
            $contentType,
2087
            self::ENG_US
2088
        );
2089
        $contentCreate->setField('name', 'My Content');
2090
        $content = $contentService->publishVersion(
2091
            $contentService->createContent(
2092
                $contentCreate,
2093
                [$locationService->newLocationCreateStruct(2)]
2094
            )->getVersionInfo()
2095
        );
2096
        // perform sanity check
2097
        self::assertFalse($content->contentInfo->alwaysAvailable);
2098
2099
        $updateStruct = $contentService->newContentMetadataUpdateStruct();
2100
        $updateStruct->mainLanguageCode = self::ENG_GB;
2101
2102
        $contentService->updateContentMetadata($content->contentInfo, $updateStruct);
2103
2104
        $reloadedContent = $contentService->loadContent($content->id);
2105
        self::assertEquals(self::ENG_GB, $reloadedContent->contentInfo->mainLanguageCode);
2106
2107
        // check that other properties remained unchanged
2108
        self::assertStructPropertiesCorrect(
2109
            $content->contentInfo,
2110
            $reloadedContent->contentInfo,
2111
            [
2112
                'id',
2113
                'contentTypeId',
2114
                'name',
2115
                'sectionId',
2116
                'currentVersionNo',
2117
                'published',
2118
                'ownerId',
2119
                'alwaysAvailable',
2120
                'remoteId',
2121
                'mainLocationId',
2122
                'status',
2123
            ]
2124
        );
2125
    }
2126
2127
    /**
2128
     * Test for the deleteContent() method.
2129
     *
2130
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2131
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2132
     */
2133
    public function testDeleteContent()
2134
    {
2135
        $contentVersion2 = $this->createContentVersion2();
2136
2137
        // Load the locations for this content object
2138
        $locations = $this->locationService->loadLocations($contentVersion2->contentInfo);
2139
2140
        // This will delete the content, all versions and the associated locations
2141
        $this->contentService->deleteContent($contentVersion2->contentInfo);
2142
2143
        $this->expectException(NotFoundException::class);
2144
2145
        foreach ($locations as $location) {
2146
            $this->locationService->loadLocation($location->id);
2147
        }
2148
    }
2149
2150
    /**
2151
     * Test for the deleteContent() method.
2152
     *
2153
     * Test for issue EZP-21057:
2154
     * "contentService: Unable to delete a content with an empty file attribute"
2155
     *
2156
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2157
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2158
     */
2159
    public function testDeleteContentWithEmptyBinaryField()
2160
    {
2161
        $contentVersion = $this->createContentVersion1EmptyBinaryField();
2162
2163
        // Load the locations for this content object
2164
        $locations = $this->locationService->loadLocations($contentVersion->contentInfo);
2165
2166
        // This will delete the content, all versions and the associated locations
2167
        $this->contentService->deleteContent($contentVersion->contentInfo);
2168
2169
        $this->expectException(NotFoundException::class);
2170
2171
        foreach ($locations as $location) {
2172
            $this->locationService->loadLocation($location->id);
2173
        }
2174
    }
2175
2176
    public function testCountContentDraftsReturnsZeroByDefault(): void
2177
    {
2178
        $this->assertSame(0, $this->contentService->countContentDrafts());
2179
    }
2180
2181
    public function testCountContentDrafts(): void
2182
    {
2183
        // Create 5 drafts
2184
        $this->createContentDrafts(5);
2185
2186
        $this->assertSame(5, $this->contentService->countContentDrafts());
2187
    }
2188
2189
    public function testCountContentDraftsForUsers(): void
2190
    {
2191
        $newUser = $this->createUserWithPolicies(
2192
            'new_user',
2193
            [
2194
                ['module' => 'content', 'function' => 'create'],
2195
                ['module' => 'content', 'function' => 'read'],
2196
                ['module' => 'content', 'function' => 'publish'],
2197
                ['module' => 'content', 'function' => 'edit'],
2198
            ]
2199
        );
2200
2201
        $previousUser = $this->permissionResolver->getCurrentUserReference();
2202
2203
        // Set new editor as user
2204
        $this->permissionResolver->setCurrentUserReference($newUser);
2205
2206
        // Create a content draft as newUser
2207
        $publishedContent = $this->createContentVersion1();
2208
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2209
2210
        // Reset to previous current user
2211
        $this->permissionResolver->setCurrentUserReference($previousUser);
2212
2213
        // Now $contentDrafts for the previous current user and the new user
2214
        $newUserDrafts = $this->contentService->countContentDrafts($newUser);
2215
        $previousUserDrafts = $this->contentService->countContentDrafts();
2216
2217
        $this->assertSame(1, $newUserDrafts);
2218
        $this->assertSame(0, $previousUserDrafts);
2219
    }
2220
2221
    /**
2222
     * Test for the loadContentDrafts() method.
2223
     *
2224
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2225
     */
2226
    public function testLoadContentDraftsReturnsEmptyArrayByDefault()
2227
    {
2228
        $contentDrafts = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

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...
2229
2230
        $this->assertSame([], $contentDrafts);
2231
    }
2232
2233
    /**
2234
     * Test for the loadContentDrafts() method.
2235
     *
2236
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2237
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
2238
     */
2239
    public function testLoadContentDrafts()
2240
    {
2241
        // "Media" content object
2242
        $mediaContentInfo = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
2243
2244
        // "eZ Publish Demo Design ..." content object
2245
        $demoDesignContentInfo = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
2246
2247
        // Create some drafts
2248
        $this->contentService->createContentDraft($mediaContentInfo);
2249
        $this->contentService->createContentDraft($demoDesignContentInfo);
2250
2251
        // Now $contentDrafts should contain two drafted versions
2252
        $draftedVersions = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

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...
2253
2254
        $actual = [
2255
            $draftedVersions[0]->status,
2256
            $draftedVersions[0]->getContentInfo()->remoteId,
2257
            $draftedVersions[1]->status,
2258
            $draftedVersions[1]->getContentInfo()->remoteId,
2259
        ];
2260
        sort($actual, SORT_STRING);
2261
2262
        $this->assertEquals(
2263
            [
2264
                VersionInfo::STATUS_DRAFT,
2265
                VersionInfo::STATUS_DRAFT,
2266
                self::DEMO_DESIGN_REMOTE_ID,
2267
                self::MEDIA_REMOTE_ID,
2268
            ],
2269
            $actual
2270
        );
2271
    }
2272
2273
    /**
2274
     * Test for the loadContentDrafts() method.
2275
     *
2276
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts($user)
2277
     */
2278
    public function testLoadContentDraftsWithFirstParameter()
2279
    {
2280
        $user = $this->createUserVersion1();
2281
2282
        // Get current user
2283
        $oldCurrentUser = $this->permissionResolver->getCurrentUserReference();
2284
2285
        // Set new editor as user
2286
        $this->permissionResolver->setCurrentUserReference($user);
2287
2288
        // "Media" content object
2289
        $mediaContentInfo = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
2290
2291
        // Create a content draft
2292
        $this->contentService->createContentDraft($mediaContentInfo);
2293
2294
        // Reset to previous current user
2295
        $this->permissionResolver->setCurrentUserReference($oldCurrentUser);
2296
2297
        // Now $contentDrafts for the previous current user and the new user
2298
        $newCurrentUserDrafts = $this->contentService->loadContentDrafts($user);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

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...
2299
        $oldCurrentUserDrafts = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

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...
2300
2301
        $this->assertSame([], $oldCurrentUserDrafts);
2302
2303
        $this->assertEquals(
2304
            [
2305
                VersionInfo::STATUS_DRAFT,
2306
                self::MEDIA_REMOTE_ID,
2307
            ],
2308
            [
2309
                $newCurrentUserDrafts[0]->status,
2310
                $newCurrentUserDrafts[0]->getContentInfo()->remoteId,
2311
            ]
2312
        );
2313
        $this->assertTrue($newCurrentUserDrafts[0]->isDraft());
2314
        $this->assertFalse($newCurrentUserDrafts[0]->isArchived());
2315
        $this->assertFalse($newCurrentUserDrafts[0]->isPublished());
2316
    }
2317
2318
    /**
2319
     * Test for the loadContentDraftList() method.
2320
     *
2321
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2322
     */
2323
    public function testLoadContentDraftListWithPaginationParameters()
2324
    {
2325
        // Create some drafts
2326
        $publishedContent = $this->createContentVersion1();
2327
        $draftContentA = $this->contentService->createContentDraft($publishedContent->contentInfo);
2328
        $draftContentB = $this->contentService->createContentDraft($draftContentA->contentInfo);
2329
        $draftContentC = $this->contentService->createContentDraft($draftContentB->contentInfo);
2330
        $draftContentD = $this->contentService->createContentDraft($draftContentC->contentInfo);
2331
        $draftContentE = $this->contentService->createContentDraft($draftContentD->contentInfo);
2332
2333
        $draftsOnPage1 = $this->contentService->loadContentDraftList(null, 0, 2);
2334
        $draftsOnPage2 = $this->contentService->loadContentDraftList(null, 2, 2);
2335
2336
        $this->assertSame(5, $draftsOnPage1->totalCount);
2337
        $this->assertSame(5, $draftsOnPage2->totalCount);
2338
        $this->assertEquals($draftContentE->getVersionInfo(), $draftsOnPage1->items[0]->getVersionInfo());
2339
        $this->assertEquals($draftContentD->getVersionInfo(), $draftsOnPage1->items[1]->getVersionInfo());
2340
        $this->assertEquals($draftContentC->getVersionInfo(), $draftsOnPage2->items[0]->getVersionInfo());
2341
        $this->assertEquals($draftContentB->getVersionInfo(), $draftsOnPage2->items[1]->getVersionInfo());
2342
    }
2343
2344
    /**
2345
     * Test for the loadContentDraftList() method.
2346
     *
2347
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts($user)
2348
     */
2349
    public function testLoadContentDraftListWithForUserWithLimitation()
2350
    {
2351
        $oldUser = $this->permissionResolver->getCurrentUserReference();
2352
2353
        $parentContent = $this->createFolder(['eng-US' => 'parentFolder'], 2);
2354
        $content = $this->createFolder(['eng-US' => 'parentFolder'], $parentContent->contentInfo->mainLocationId);
2355
2356
        // User has limitation to read versions only for `$content`, not for `$parentContent`
2357
        $newUser = $this->createUserWithVersionReadLimitations([$content->contentInfo->mainLocationId]);
2358
2359
        $this->permissionResolver->setCurrentUserReference($newUser);
2360
2361
        $contentDraftUnauthorized = $this->contentService->createContentDraft($parentContent->contentInfo);
2362
        $contentDraftA = $this->contentService->createContentDraft($content->contentInfo);
2363
        $contentDraftB = $this->contentService->createContentDraft($content->contentInfo);
2364
2365
        $newUserDraftList = $this->contentService->loadContentDraftList($newUser, 0);
2366
        $this->assertSame(3, $newUserDraftList->totalCount);
2367
        $this->assertEquals($contentDraftB->getVersionInfo(), $newUserDraftList->items[0]->getVersionInfo());
2368
        $this->assertEquals($contentDraftA->getVersionInfo(), $newUserDraftList->items[1]->getVersionInfo());
2369
        $this->assertEquals(
2370
            new UnauthorizedContentDraftListItem('content', 'versionread', ['contentId' => $contentDraftUnauthorized->id]),
2371
            $newUserDraftList->items[2]
2372
        );
2373
2374
        // Reset to previous user
2375
        $this->permissionResolver->setCurrentUserReference($oldUser);
2376
2377
        $oldUserDraftList = $this->contentService->loadContentDraftList();
2378
2379
        $this->assertSame(0, $oldUserDraftList->totalCount);
2380
        $this->assertSame([], $oldUserDraftList->items);
2381
    }
2382
2383
    /**
2384
     * Test for the loadContentDraftList() method.
2385
     *
2386
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2387
     */
2388
    public function testLoadAllContentDrafts()
2389
    {
2390
        // Create more drafts then default pagination limit
2391
        $this->createContentDrafts(12);
2392
2393
        $this->assertCount(12, $this->contentService->loadContentDraftList());
2394
    }
2395
2396
    /**
2397
     * Test for the loadVersionInfo() method.
2398
     *
2399
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo($contentInfo, $versionNo)
2400
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2401
     */
2402
    public function testLoadVersionInfoWithSecondParameter()
2403
    {
2404
        $publishedContent = $this->createContentVersion1();
2405
2406
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2407
2408
        // Will return the VersionInfo of the $draftContent
2409
        $versionInfo = $this->contentService->loadVersionInfoById($publishedContent->id, 2);
2410
2411
        $this->assertEquals(2, $versionInfo->versionNo);
2412
2413
        // Check that ContentInfo contained in VersionInfo has correct main Location id set
2414
        $this->assertEquals(
2415
            $publishedContent->getVersionInfo()->getContentInfo()->mainLocationId,
2416
            $versionInfo->getContentInfo()->mainLocationId
2417
        );
2418
    }
2419
2420
    /**
2421
     * Test for the loadVersionInfo() method.
2422
     *
2423
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo($contentInfo, $versionNo)
2424
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoWithSecondParameter
2425
     */
2426
    public function testLoadVersionInfoThrowsNotFoundExceptionWithSecondParameter()
2427
    {
2428
        $draft = $this->createContentDraftVersion1();
2429
2430
        $this->expectException(NotFoundException::class);
2431
2432
        // This call will fail with a "NotFoundException", because not versionNo 2 exists for this content object.
2433
        $this->contentService->loadVersionInfo($draft->contentInfo, 2);
2434
    }
2435
2436
    /**
2437
     * Test for the loadVersionInfoById() method.
2438
     *
2439
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById($contentId, $versionNo)
2440
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoWithSecondParameter
2441
     */
2442
    public function testLoadVersionInfoByIdWithSecondParameter()
2443
    {
2444
        $publishedContent = $this->createContentVersion1();
2445
2446
        $draftContent = $this->contentService->createContentDraft($publishedContent->contentInfo);
2447
2448
        // Will return the VersionInfo of the $draftContent
2449
        $versionInfo = $this->contentService->loadVersionInfoById($publishedContent->id, 2);
2450
2451
        $this->assertEquals(2, $versionInfo->versionNo);
2452
2453
        // Check that ContentInfo contained in VersionInfo has correct main Location id set
2454
        $this->assertEquals(
2455
            $publishedContent->getVersionInfo()->getContentInfo()->mainLocationId,
2456
            $versionInfo->getContentInfo()->mainLocationId
2457
        );
2458
2459
        return [
2460
            'versionInfo' => $versionInfo,
2461
            'draftContent' => $draftContent,
2462
        ];
2463
    }
2464
2465
    /**
2466
     * Test for the returned value of the loadVersionInfoById() method.
2467
     *
2468
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoByIdWithSecondParameter
2469
     * @covers \eZ\Publish\API\Repository\ContentService::loadVersionInfoById
2470
     *
2471
     * @param array $data
2472
     */
2473
    public function testLoadVersionInfoByIdWithSecondParameterSetsExpectedVersionInfo(array $data)
2474
    {
2475
        /** @var VersionInfo $versionInfo */
2476
        $versionInfo = $data['versionInfo'];
2477
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $draftContent */
2478
        $draftContent = $data['draftContent'];
2479
2480
        $this->assertPropertiesCorrect(
2481
            [
2482
                'names' => [
2483
                    self::ENG_US => 'An awesome forum',
2484
                ],
2485
                'contentInfo' => new ContentInfo([
2486
                    'id' => $draftContent->contentInfo->id,
2487
                    'contentTypeId' => 28,
2488
                    'name' => 'An awesome forum',
2489
                    'sectionId' => 1,
2490
                    'currentVersionNo' => 1,
2491
                    'published' => true,
2492
                    'ownerId' => 14,
2493
                    // this Content Object is created at the test runtime
2494
                    'modificationDate' => $versionInfo->contentInfo->modificationDate,
2495
                    'publishedDate' => $versionInfo->contentInfo->publishedDate,
2496
                    'alwaysAvailable' => 1,
2497
                    'remoteId' => 'abcdef0123456789abcdef0123456789',
2498
                    'mainLanguageCode' => self::ENG_US,
2499
                    'mainLocationId' => $draftContent->contentInfo->mainLocationId,
2500
                    'status' => ContentInfo::STATUS_PUBLISHED,
2501
                ]),
2502
                'id' => $draftContent->versionInfo->id,
2503
                'versionNo' => 2,
2504
                'creatorId' => 14,
2505
                'status' => 0,
2506
                'initialLanguageCode' => self::ENG_US,
2507
                'languageCodes' => [
2508
                    self::ENG_US,
2509
                ],
2510
            ],
2511
            $versionInfo
2512
        );
2513
    }
2514
2515
    /**
2516
     * Test for the loadVersionInfoById() method.
2517
     *
2518
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById($contentId, $versionNo)
2519
     */
2520
    public function testLoadVersionInfoByIdThrowsNotFoundExceptionWithSecondParameter()
2521
    {
2522
        $content = $this->createContentVersion1();
2523
2524
        $this->expectException(NotFoundException::class);
2525
2526
        // This call will fail with a "NotFoundException", because not versionNo 2 exists for this content object.
2527
        $this->contentService->loadVersionInfoById($content->id, 2);
2528
    }
2529
2530
    /**
2531
     * Test for the loadContentByVersionInfo() method.
2532
     *
2533
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByVersionInfo($versionInfo, $languages)
2534
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
2535
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByVersionInfo
2536
     */
2537
    public function testLoadContentByVersionInfoWithSecondParameter()
2538
    {
2539
        $sectionId = $this->generateId('section', 1);
2540
        $contentTypeService = $this->getRepository()->getContentTypeService();
2541
2542
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
2543
2544
        $contentCreateStruct = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
2545
2546
        $contentCreateStruct->setField('name', 'Sindelfingen forum²');
2547
2548
        $contentCreateStruct->setField('name', 'Sindelfingen forum²³', self::ENG_GB);
2549
2550
        $contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
2551
        // $sectionId contains the ID of section 1
2552
        $contentCreateStruct->sectionId = $sectionId;
2553
        $contentCreateStruct->alwaysAvailable = true;
2554
2555
        // Create a new content draft
2556
        $content = $this->contentService->createContent($contentCreateStruct);
2557
2558
        // Now publish this draft
2559
        $publishedContent = $this->contentService->publishVersion($content->getVersionInfo());
2560
2561
        // Will return a content instance with fields in "eng-US"
2562
        $reloadedContent = $this->contentService->loadContentByVersionInfo(
2563
            $publishedContent->getVersionInfo(),
2564
            [
2565
                self::ENG_GB,
2566
            ],
2567
            false
2568
        );
2569
2570
        $actual = [];
2571
        foreach ($reloadedContent->getFields() as $field) {
2572
            $actual[] = new Field(
2573
                [
2574
                    'id' => 0,
2575
                    'value' => $field->value !== null, // Actual value tested by FieldType integration tests
2576
                    'languageCode' => $field->languageCode,
2577
                    'fieldDefIdentifier' => $field->fieldDefIdentifier,
2578
                ]
2579
            );
2580
        }
2581
        usort(
2582
            $actual,
2583
            function ($field1, $field2) {
2584
                if (0 === ($return = strcasecmp($field1->fieldDefIdentifier, $field2->fieldDefIdentifier))) {
2585
                    return strcasecmp($field1->languageCode, $field2->languageCode);
2586
                }
2587
2588
                return $return;
2589
            }
2590
        );
2591
2592
        $expected = [
2593
            new Field(
2594
                [
2595
                    'id' => 0,
2596
                    'value' => true,
2597
                    'languageCode' => self::ENG_GB,
2598
                    'fieldDefIdentifier' => 'description',
2599
                ]
2600
            ),
2601
            new Field(
2602
                [
2603
                    'id' => 0,
2604
                    'value' => true,
2605
                    'languageCode' => self::ENG_GB,
2606
                    'fieldDefIdentifier' => 'name',
2607
                ]
2608
            ),
2609
        ];
2610
2611
        $this->assertEquals($expected, $actual);
2612
    }
2613
2614
    /**
2615
     * Test for the loadContentByContentInfo() method.
2616
     *
2617
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages)
2618
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
2619
     */
2620
    public function testLoadContentByContentInfoWithLanguageParameters()
2621
    {
2622
        $sectionId = $this->generateId('section', 1);
2623
        $contentTypeService = $this->getRepository()->getContentTypeService();
2624
2625
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
2626
2627
        $contentCreateStruct = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
2628
2629
        $contentCreateStruct->setField('name', 'Sindelfingen forum²');
2630
2631
        $contentCreateStruct->setField('name', 'Sindelfingen forum²³', self::ENG_GB);
2632
2633
        $contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
2634
        // $sectionId contains the ID of section 1
2635
        $contentCreateStruct->sectionId = $sectionId;
2636
        $contentCreateStruct->alwaysAvailable = true;
2637
2638
        // Create a new content draft
2639
        $content = $this->contentService->createContent($contentCreateStruct);
2640
2641
        // Now publish this draft
2642
        $publishedContent = $this->contentService->publishVersion($content->getVersionInfo());
2643
2644
        // Will return a content instance with fields in "eng-US"
2645
        $reloadedContent = $this->contentService->loadContentByContentInfo(
2646
            $publishedContent->contentInfo,
2647
            [
2648
                self::ENG_US,
2649
            ],
2650
            null,
2651
            false
2652
        );
2653
2654
        $actual = $this->normalizeFields($reloadedContent->getFields());
2655
2656
        $expected = [
2657
            new Field(
2658
                [
2659
                    'id' => 0,
2660
                    'value' => true,
2661
                    'languageCode' => self::ENG_US,
2662
                    'fieldDefIdentifier' => 'description',
2663
                    'fieldTypeIdentifier' => 'ezrichtext',
2664
                ]
2665
            ),
2666
            new Field(
2667
                [
2668
                    'id' => 0,
2669
                    'value' => true,
2670
                    'languageCode' => self::ENG_US,
2671
                    'fieldDefIdentifier' => 'name',
2672
                    'fieldTypeIdentifier' => 'ezstring',
2673
                ]
2674
            ),
2675
        ];
2676
2677
        $this->assertEquals($expected, $actual);
2678
2679
        // Will return a content instance with fields in "eng-GB" (versions prior to 6.0.0-beta9 returned "eng-US" also)
2680
        $reloadedContent = $this->contentService->loadContentByContentInfo(
2681
            $publishedContent->contentInfo,
2682
            [
2683
                self::ENG_GB,
2684
            ],
2685
            null,
2686
            true
2687
        );
2688
2689
        $actual = $this->normalizeFields($reloadedContent->getFields());
2690
2691
        $expected = [
2692
            new Field(
2693
                [
2694
                    'id' => 0,
2695
                    'value' => true,
2696
                    'languageCode' => self::ENG_GB,
2697
                    'fieldDefIdentifier' => 'description',
2698
                    'fieldTypeIdentifier' => 'ezrichtext',
2699
                ]
2700
            ),
2701
            new Field(
2702
                [
2703
                    'id' => 0,
2704
                    'value' => true,
2705
                    'languageCode' => self::ENG_GB,
2706
                    'fieldDefIdentifier' => 'name',
2707
                    'fieldTypeIdentifier' => 'ezstring',
2708
                ]
2709
            ),
2710
        ];
2711
2712
        $this->assertEquals($expected, $actual);
2713
2714
        // Will return a content instance with fields in main language "eng-US", as "fre-FR" does not exists
2715
        $reloadedContent = $this->contentService->loadContentByContentInfo(
2716
            $publishedContent->contentInfo,
2717
            [
2718
                'fre-FR',
2719
            ],
2720
            null,
2721
            true
2722
        );
2723
2724
        $actual = $this->normalizeFields($reloadedContent->getFields());
2725
2726
        $expected = [
2727
            new Field(
2728
                [
2729
                    'id' => 0,
2730
                    'value' => true,
2731
                    'languageCode' => self::ENG_US,
2732
                    'fieldDefIdentifier' => 'description',
2733
                    'fieldTypeIdentifier' => 'ezrichtext',
2734
                ]
2735
            ),
2736
            new Field(
2737
                [
2738
                    'id' => 0,
2739
                    'value' => true,
2740
                    'languageCode' => self::ENG_US,
2741
                    'fieldDefIdentifier' => 'name',
2742
                    'fieldTypeIdentifier' => 'ezstring',
2743
                ]
2744
            ),
2745
        ];
2746
2747
        $this->assertEquals($expected, $actual);
2748
    }
2749
2750
    /**
2751
     * Test for the loadContentByContentInfo() method.
2752
     *
2753
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages, $versionNo)
2754
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
2755
     */
2756
    public function testLoadContentByContentInfoWithVersionNumberParameter()
2757
    {
2758
        $publishedContent = $this->createContentVersion1();
2759
2760
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2761
2762
        // This content instance is identical to $draftContent
2763
        $draftContentReloaded = $this->contentService->loadContentByContentInfo(
2764
            $publishedContent->contentInfo,
2765
            null,
2766
            2
2767
        );
2768
2769
        $this->assertEquals(
2770
            2,
2771
            $draftContentReloaded->getVersionInfo()->versionNo
2772
        );
2773
2774
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2775
        $this->assertEquals(
2776
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2777
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2778
        );
2779
    }
2780
2781
    /**
2782
     * Test for the loadContentByContentInfo() method.
2783
     *
2784
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages, $versionNo)
2785
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfoWithVersionNumberParameter
2786
     */
2787
    public function testLoadContentByContentInfoThrowsNotFoundExceptionWithVersionNumberParameter()
2788
    {
2789
        $content = $this->createContentVersion1();
2790
2791
        $this->expectException(NotFoundException::class);
2792
2793
        // This call will fail with a "NotFoundException", because no content with versionNo = 2 exists.
2794
        $this->contentService->loadContentByContentInfo($content->contentInfo, null, 2);
2795
    }
2796
2797
    /**
2798
     * Test for the loadContent() method.
2799
     *
2800
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages)
2801
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2802
     */
2803
    public function testLoadContentWithPrioritizedLanguages()
2804
    {
2805
        $draft = $this->createMultipleLanguageDraftVersion1();
2806
2807
        // This draft contains those fields localized with "eng-GB"
2808
        $draftLocalized = $this->contentService->loadContent($draft->id, [self::ENG_GB], null, false);
2809
2810
        $this->assertLocaleFieldsEquals($draftLocalized->getFields(), self::ENG_GB);
2811
2812
        return $draftLocalized;
2813
    }
2814
2815
    /**
2816
     * Test for the loadContent() method using undefined translation.
2817
     *
2818
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithPrioritizedLanguages
2819
     *
2820
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
2821
     */
2822
    public function testLoadContentWithPrioritizedLanguagesThrowsNotFoundException(Content $contentDraft)
2823
    {
2824
        $this->expectException(NotFoundException::class);
2825
2826
        $this->contentService->loadContent($contentDraft->id, [self::GER_DE], null, false);
2827
    }
2828
2829
    /**
2830
     * Test for the loadContent() method.
2831
     *
2832
     * @see \eZ\Publish\API\Repository\ContentService::loadContent
2833
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithPrioritizedLanguages
2834
     */
2835
    public function testLoadContentPassTroughPrioritizedLanguagesToContentType(Content $content): void
2836
    {
2837
        $contentTypeService = $this->getRepository()->getContentTypeService();
2838
2839
        $contentType = $contentTypeService->loadContentType(
2840
            $content->contentInfo->contentTypeId,
2841
            [self::ENG_GB]
2842
        );
2843
2844
        $this->assertEquals($contentType, $content->getContentType());
2845
    }
2846
2847
    /**
2848
     * Test for the loadContent() method.
2849
     *
2850
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages, $versionNo)
2851
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2852
     */
2853
    public function testLoadContentWithThirdParameter()
2854
    {
2855
        $publishedContent = $this->createContentVersion1();
2856
2857
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2858
2859
        // This content instance is identical to $draftContent
2860
        $draftContentReloaded = $this->contentService->loadContent($publishedContent->id, null, 2);
2861
2862
        $this->assertEquals(2, $draftContentReloaded->getVersionInfo()->versionNo);
2863
2864
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2865
        $this->assertEquals(
2866
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2867
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2868
        );
2869
    }
2870
2871
    /**
2872
     * Test for the loadContent() method.
2873
     *
2874
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages, $versionNo)
2875
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithThirdParameter
2876
     */
2877
    public function testLoadContentThrowsNotFoundExceptionWithThirdParameter()
2878
    {
2879
        $content = $this->createContentVersion1();
2880
2881
        $this->expectException(NotFoundException::class);
2882
2883
        // This call will fail with a "NotFoundException", because for this content object no versionNo=2 exists.
2884
        $this->contentService->loadContent($content->id, null, 2);
2885
    }
2886
2887
    /**
2888
     * Test for the loadContentByRemoteId() method.
2889
     *
2890
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages)
2891
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2892
     */
2893
    public function testLoadContentByRemoteIdWithSecondParameter()
2894
    {
2895
        $draft = $this->createMultipleLanguageDraftVersion1();
2896
2897
        $this->contentService->publishVersion($draft->versionInfo);
2898
2899
        // This draft contains those fields localized with "eng-GB"
2900
        $draftLocalized = $this->contentService->loadContentByRemoteId(
2901
            $draft->contentInfo->remoteId,
2902
            [self::ENG_GB],
2903
            null,
2904
            false
2905
        );
2906
2907
        $this->assertLocaleFieldsEquals($draftLocalized->getFields(), self::ENG_GB);
2908
    }
2909
2910
    /**
2911
     * Test for the loadContentByRemoteId() method.
2912
     *
2913
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages, $versionNo)
2914
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2915
     */
2916
    public function testLoadContentByRemoteIdWithThirdParameter()
2917
    {
2918
        $publishedContent = $this->createContentVersion1();
2919
2920
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2921
2922
        // This content instance is identical to $draftContent
2923
        $draftContentReloaded = $this->contentService->loadContentByRemoteId(
2924
            $publishedContent->contentInfo->remoteId,
2925
            null,
2926
            2
2927
        );
2928
2929
        $this->assertEquals(2, $draftContentReloaded->getVersionInfo()->versionNo);
2930
2931
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2932
        $this->assertEquals(
2933
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2934
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2935
        );
2936
    }
2937
2938
    /**
2939
     * Test for the loadContentByRemoteId() method.
2940
     *
2941
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages, $versionNo)
2942
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteIdWithThirdParameter
2943
     */
2944
    public function testLoadContentByRemoteIdThrowsNotFoundExceptionWithThirdParameter()
2945
    {
2946
        $content = $this->createContentVersion1();
2947
2948
        $this->expectException(NotFoundException::class);
2949
2950
        // This call will fail with a "NotFoundException", because for this content object no versionNo=2 exists.
2951
        $this->contentService->loadContentByRemoteId(
2952
            $content->contentInfo->remoteId,
2953
            null,
2954
            2
2955
        );
2956
    }
2957
2958
    /**
2959
     * Test that retrieval of translated name field respects prioritized language list.
2960
     *
2961
     * @dataProvider getPrioritizedLanguageList
2962
     * @param string[]|null $languageCodes
2963
     */
2964
    public function testLoadContentWithPrioritizedLanguagesList($languageCodes)
2965
    {
2966
        $content = $this->createContentVersion2();
2967
2968
        $content = $this->contentService->loadContent($content->id, $languageCodes);
2969
2970
        $expectedName = $content->getVersionInfo()->getName(
2971
            isset($languageCodes[0]) ? $languageCodes[0] : null
2972
        );
2973
        $nameValue = $content->getFieldValue('name');
2974
        /** @var \eZ\Publish\Core\FieldType\TextLine\Value $nameValue */
2975
        self::assertEquals($expectedName, $nameValue->text);
2976
        self::assertEquals($expectedName, $content->getVersionInfo()->getName());
2977
        // Also check value on shortcut method on content
2978
        self::assertEquals($expectedName, $content->getName());
2979
    }
2980
2981
    /**
2982
     * @return array
2983
     */
2984
    public function getPrioritizedLanguageList()
2985
    {
2986
        return [
2987
            [[self::ENG_US]],
2988
            [[self::ENG_GB]],
2989
            [[self::ENG_GB, self::ENG_US]],
2990
            [[self::ENG_US, self::ENG_GB]],
2991
        ];
2992
    }
2993
2994
    /**
2995
     * Test for the deleteVersion() method.
2996
     *
2997
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
2998
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
2999
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3000
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3001
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
3002
     */
3003
    public function testDeleteVersion()
3004
    {
3005
        $content = $this->createContentVersion1();
3006
3007
        // Create new draft, because published or last version of the Content can't be deleted
3008
        $draft = $this->contentService->createContentDraft(
3009
            $content->getVersionInfo()->getContentInfo()
3010
        );
3011
3012
        // Delete the previously created draft
3013
        $this->contentService->deleteVersion($draft->getVersionInfo());
3014
3015
        $versions = $this->contentService->loadVersions($content->getVersionInfo()->getContentInfo());
3016
3017
        $this->assertCount(1, $versions);
3018
        $this->assertEquals(
3019
            $content->getVersionInfo()->id,
3020
            $versions[0]->id
3021
        );
3022
    }
3023
3024
    /**
3025
     * Test for the deleteVersion() method.
3026
     *
3027
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3028
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3029
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3030
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3031
     */
3032
    public function testDeleteVersionThrowsBadStateExceptionOnPublishedVersion()
3033
    {
3034
        $content = $this->createContentVersion1();
3035
3036
        $this->expectException(BadStateException::class);
3037
3038
        // This call will fail with a "BadStateException", because the content version is currently published.
3039
        $this->contentService->deleteVersion($content->getVersionInfo());
3040
    }
3041
3042
    /**
3043
     * Test for the deleteVersion() method.
3044
     *
3045
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3046
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3047
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3048
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3049
     */
3050
    public function testDeleteVersionWorksIfOnlyVersionIsDraft()
3051
    {
3052
        $draft = $this->createContentDraftVersion1();
3053
3054
        $this->contentService->deleteVersion($draft->getVersionInfo());
3055
3056
        $this->expectException(NotFoundException::class);
3057
3058
        // This call will fail with a "NotFound", because we allow to delete content if remaining version is draft.
3059
        // Can normally only happen if there where always only a draft to begin with, simplifies UI edit API usage.
3060
        $this->contentService->loadContent($draft->id);
3061
    }
3062
3063
    /**
3064
     * Test for the loadVersions() method.
3065
     *
3066
     * @see \eZ\Publish\API\Repository\ContentService::loadVersions()
3067
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3068
     *
3069
     * @return VersionInfo[]
3070
     */
3071
    public function testLoadVersions()
3072
    {
3073
        $contentVersion2 = $this->createContentVersion2();
3074
3075
        // Load versions of this ContentInfo instance
3076
        $versions = $this->contentService->loadVersions($contentVersion2->contentInfo);
3077
3078
        $expectedVersionsOrder = [
3079
            $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 1),
3080
            $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 2),
3081
        ];
3082
3083
        $this->assertEquals($expectedVersionsOrder, $versions);
3084
3085
        return $versions;
3086
    }
3087
3088
    /**
3089
     * Test for the loadVersions() method.
3090
     *
3091
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersions
3092
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersions
3093
     *
3094
     * @param \eZ\Publish\API\Repository\Values\Content\VersionInfo[] $versions
3095
     */
3096
    public function testLoadVersionsSetsExpectedVersionInfo(array $versions)
3097
    {
3098
        $this->assertCount(2, $versions);
3099
3100
        $expectedVersions = [
3101
            [
3102
                'versionNo' => 1,
3103
                'creatorId' => 14,
3104
                'status' => VersionInfo::STATUS_ARCHIVED,
3105
                'initialLanguageCode' => self::ENG_US,
3106
                'languageCodes' => [self::ENG_US],
3107
            ],
3108
            [
3109
                'versionNo' => 2,
3110
                'creatorId' => 10,
3111
                'status' => VersionInfo::STATUS_PUBLISHED,
3112
                'initialLanguageCode' => self::ENG_US,
3113
                'languageCodes' => [self::ENG_US, self::ENG_GB],
3114
            ],
3115
        ];
3116
3117
        $this->assertPropertiesCorrect($expectedVersions[0], $versions[0]);
3118
        $this->assertPropertiesCorrect($expectedVersions[1], $versions[1]);
3119
        $this->assertEquals(
3120
            $versions[0]->creationDate->getTimestamp(),
3121
            $versions[1]->creationDate->getTimestamp(),
3122
            'Creation time did not match within delta of 2 seconds',
3123
            2
3124
        );
3125
        $this->assertEquals(
3126
            $versions[0]->modificationDate->getTimestamp(),
3127
            $versions[1]->modificationDate->getTimestamp(),
3128
            'Creation time did not match within delta of 2 seconds',
3129
            2
3130
        );
3131
        $this->assertTrue($versions[0]->isArchived());
3132
        $this->assertFalse($versions[0]->isDraft());
3133
        $this->assertFalse($versions[0]->isPublished());
3134
3135
        $this->assertTrue($versions[1]->isPublished());
3136
        $this->assertFalse($versions[1]->isDraft());
3137
        $this->assertFalse($versions[1]->isArchived());
3138
    }
3139
3140
    /**
3141
     * Test for the copyContent() method.
3142
     *
3143
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
3144
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3145
     * @group field-type
3146
     */
3147
    public function testCopyContent()
3148
    {
3149
        $parentLocationId = $this->generateId('location', 56);
3150
3151
        $contentVersion2 = $this->createMultipleLanguageContentVersion2();
3152
3153
        // Configure new target location
3154
        $targetLocationCreate = $this->locationService->newLocationCreateStruct($parentLocationId);
3155
3156
        $targetLocationCreate->priority = 42;
3157
        $targetLocationCreate->hidden = true;
3158
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3159
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3160
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3161
3162
        // Copy content with all versions and drafts
3163
        $contentCopied = $this->contentService->copyContent(
3164
            $contentVersion2->contentInfo,
3165
            $targetLocationCreate
3166
        );
3167
3168
        $this->assertInstanceOf(
3169
            Content::class,
3170
            $contentCopied
3171
        );
3172
3173
        $this->assertNotEquals(
3174
            $contentVersion2->contentInfo->remoteId,
3175
            $contentCopied->contentInfo->remoteId
3176
        );
3177
3178
        $this->assertNotEquals(
3179
            $contentVersion2->id,
3180
            $contentCopied->id
3181
        );
3182
3183
        $this->assertEquals(
3184
            2,
3185
            count($this->contentService->loadVersions($contentCopied->contentInfo))
3186
        );
3187
3188
        $this->assertEquals(2, $contentCopied->getVersionInfo()->versionNo);
3189
3190
        $this->assertAllFieldsEquals($contentCopied->getFields());
3191
3192
        $this->assertDefaultContentStates($contentCopied->contentInfo);
3193
3194
        $this->assertNotNull(
3195
            $contentCopied->contentInfo->mainLocationId,
3196
            'Expected main location to be set given we provided a LocationCreateStruct'
3197
        );
3198
    }
3199
3200
    /**
3201
     * Test for the copyContent() method with ezsettings.default.content.retain_owner_on_copy set to false
3202
     * See settings/test/integration_legacy.yml for service override.
3203
     *
3204
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
3205
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3206
     * @group field-type
3207
     */
3208
    public function testCopyContentWithNewOwner()
3209
    {
3210
        $parentLocationId = $this->generateId('location', 56);
3211
3212
        $userService = $this->getRepository()->getUserService();
3213
3214
        $newOwner = $this->createUser('new_owner', 'foo', 'bar');
3215
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $contentVersion2 */
3216
        $contentVersion2 = $this->createContentDraftVersion1(
3217
            $parentLocationId,
3218
            self::FORUM_IDENTIFIER,
3219
            'name',
3220
            $newOwner
3221
        );
3222
3223
        // Configure new target location
3224
        $targetLocationCreate = $this->locationService->newLocationCreateStruct($parentLocationId);
3225
3226
        $targetLocationCreate->priority = 42;
3227
        $targetLocationCreate->hidden = true;
3228
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3229
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3230
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3231
3232
        // Copy content with all versions and drafts
3233
        $contentCopied = $this->contentService->copyContent(
3234
            $contentVersion2->contentInfo,
3235
            $targetLocationCreate
3236
        );
3237
3238
        $this->assertEquals(
3239
            $newOwner->id,
3240
            $contentVersion2->contentInfo->ownerId
3241
        );
3242
        $this->assertEquals(
3243
            $userService->loadUserByLogin('admin')->getUserId(),
3244
            $contentCopied->contentInfo->ownerId
3245
        );
3246
    }
3247
3248
    /**
3249
     * Test for the copyContent() method.
3250
     *
3251
     * @see \eZ\Publish\API\Repository\ContentService::copyContent($contentInfo, $destinationLocationCreateStruct, $versionInfo)
3252
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
3253
     */
3254
    public function testCopyContentWithGivenVersion()
3255
    {
3256
        $parentLocationId = $this->generateId('location', 56);
3257
3258
        $contentVersion2 = $this->createContentVersion2();
3259
3260
        // Configure new target location
3261
        $targetLocationCreate = $this->locationService->newLocationCreateStruct($parentLocationId);
3262
3263
        $targetLocationCreate->priority = 42;
3264
        $targetLocationCreate->hidden = true;
3265
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3266
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3267
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3268
3269
        // Copy only the initial version
3270
        $contentCopied = $this->contentService->copyContent(
3271
            $contentVersion2->contentInfo,
3272
            $targetLocationCreate,
3273
            $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 1)
3274
        );
3275
3276
        $this->assertInstanceOf(
3277
            Content::class,
3278
            $contentCopied
3279
        );
3280
3281
        $this->assertNotEquals(
3282
            $contentVersion2->contentInfo->remoteId,
3283
            $contentCopied->contentInfo->remoteId
3284
        );
3285
3286
        $this->assertNotEquals(
3287
            $contentVersion2->id,
3288
            $contentCopied->id
3289
        );
3290
3291
        $this->assertEquals(
3292
            1,
3293
            count($this->contentService->loadVersions($contentCopied->contentInfo))
3294
        );
3295
3296
        $this->assertEquals(1, $contentCopied->getVersionInfo()->versionNo);
3297
3298
        $this->assertNotNull(
3299
            $contentCopied->contentInfo->mainLocationId,
3300
            'Expected main location to be set given we provided a LocationCreateStruct'
3301
        );
3302
    }
3303
3304
    /**
3305
     * Test for the addRelation() method.
3306
     *
3307
     * @return \eZ\Publish\API\Repository\Values\Content\Content
3308
     *
3309
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3310
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3311
     */
3312
    public function testAddRelation()
3313
    {
3314
        $draft = $this->createContentDraftVersion1();
3315
3316
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3317
3318
        // Create relation between new content object and "Media" page
3319
        $relation = $this->contentService->addRelation(
3320
            $draft->getVersionInfo(),
3321
            $media
3322
        );
3323
3324
        $this->assertInstanceOf(
3325
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Relation',
3326
            $relation
3327
        );
3328
3329
        return $this->contentService->loadRelations($draft->getVersionInfo());
3330
    }
3331
3332
    /**
3333
     * Test for the addRelation() method.
3334
     *
3335
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3336
     *
3337
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3338
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3339
     */
3340
    public function testAddRelationAddsRelationToContent($relations)
3341
    {
3342
        $this->assertEquals(
3343
            1,
3344
            count($relations)
3345
        );
3346
    }
3347
3348
    /**
3349
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3350
     */
3351
    protected function assertExpectedRelations($relations)
3352
    {
3353
        $this->assertEquals(
3354
            [
3355
                'type' => Relation::COMMON,
3356
                'sourceFieldDefinitionIdentifier' => null,
3357
                'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3358
                'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3359
            ],
3360
            [
3361
                'type' => $relations[0]->type,
3362
                'sourceFieldDefinitionIdentifier' => $relations[0]->sourceFieldDefinitionIdentifier,
3363
                'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3364
                'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3365
            ]
3366
        );
3367
    }
3368
3369
    /**
3370
     * Test for the addRelation() method.
3371
     *
3372
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3373
     *
3374
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3375
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3376
     */
3377
    public function testAddRelationSetsExpectedRelations($relations)
3378
    {
3379
        $this->assertExpectedRelations($relations);
3380
    }
3381
3382
    /**
3383
     * Test for the createContentDraft() method.
3384
     *
3385
     * @return \eZ\Publish\API\Repository\Values\Content\Relation[]
3386
     *
3387
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
3388
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelationSetsExpectedRelations
3389
     */
3390
    public function testCreateContentDraftWithRelations()
3391
    {
3392
        $draft = $this->createContentDraftVersion1();
3393
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3394
3395
        // Create relation between new content object and "Media" page
3396
        $this->contentService->addRelation(
3397
            $draft->getVersionInfo(),
3398
            $media
3399
        );
3400
3401
        $content = $this->contentService->publishVersion($draft->versionInfo);
3402
        $newDraft = $this->contentService->createContentDraft($content->contentInfo);
3403
3404
        return $this->contentService->loadRelations($newDraft->getVersionInfo());
3405
    }
3406
3407
    /**
3408
     * Test for the createContentDraft() method.
3409
     *
3410
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3411
     *
3412
     * @return \eZ\Publish\API\Repository\Values\Content\Relation[]
3413
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraftWithRelations
3414
     */
3415
    public function testCreateContentDraftWithRelationsCreatesRelations($relations)
3416
    {
3417
        $this->assertEquals(
3418
            1,
3419
            count($relations)
3420
        );
3421
3422
        return $relations;
3423
    }
3424
3425
    /**
3426
     * Test for the createContentDraft() method.
3427
     *
3428
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3429
     *
3430
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraftWithRelationsCreatesRelations
3431
     */
3432
    public function testCreateContentDraftWithRelationsCreatesExpectedRelations($relations)
3433
    {
3434
        $this->assertExpectedRelations($relations);
3435
    }
3436
3437
    /**
3438
     * Test for the addRelation() method.
3439
     *
3440
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3441
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3442
     */
3443
    public function testAddRelationThrowsBadStateException()
3444
    {
3445
        $content = $this->createContentVersion1();
3446
3447
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3448
3449
        $this->expectException(BadStateException::class);
3450
3451
        // This call will fail with a "BadStateException", because content is published and not a draft.
3452
        $this->contentService->addRelation(
3453
            $content->getVersionInfo(),
3454
            $media
3455
        );
3456
    }
3457
3458
    /**
3459
     * Test for the loadRelations() method.
3460
     *
3461
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3462
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3463
     */
3464
    public function testLoadRelations()
3465
    {
3466
        $draft = $this->createContentDraftVersion1();
3467
3468
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3469
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
3470
3471
        // Create relation between new content object and "Media" page
3472
        $this->contentService->addRelation(
3473
            $draft->getVersionInfo(),
3474
            $media
3475
        );
3476
3477
        // Create another relation with the "Demo Design" page
3478
        $this->contentService->addRelation(
3479
            $draft->getVersionInfo(),
3480
            $demoDesign
3481
        );
3482
3483
        $relations = $this->contentService->loadRelations($draft->getVersionInfo());
3484
3485
        usort(
3486
            $relations,
3487
            function ($rel1, $rel2) {
3488
                return strcasecmp(
3489
                    $rel2->getDestinationContentInfo()->remoteId,
3490
                    $rel1->getDestinationContentInfo()->remoteId
3491
                );
3492
            }
3493
        );
3494
3495
        $this->assertEquals(
3496
            [
3497
                [
3498
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3499
                    'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3500
                ],
3501
                [
3502
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3503
                    'destinationContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3504
                ],
3505
            ],
3506
            [
3507
                [
3508
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3509
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3510
                ],
3511
                [
3512
                    'sourceContentInfo' => $relations[1]->sourceContentInfo->remoteId,
3513
                    'destinationContentInfo' => $relations[1]->destinationContentInfo->remoteId,
3514
                ],
3515
            ]
3516
        );
3517
    }
3518
3519
    /**
3520
     * Test for the loadRelations() method.
3521
     *
3522
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3523
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3524
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
3525
     */
3526
    public function testLoadRelationsSkipsArchivedContent()
3527
    {
3528
        $trashService = $this->getRepository()->getTrashService();
3529
3530
        $draft = $this->createContentDraftVersion1();
3531
3532
        // Load other content objects
3533
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3534
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
3535
3536
        // Create relation between new content object and "Media" page
3537
        $this->contentService->addRelation(
3538
            $draft->getVersionInfo(),
3539
            $media
3540
        );
3541
3542
        // Create another relation with the "Demo Design" page
3543
        $this->contentService->addRelation(
3544
            $draft->getVersionInfo(),
3545
            $demoDesign
3546
        );
3547
3548
        $demoDesignLocation = $this->locationService->loadLocation($demoDesign->mainLocationId);
3549
3550
        // Trashing Content's last Location will change its status to archived,
3551
        // in this case relation towards it will not be loaded.
3552
        $trashService->trash($demoDesignLocation);
3553
3554
        // Load all relations
3555
        $relations = $this->contentService->loadRelations($draft->getVersionInfo());
3556
3557
        $this->assertCount(1, $relations);
3558
        $this->assertEquals(
3559
            [
3560
                [
3561
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3562
                    'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3563
                ],
3564
            ],
3565
            [
3566
                [
3567
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3568
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3569
                ],
3570
            ]
3571
        );
3572
    }
3573
3574
    /**
3575
     * Test for the loadRelations() method.
3576
     *
3577
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3578
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3579
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
3580
     */
3581
    public function testLoadRelationsSkipsDraftContent()
3582
    {
3583
        $draft = $this->createContentDraftVersion1();
3584
3585
        // Load other content objects
3586
        $media = $this->contentService->loadContentByRemoteId(self::MEDIA_REMOTE_ID);
3587
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
3588
3589
        // Create draft of "Media" page
3590
        $mediaDraft = $this->contentService->createContentDraft($media->contentInfo);
3591
3592
        // Create relation between "Media" page and new content object draft.
3593
        // This relation will not be loaded before the draft is published.
3594
        $this->contentService->addRelation(
3595
            $mediaDraft->getVersionInfo(),
3596
            $draft->getVersionInfo()->getContentInfo()
3597
        );
3598
3599
        // Create another relation with the "Demo Design" page
3600
        $this->contentService->addRelation(
3601
            $mediaDraft->getVersionInfo(),
3602
            $demoDesign
3603
        );
3604
3605
        $relations = $this->contentService->loadRelations($mediaDraft->getVersionInfo());
3606
3607
        $this->assertCount(1, $relations);
3608
        $this->assertEquals(
3609
            [
3610
                [
3611
                    'sourceContentInfo' => self::MEDIA_REMOTE_ID,
3612
                    'destinationContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3613
                ],
3614
            ],
3615
            [
3616
                [
3617
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3618
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3619
                ],
3620
            ]
3621
        );
3622
    }
3623
3624
    /**
3625
     * Test for the countReverseRelations() method.
3626
     *
3627
     * @covers \eZ\Publish\API\Repository\ContentService::countReverseRelations
3628
     */
3629
    public function testCountReverseRelations(): void
3630
    {
3631
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3632
            $this->contentService->createContentDraft(
3633
                $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3634
            ),
3635
            $this->contentService->createContentDraft(
3636
                $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3637
            ),
3638
        ]);
3639
3640
        $contentInfo = $contentWithReverseRelations->content->getVersionInfo()->getContentInfo();
3641
3642
        $this->assertEquals(2, $this->contentService->countReverseRelations($contentInfo));
3643
    }
3644
3645
    /**
3646
     * Test for the countReverseRelations() method.
3647
     *
3648
     * @covers \eZ\Publish\API\Repository\ContentService::countReverseRelations
3649
     */
3650
    public function testCountReverseRelationsReturnsZeroByDefault(): void
3651
    {
3652
        $draft = $this->createContentDraftVersion1();
3653
3654
        $this->assertSame(0, $this->contentService->countReverseRelations($draft->getVersionInfo()->getContentInfo()));
3655
    }
3656
3657
    /**
3658
     * Test for the countReverseRelations() method.
3659
     *
3660
     * @covers \eZ\Publish\API\Repository\ContentService::countReverseRelations
3661
     */
3662
    public function testCountReverseRelationsForUnauthorizedUser(): void
3663
    {
3664
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3665
            $this->contentService->createContentDraft(
3666
                $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3667
            ),
3668
        ]);
3669
        $mediaUser = $this->createMediaUserVersion1();
3670
        $this->permissionResolver->setCurrentUserReference($mediaUser);
3671
3672
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
3673
3674
        $this->assertSame(0, $this->contentService->countReverseRelations($contentInfo));
3675
    }
3676
3677
    /**
3678
     * Test for the loadReverseRelations() method.
3679
     *
3680
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3681
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3682
     */
3683
    public function testLoadReverseRelations()
3684
    {
3685
        $versionInfo = $this->createContentVersion1()->getVersionInfo();
3686
        $contentInfo = $versionInfo->getContentInfo();
3687
3688
        // Create some drafts
3689
        $mediaDraft = $this->contentService->createContentDraft(
3690
            $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID)
3691
        );
3692
        $demoDesignDraft = $this->contentService->createContentDraft(
3693
            $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID)
3694
        );
3695
3696
        // Create relation between new content object and "Media" page
3697
        $relation1 = $this->contentService->addRelation(
3698
            $mediaDraft->getVersionInfo(),
3699
            $contentInfo
3700
        );
3701
3702
        // Create another relation with the "Demo Design" page
3703
        $relation2 = $this->contentService->addRelation(
3704
            $demoDesignDraft->getVersionInfo(),
3705
            $contentInfo
3706
        );
3707
3708
        // Publish drafts, so relations become active
3709
        $this->contentService->publishVersion($mediaDraft->getVersionInfo());
3710
        $this->contentService->publishVersion($demoDesignDraft->getVersionInfo());
3711
3712
        $relations = $this->contentService->loadRelations($versionInfo);
3713
        $reverseRelations = $this->contentService->loadReverseRelations($contentInfo);
3714
3715
        $this->assertEquals($contentInfo->id, $relation1->getDestinationContentInfo()->id);
3716
        $this->assertEquals($mediaDraft->id, $relation1->getSourceContentInfo()->id);
3717
3718
        $this->assertEquals($contentInfo->id, $relation2->getDestinationContentInfo()->id);
3719
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3720
3721
        $this->assertEquals(0, count($relations));
3722
        $this->assertEquals(2, count($reverseRelations));
3723
3724
        usort(
3725
            $reverseRelations,
3726
            function ($rel1, $rel2) {
3727
                return strcasecmp(
3728
                    $rel2->getSourceContentInfo()->remoteId,
3729
                    $rel1->getSourceContentInfo()->remoteId
3730
                );
3731
            }
3732
        );
3733
3734
        $this->assertEquals(
3735
            [
3736
                [
3737
                    'sourceContentInfo' => self::MEDIA_REMOTE_ID,
3738
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3739
                ],
3740
                [
3741
                    'sourceContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3742
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3743
                ],
3744
            ],
3745
            [
3746
                [
3747
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3748
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3749
                ],
3750
                [
3751
                    'sourceContentInfo' => $reverseRelations[1]->sourceContentInfo->remoteId,
3752
                    'destinationContentInfo' => $reverseRelations[1]->destinationContentInfo->remoteId,
3753
                ],
3754
            ]
3755
        );
3756
    }
3757
3758
    /**
3759
     * Test for the loadReverseRelations() method.
3760
     *
3761
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3762
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3763
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadReverseRelations
3764
     */
3765
    public function testLoadReverseRelationsSkipsArchivedContent()
3766
    {
3767
        $trashService = $this->getRepository()->getTrashService();
3768
3769
        $versionInfo = $this->createContentVersion1()->getVersionInfo();
3770
        $contentInfo = $versionInfo->getContentInfo();
3771
3772
        // Create some drafts
3773
        $mediaDraft = $this->contentService->createContentDraft(
3774
            $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID)
3775
        );
3776
        $demoDesignDraft = $this->contentService->createContentDraft(
3777
            $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID)
3778
        );
3779
3780
        // Create relation between new content object and "Media" page
3781
        $relation1 = $this->contentService->addRelation(
3782
            $mediaDraft->getVersionInfo(),
3783
            $contentInfo
3784
        );
3785
3786
        // Create another relation with the "Demo Design" page
3787
        $relation2 = $this->contentService->addRelation(
3788
            $demoDesignDraft->getVersionInfo(),
3789
            $contentInfo
3790
        );
3791
3792
        // Publish drafts, so relations become active
3793
        $this->contentService->publishVersion($mediaDraft->getVersionInfo());
3794
        $this->contentService->publishVersion($demoDesignDraft->getVersionInfo());
3795
3796
        $demoDesignLocation = $this->locationService->loadLocation($demoDesignDraft->contentInfo->mainLocationId);
3797
3798
        // Trashing Content's last Location will change its status to archived,
3799
        // in this case relation from it will not be loaded.
3800
        $trashService->trash($demoDesignLocation);
3801
3802
        // Load all relations
3803
        $relations = $this->contentService->loadRelations($versionInfo);
3804
        $reverseRelations = $this->contentService->loadReverseRelations($contentInfo);
3805
3806
        $this->assertEquals($contentInfo->id, $relation1->getDestinationContentInfo()->id);
3807
        $this->assertEquals($mediaDraft->id, $relation1->getSourceContentInfo()->id);
3808
3809
        $this->assertEquals($contentInfo->id, $relation2->getDestinationContentInfo()->id);
3810
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3811
3812
        $this->assertEquals(0, count($relations));
3813
        $this->assertEquals(1, count($reverseRelations));
3814
3815
        $this->assertEquals(
3816
            [
3817
                [
3818
                    'sourceContentInfo' => self::MEDIA_REMOTE_ID,
3819
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3820
                ],
3821
            ],
3822
            [
3823
                [
3824
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3825
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3826
                ],
3827
            ]
3828
        );
3829
    }
3830
3831
    /**
3832
     * Test for the loadReverseRelations() method.
3833
     *
3834
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3835
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3836
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadReverseRelations
3837
     */
3838
    public function testLoadReverseRelationsSkipsDraftContent()
3839
    {
3840
        // Load "Media" page Content
3841
        $media = $this->contentService->loadContentByRemoteId(self::MEDIA_REMOTE_ID);
3842
3843
        // Create some drafts
3844
        $newDraftVersionInfo = $this->createContentDraftVersion1()->getVersionInfo();
3845
        $demoDesignDraft = $this->contentService->createContentDraft(
3846
            $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID)
3847
        );
3848
3849
        // Create relation between "Media" page and new content object
3850
        $relation1 = $this->contentService->addRelation(
3851
            $newDraftVersionInfo,
3852
            $media->contentInfo
3853
        );
3854
3855
        // Create another relation with the "Demo Design" page
3856
        $relation2 = $this->contentService->addRelation(
3857
            $demoDesignDraft->getVersionInfo(),
3858
            $media->contentInfo
3859
        );
3860
3861
        // Publish drafts, so relations become active
3862
        $this->contentService->publishVersion($demoDesignDraft->getVersionInfo());
3863
        // We will not publish new Content draft, therefore relation from it
3864
        // will not be loaded as reverse relation for "Media" page
3865
3866
        $relations = $this->contentService->loadRelations($media->versionInfo);
3867
        $reverseRelations = $this->contentService->loadReverseRelations($media->contentInfo);
3868
3869
        $this->assertEquals($media->contentInfo->id, $relation1->getDestinationContentInfo()->id);
3870
        $this->assertEquals($newDraftVersionInfo->contentInfo->id, $relation1->getSourceContentInfo()->id);
3871
3872
        $this->assertEquals($media->contentInfo->id, $relation2->getDestinationContentInfo()->id);
3873
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3874
3875
        $this->assertEquals(0, count($relations));
3876
        $this->assertEquals(1, count($reverseRelations));
3877
3878
        $this->assertEquals(
3879
            [
3880
                [
3881
                    'sourceContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3882
                    'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3883
                ],
3884
            ],
3885
            [
3886
                [
3887
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3888
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3889
                ],
3890
            ]
3891
        );
3892
    }
3893
3894
    /**
3895
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
3896
     */
3897
    public function testLoadReverseRelationList(): void
3898
    {
3899
        $draft1 = $this->contentService->createContentDraft(
3900
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3901
        );
3902
        $draft2 = $this->contentService->createContentDraft(
3903
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3904
        );
3905
        $draft3 = $this->contentService->createContentDraft(
3906
            $this->createFolder([self::ENG_GB => 'Baz'], 2)->contentInfo
3907
        );
3908
3909
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3910
            $draft1,
3911
            $draft2,
3912
            $draft3,
3913
        ]);
3914
3915
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
3916
3917
        $reverseRelationList = $this->contentService->loadReverseRelationList($contentInfo);
3918
3919
        $this->assertSame(3, $reverseRelationList->totalCount);
3920
        $this->assertEquals(
3921
            $contentWithReverseRelations->reverseRelations[2]->contentInfo,
3922
            $reverseRelationList->items[0]->getRelation()->sourceContentInfo
3923
        );
3924
        $this->assertEquals(
3925
            $contentWithReverseRelations->reverseRelations[1]->contentInfo,
3926
            $reverseRelationList->items[1]->getRelation()->sourceContentInfo
3927
        );
3928
        $this->assertEquals(
3929
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
3930
            $reverseRelationList->items[2]->getRelation()->sourceContentInfo
3931
        );
3932
    }
3933
3934
    /**
3935
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
3936
     */
3937
    public function testLoadReverseRelationListWithPagination(): void
3938
    {
3939
        $draft1 = $this->contentService->createContentDraft(
3940
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3941
        );
3942
        $draft2 = $this->contentService->createContentDraft(
3943
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3944
        );
3945
        $draft3 = $this->contentService->createContentDraft(
3946
            $this->createFolder([self::ENG_GB => 'Baz'], 2)->contentInfo
3947
        );
3948
3949
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3950
            $draft1,
3951
            $draft2,
3952
            $draft3,
3953
        ]);
3954
3955
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
3956
3957
        $reverseRelationPage1 = $this->contentService->loadReverseRelationList($contentInfo, 0, 2);
3958
        $reverseRelationPage2 = $this->contentService->loadReverseRelationList($contentInfo, 2, 2);
3959
        $this->assertSame(3, $reverseRelationPage1->totalCount);
3960
        $this->assertSame(3, $reverseRelationPage2->totalCount);
3961
        $this->assertEquals(
3962
            $contentWithReverseRelations->reverseRelations[2]->contentInfo,
3963
            $reverseRelationPage1->items[0]->getRelation()->sourceContentInfo
3964
        );
3965
        $this->assertEquals(
3966
            $contentWithReverseRelations->reverseRelations[1]->contentInfo,
3967
            $reverseRelationPage1->items[1]->getRelation()->sourceContentInfo
3968
        );
3969
        $this->assertEquals(
3970
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
3971
            $reverseRelationPage2->items[0]->getRelation()->sourceContentInfo
3972
        );
3973
    }
3974
3975
    /**
3976
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
3977
     */
3978
    public function testLoadReverseRelationListSkipsArchivedContent(): void
3979
    {
3980
        $trashService = $this->getRepository()->getTrashService();
3981
3982
        $draft1 = $this->contentService->createContentDraft(
3983
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3984
        );
3985
        $draft2 = $this->contentService->createContentDraft(
3986
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3987
        );
3988
        $draft3 = $this->contentService->createContentDraft(
3989
            $this->createFolder([self::ENG_GB => 'Baz'], 2)->contentInfo
3990
        );
3991
3992
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3993
            $draft1,
3994
            $draft2,
3995
            $draft3,
3996
        ]);
3997
3998
        $locationToTrash = $this->locationService->loadLocation($draft3->contentInfo->mainLocationId);
3999
4000
        // Trashing Content's last Location will change its status to archived, in this case relation from it will not be loaded.
4001
        $trashService->trash($locationToTrash);
4002
4003
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
4004
        $reverseRelationList = $this->contentService->loadReverseRelationList($contentInfo);
4005
4006
        $this->assertSame(2, $reverseRelationList->totalCount);
4007
        $this->assertEquals(
4008
            $contentWithReverseRelations->reverseRelations[1]->contentInfo,
4009
            $reverseRelationList->items[0]->getRelation()->sourceContentInfo
4010
        );
4011
        $this->assertEquals(
4012
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
4013
            $reverseRelationList->items[1]->getRelation()->sourceContentInfo
4014
        );
4015
    }
4016
4017
    /**
4018
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
4019
     */
4020
    public function testLoadReverseRelationListSkipsDraftContent()
4021
    {
4022
        $draft1 = $this->contentService->createContentDraft(
4023
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
4024
        );
4025
4026
        $contentWithReverseRelations = $this->createContentWithReverseRelations([$draft1]);
4027
4028
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
4029
4030
        // create a relation, but without publishing it
4031
        $draft2 = $this->contentService->createContentDraft(
4032
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
4033
        );
4034
        $this->contentService->addRelation(
4035
            $draft2->getVersionInfo(),
4036
            $contentInfo
4037
        );
4038
4039
        $reverseRelationList = $this->contentService->loadReverseRelationList($contentInfo);
4040
4041
        $this->assertSame(1, $reverseRelationList->totalCount);
4042
        $this->assertEquals(
4043
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
4044
            $reverseRelationList->items[0]->getRelation()->sourceContentInfo
4045
        );
4046
    }
4047
4048
    /**
4049
     * Test for the deleteRelation() method.
4050
     *
4051
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4052
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
4053
     */
4054
    public function testDeleteRelation()
4055
    {
4056
        $draft = $this->createContentDraftVersion1();
4057
4058
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
4059
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
4060
4061
        // Establish some relations
4062
        $this->contentService->addRelation($draft->getVersionInfo(), $media);
4063
        $this->contentService->addRelation($draft->getVersionInfo(), $demoDesign);
4064
4065
        // Delete one of the currently created relations
4066
        $this->contentService->deleteRelation($draft->getVersionInfo(), $media);
4067
4068
        // The relations array now contains only one element
4069
        $relations = $this->contentService->loadRelations($draft->getVersionInfo());
4070
4071
        $this->assertEquals(1, count($relations));
4072
    }
4073
4074
    /**
4075
     * Test for the deleteRelation() method.
4076
     *
4077
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4078
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteRelation
4079
     */
4080
    public function testDeleteRelationThrowsBadStateException()
4081
    {
4082
        $content = $this->createContentVersion1();
4083
4084
        // Load the destination object
4085
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
4086
4087
        // Create a new draft
4088
        $draftVersion2 = $this->contentService->createContentDraft($content->contentInfo);
4089
4090
        // Add a relation
4091
        $this->contentService->addRelation($draftVersion2->getVersionInfo(), $media);
4092
4093
        // Publish new version
4094
        $contentVersion2 = $this->contentService->publishVersion(
4095
            $draftVersion2->getVersionInfo()
4096
        );
4097
4098
        $this->expectException(BadStateException::class);
4099
4100
        // This call will fail with a "BadStateException", because content is published and not a draft.
4101
        $this->contentService->deleteRelation(
4102
            $contentVersion2->getVersionInfo(),
4103
            $media
4104
        );
4105
    }
4106
4107
    /**
4108
     * Test for the deleteRelation() method.
4109
     *
4110
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4111
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteRelation
4112
     */
4113
    public function testDeleteRelationThrowsInvalidArgumentException()
4114
    {
4115
        $draft = $this->createContentDraftVersion1();
4116
4117
        // Load the destination object
4118
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
4119
4120
        // This call will fail with a "InvalidArgumentException", because no relation exists between $draft and $media.
4121
        $this->expectException(APIInvalidArgumentException::class);
4122
        $this->contentService->deleteRelation(
4123
            $draft->getVersionInfo(),
4124
            $media
4125
        );
4126
    }
4127
4128
    /**
4129
     * Test for the createContent() method.
4130
     *
4131
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
4132
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4133
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4134
     */
4135
    public function testCreateContentInTransactionWithRollback()
4136
    {
4137
        if ($this->isVersion4()) {
4138
            $this->markTestSkipped('This test requires eZ Publish 5');
4139
        }
4140
4141
        $repository = $this->getRepository();
4142
4143
        $contentTypeService = $this->getRepository()->getContentTypeService();
4144
4145
        // Start a transaction
4146
        $repository->beginTransaction();
4147
4148
        try {
4149
            $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
4150
4151
            // Get a content create struct and set mandatory properties
4152
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
4153
            $contentCreate->setField('name', 'Sindelfingen forum');
4154
4155
            $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
4156
            $contentCreate->alwaysAvailable = true;
4157
4158
            // Create a new content object
4159
            $contentId = $this->contentService->createContent($contentCreate)->id;
4160
        } catch (Exception $e) {
4161
            // Cleanup hanging transaction on error
4162
            $repository->rollback();
4163
            throw $e;
4164
        }
4165
4166
        // Rollback all changes
4167
        $repository->rollback();
4168
4169
        try {
4170
            // This call will fail with a "NotFoundException"
4171
            $this->contentService->loadContent($contentId);
4172
        } catch (NotFoundException $e) {
4173
            // This is expected
4174
            return;
4175
        }
4176
4177
        $this->fail('Content object still exists after rollback.');
4178
    }
4179
4180
    /**
4181
     * Test for the createContent() method.
4182
     *
4183
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
4184
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4185
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4186
     */
4187
    public function testCreateContentInTransactionWithCommit()
4188
    {
4189
        if ($this->isVersion4()) {
4190
            $this->markTestSkipped('This test requires eZ Publish 5');
4191
        }
4192
4193
        $repository = $this->getRepository();
4194
4195
        $contentTypeService = $repository->getContentTypeService();
4196
4197
        // Start a transaction
4198
        $repository->beginTransaction();
4199
4200
        try {
4201
            $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
4202
4203
            // Get a content create struct and set mandatory properties
4204
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
4205
            $contentCreate->setField('name', 'Sindelfingen forum');
4206
4207
            $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
4208
            $contentCreate->alwaysAvailable = true;
4209
4210
            // Create a new content object
4211
            $contentId = $this->contentService->createContent($contentCreate)->id;
4212
4213
            // Commit changes
4214
            $repository->commit();
4215
        } catch (Exception $e) {
4216
            // Cleanup hanging transaction on error
4217
            $repository->rollback();
4218
            throw $e;
4219
        }
4220
4221
        // Load the new content object
4222
        $content = $this->contentService->loadContent($contentId);
4223
4224
        $this->assertEquals($contentId, $content->id);
4225
    }
4226
4227
    /**
4228
     * Test for the createContent() method.
4229
     *
4230
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
4231
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
4232
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentThrowsNotFoundException
4233
     */
4234
    public function testCreateContentWithLocationCreateParameterInTransactionWithRollback()
4235
    {
4236
        $repository = $this->getRepository();
4237
4238
        // Start a transaction
4239
        $repository->beginTransaction();
4240
4241
        try {
4242
            $draft = $this->createContentDraftVersion1();
4243
        } catch (Exception $e) {
4244
            // Cleanup hanging transaction on error
4245
            $repository->rollback();
4246
            throw $e;
4247
        }
4248
4249
        $contentId = $draft->id;
4250
4251
        // Roleback the transaction
4252
        $repository->rollback();
4253
4254
        try {
4255
            // This call will fail with a "NotFoundException"
4256
            $this->contentService->loadContent($contentId);
4257
        } catch (NotFoundException $e) {
4258
            return;
4259
        }
4260
4261
        $this->fail('Can still load content object after rollback.');
4262
    }
4263
4264
    /**
4265
     * Test for the createContent() method.
4266
     *
4267
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
4268
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
4269
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentThrowsNotFoundException
4270
     */
4271
    public function testCreateContentWithLocationCreateParameterInTransactionWithCommit()
4272
    {
4273
        $repository = $this->getRepository();
4274
4275
        // Start a transaction
4276
        $repository->beginTransaction();
4277
4278
        try {
4279
            $draft = $this->createContentDraftVersion1();
4280
4281
            $contentId = $draft->id;
4282
4283
            // Roleback the transaction
4284
            $repository->commit();
4285
        } catch (Exception $e) {
4286
            // Cleanup hanging transaction on error
4287
            $repository->rollback();
4288
            throw $e;
4289
        }
4290
4291
        // Load the new content object
4292
        $content = $this->contentService->loadContent($contentId);
4293
4294
        $this->assertEquals($contentId, $content->id);
4295
    }
4296
4297
    /**
4298
     * Test for the createContentDraft() method.
4299
     *
4300
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
4301
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
4302
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4303
     */
4304
    public function testCreateContentDraftInTransactionWithRollback()
4305
    {
4306
        $repository = $this->getRepository();
4307
4308
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4309
4310
        // Load the user group content object
4311
        $content = $this->contentService->loadContent($contentId);
4312
4313
        // Start a new transaction
4314
        $repository->beginTransaction();
4315
4316
        try {
4317
            // Create a new draft
4318
            $drafted = $this->contentService->createContentDraft($content->contentInfo);
4319
4320
            // Store version number for later reuse
4321
            $versionNo = $drafted->versionInfo->versionNo;
4322
        } catch (Exception $e) {
4323
            // Cleanup hanging transaction on error
4324
            $repository->rollback();
4325
            throw $e;
4326
        }
4327
4328
        // Rollback
4329
        $repository->rollback();
4330
4331
        try {
4332
            // This call will fail with a "NotFoundException"
4333
            $this->contentService->loadContent($contentId, null, $versionNo);
4334
        } catch (NotFoundException $e) {
4335
            return;
4336
        }
4337
4338
        $this->fail('Can still load content draft after rollback');
4339
    }
4340
4341
    /**
4342
     * Test for the createContentDraft() method.
4343
     *
4344
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
4345
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
4346
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4347
     */
4348
    public function testCreateContentDraftInTransactionWithCommit()
4349
    {
4350
        $repository = $this->getRepository();
4351
4352
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4353
4354
        // Load the user group content object
4355
        $content = $this->contentService->loadContent($contentId);
4356
4357
        // Start a new transaction
4358
        $repository->beginTransaction();
4359
4360
        try {
4361
            // Create a new draft
4362
            $drafted = $this->contentService->createContentDraft($content->contentInfo);
4363
4364
            // Store version number for later reuse
4365
            $versionNo = $drafted->versionInfo->versionNo;
4366
4367
            // Commit all changes
4368
            $repository->commit();
4369
        } catch (Exception $e) {
4370
            // Cleanup hanging transaction on error
4371
            $repository->rollback();
4372
            throw $e;
4373
        }
4374
4375
        $content = $this->contentService->loadContent($contentId, null, $versionNo);
4376
4377
        $this->assertEquals(
4378
            $versionNo,
4379
            $content->getVersionInfo()->versionNo
4380
        );
4381
    }
4382
4383
    /**
4384
     * Test for the publishVersion() method.
4385
     *
4386
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
4387
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
4388
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4389
     */
4390
    public function testPublishVersionInTransactionWithRollback()
4391
    {
4392
        $repository = $this->getRepository();
4393
4394
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4395
4396
        // Load the user group content object
4397
        $content = $this->contentService->loadContent($contentId);
4398
4399
        // Start a new transaction
4400
        $repository->beginTransaction();
4401
4402
        try {
4403
            $draftVersion = $this->contentService->createContentDraft($content->contentInfo)->getVersionInfo();
4404
4405
            // Publish a new version
4406
            $content = $this->contentService->publishVersion($draftVersion);
4407
4408
            // Store version number for later reuse
4409
            $versionNo = $content->versionInfo->versionNo;
4410
        } catch (Exception $e) {
4411
            // Cleanup hanging transaction on error
4412
            $repository->rollback();
4413
            throw $e;
4414
        }
4415
4416
        // Rollback
4417
        $repository->rollback();
4418
4419
        try {
4420
            // This call will fail with a "NotFoundException"
4421
            $this->contentService->loadContent($contentId, null, $versionNo);
4422
        } catch (NotFoundException $e) {
4423
            return;
4424
        }
4425
4426
        $this->fail('Can still load content draft after rollback');
4427
    }
4428
4429
    /**
4430
     * Test for the publishVersion() method.
4431
     *
4432
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
4433
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
4434
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
4435
     */
4436
    public function testPublishVersionInTransactionWithCommit()
4437
    {
4438
        $repository = $this->getRepository();
4439
4440
        // Load the user group content object
4441
        $template = $this->contentService->loadContent(self::ADMINISTRATORS_USER_GROUP_ID);
4442
4443
        // Start a new transaction
4444
        $repository->beginTransaction();
4445
4446
        try {
4447
            // Publish a new version
4448
            $content = $this->contentService->publishVersion(
4449
                $this->contentService->createContentDraft($template->contentInfo)->getVersionInfo()
4450
            );
4451
4452
            // Store version number for later reuse
4453
            $versionNo = $content->versionInfo->versionNo;
4454
4455
            // Commit all changes
4456
            $repository->commit();
4457
        } catch (Exception $e) {
4458
            // Cleanup hanging transaction on error
4459
            $repository->rollback();
4460
            throw $e;
4461
        }
4462
4463
        // Load current version info
4464
        $versionInfo = $this->contentService->loadVersionInfo($content->contentInfo);
4465
4466
        $this->assertEquals($versionNo, $versionInfo->versionNo);
4467
    }
4468
4469
    /**
4470
     * Test for the updateContent() method.
4471
     *
4472
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
4473
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
4474
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4475
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4476
     */
4477
    public function testUpdateContentInTransactionWithRollback()
4478
    {
4479
        $repository = $this->getRepository();
4480
4481
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4482
4483
        // Create a new user group draft
4484
        $draft = $this->contentService->createContentDraft(
4485
            $this->contentService->loadContentInfo($contentId)
4486
        );
4487
4488
        // Get an update struct and change the group name
4489
        $contentUpdate = $this->contentService->newContentUpdateStruct();
4490
        $contentUpdate->setField('name', self::ADMINISTRATORS_USER_GROUP_NAME, self::ENG_US);
4491
4492
        // Start a transaction
4493
        $repository->beginTransaction();
4494
4495
        try {
4496
            // Update the group name
4497
            $draft = $this->contentService->updateContent(
4498
                $draft->getVersionInfo(),
4499
                $contentUpdate
4500
            );
4501
4502
            // Publish updated version
4503
            $this->contentService->publishVersion($draft->getVersionInfo());
4504
        } catch (Exception $e) {
4505
            // Cleanup hanging transaction on error
4506
            $repository->rollback();
4507
            throw $e;
4508
        }
4509
4510
        // Rollback all changes.
4511
        $repository->rollback();
4512
4513
        // Name will still be "Administrator users"
4514
        $name = $this->contentService->loadContent($contentId)->getFieldValue('name');
4515
4516
        $this->assertEquals('Administrator users', $name);
4517
    }
4518
4519
    /**
4520
     * Test for the updateContent() method.
4521
     *
4522
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
4523
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
4524
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4525
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4526
     */
4527
    public function testUpdateContentInTransactionWithCommit()
4528
    {
4529
        $repository = $this->getRepository();
4530
4531
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4532
4533
        // Create a new user group draft
4534
        $draft = $this->contentService->createContentDraft(
4535
            $this->contentService->loadContentInfo($contentId)
4536
        );
4537
4538
        // Get an update struct and change the group name
4539
        $contentUpdate = $this->contentService->newContentUpdateStruct();
4540
        $contentUpdate->setField('name', self::ADMINISTRATORS_USER_GROUP_NAME, self::ENG_US);
4541
4542
        // Start a transaction
4543
        $repository->beginTransaction();
4544
4545
        try {
4546
            // Update the group name
4547
            $draft = $this->contentService->updateContent(
4548
                $draft->getVersionInfo(),
4549
                $contentUpdate
4550
            );
4551
4552
            // Publish updated version
4553
            $this->contentService->publishVersion($draft->getVersionInfo());
4554
4555
            // Commit all changes.
4556
            $repository->commit();
4557
        } catch (Exception $e) {
4558
            // Cleanup hanging transaction on error
4559
            $repository->rollback();
4560
            throw $e;
4561
        }
4562
4563
        // Name is now "Administrators"
4564
        $name = $this->contentService->loadContent($contentId)->getFieldValue('name', self::ENG_US);
4565
4566
        $this->assertEquals(self::ADMINISTRATORS_USER_GROUP_NAME, $name);
4567
    }
4568
4569
    /**
4570
     * Test for the updateContentMetadata() method.
4571
     *
4572
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4573
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
4574
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4575
     */
4576
    public function testUpdateContentMetadataInTransactionWithRollback()
4577
    {
4578
        $repository = $this->getRepository();
4579
4580
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4581
4582
        // Load a ContentInfo object
4583
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4584
4585
        // Store remoteId for later testing
4586
        $remoteId = $contentInfo->remoteId;
4587
4588
        // Start a transaction
4589
        $repository->beginTransaction();
4590
4591
        try {
4592
            // Get metadata update struct and change remoteId
4593
            $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
4594
            $metadataUpdate->remoteId = md5(microtime(true));
4595
4596
            // Update the metadata of the published content object
4597
            $this->contentService->updateContentMetadata(
4598
                $contentInfo,
4599
                $metadataUpdate
4600
            );
4601
        } catch (Exception $e) {
4602
            // Cleanup hanging transaction on error
4603
            $repository->rollback();
4604
            throw $e;
4605
        }
4606
4607
        // Rollback all changes.
4608
        $repository->rollback();
4609
4610
        // Load current remoteId
4611
        $remoteIdReloaded = $this->contentService->loadContentInfo($contentId)->remoteId;
4612
4613
        $this->assertEquals($remoteId, $remoteIdReloaded);
4614
    }
4615
4616
    /**
4617
     * Test for the updateContentMetadata() method.
4618
     *
4619
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4620
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
4621
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4622
     */
4623
    public function testUpdateContentMetadataInTransactionWithCommit()
4624
    {
4625
        $repository = $this->getRepository();
4626
4627
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4628
4629
        // Load a ContentInfo object
4630
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4631
4632
        // Store remoteId for later testing
4633
        $remoteId = $contentInfo->remoteId;
4634
4635
        // Start a transaction
4636
        $repository->beginTransaction();
4637
4638
        try {
4639
            // Get metadata update struct and change remoteId
4640
            $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
4641
            $metadataUpdate->remoteId = md5(microtime(true));
4642
4643
            // Update the metadata of the published content object
4644
            $this->contentService->updateContentMetadata(
4645
                $contentInfo,
4646
                $metadataUpdate
4647
            );
4648
4649
            // Commit all changes.
4650
            $repository->commit();
4651
        } catch (Exception $e) {
4652
            // Cleanup hanging transaction on error
4653
            $repository->rollback();
4654
            throw $e;
4655
        }
4656
4657
        // Load current remoteId
4658
        $remoteIdReloaded = $this->contentService->loadContentInfo($contentId)->remoteId;
4659
4660
        $this->assertNotEquals($remoteId, $remoteIdReloaded);
4661
    }
4662
4663
    /**
4664
     * Test for the updateContentMetadata() method, and how cache + transactions play together.
4665
     *
4666
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4667
     * @depends testUpdateContentMetadata
4668
     * @depends testLoadContentInfo
4669
     */
4670
    public function testUpdateContentMetadataCheckWithinTransaction()
4671
    {
4672
        $repository = $this->getRepository();
4673
        $contentService = $repository->getContentService();
4674
        $contentId = $this->generateId('object', 12);
4675
4676
        // Load a ContentInfo object, and warmup cache
4677
        $contentInfo = $contentService->loadContentInfo($contentId);
4678
4679
        // Store remoteId for later testing
4680
        $remoteId = $contentInfo->remoteId;
4681
4682
        // Start a transaction
4683
        $repository->beginTransaction();
4684
4685
        try {
4686
            // Get metadata update struct and change remoteId
4687
            $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
4688
            $metadataUpdate->remoteId = md5(microtime(true));
4689
4690
            // Update the metadata of the published content object
4691
            $contentService->updateContentMetadata(
4692
                $contentInfo,
4693
                $metadataUpdate
4694
            );
4695
4696
            // Check that it's been updated
4697
            $remoteIdReloaded = $contentService->loadContentInfo($contentId)->remoteId;
4698
            $this->assertNotEquals($remoteId, $remoteIdReloaded);
4699
4700
            // Commit all changes.
4701
            $repository->commit();
4702
        } catch (Exception $e) {
4703
            // Cleanup hanging transaction on error
4704
            $repository->rollback();
4705
            throw $e;
4706
        }
4707
    }
4708
4709
    /**
4710
     * Test for the deleteVersion() method.
4711
     *
4712
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4713
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4714
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4715
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4716
     */
4717
    public function testDeleteVersionInTransactionWithRollback()
4718
    {
4719
        $repository = $this->getRepository();
4720
4721
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4722
4723
        // Start a new transaction
4724
        $repository->beginTransaction();
4725
4726
        try {
4727
            // Create a new draft
4728
            $draft = $this->contentService->createContentDraft(
4729
                $this->contentService->loadContentInfo($contentId)
4730
            );
4731
4732
            $this->contentService->deleteVersion($draft->getVersionInfo());
4733
        } catch (Exception $e) {
4734
            // Cleanup hanging transaction on error
4735
            $repository->rollback();
4736
            throw $e;
4737
        }
4738
4739
        // Rollback all changes.
4740
        $repository->rollback();
4741
4742
        // This array will be empty
4743
        $drafts = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

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...
4744
4745
        $this->assertSame([], $drafts);
4746
    }
4747
4748
    /**
4749
     * Test for the deleteVersion() method.
4750
     *
4751
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4752
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4753
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4754
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4755
     */
4756
    public function testDeleteVersionInTransactionWithCommit()
4757
    {
4758
        $repository = $this->getRepository();
4759
4760
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4761
4762
        // Start a new transaction
4763
        $repository->beginTransaction();
4764
4765
        try {
4766
            // Create a new draft
4767
            $draft = $this->contentService->createContentDraft(
4768
                $this->contentService->loadContentInfo($contentId)
4769
            );
4770
4771
            $this->contentService->deleteVersion($draft->getVersionInfo());
4772
4773
            // Commit all changes.
4774
            $repository->commit();
4775
        } catch (Exception $e) {
4776
            // Cleanup hanging transaction on error
4777
            $repository->rollback();
4778
            throw $e;
4779
        }
4780
4781
        // This array will contain no element
4782
        $drafts = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

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...
4783
4784
        $this->assertSame([], $drafts);
4785
    }
4786
4787
    /**
4788
     * Test for the deleteContent() method.
4789
     *
4790
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
4791
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteContent
4792
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4793
     */
4794
    public function testDeleteContentInTransactionWithRollback()
4795
    {
4796
        $repository = $this->getRepository();
4797
4798
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4799
4800
        // Load a ContentInfo instance
4801
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4802
4803
        // Start a new transaction
4804
        $repository->beginTransaction();
4805
4806
        try {
4807
            // Delete content object
4808
            $this->contentService->deleteContent($contentInfo);
4809
        } catch (Exception $e) {
4810
            // Cleanup hanging transaction on error
4811
            $repository->rollback();
4812
            throw $e;
4813
        }
4814
4815
        // Rollback all changes
4816
        $repository->rollback();
4817
4818
        // This call will return the original content object
4819
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4820
4821
        $this->assertEquals($contentId, $contentInfo->id);
4822
    }
4823
4824
    /**
4825
     * Test for the deleteContent() method.
4826
     *
4827
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
4828
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteContent
4829
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4830
     */
4831
    public function testDeleteContentInTransactionWithCommit()
4832
    {
4833
        $repository = $this->getRepository();
4834
4835
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4836
4837
        // Load a ContentInfo instance
4838
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4839
4840
        // Start a new transaction
4841
        $repository->beginTransaction();
4842
4843
        try {
4844
            // Delete content object
4845
            $this->contentService->deleteContent($contentInfo);
4846
4847
            // Commit all changes
4848
            $repository->commit();
4849
        } catch (Exception $e) {
4850
            // Cleanup hanging transaction on error
4851
            $repository->rollback();
4852
            throw $e;
4853
        }
4854
4855
        // Deleted content info is not found anymore
4856
        try {
4857
            $this->contentService->loadContentInfo($contentId);
4858
        } catch (NotFoundException $e) {
4859
            return;
4860
        }
4861
4862
        $this->fail('Can still load ContentInfo after commit.');
4863
    }
4864
4865
    /**
4866
     * Test for the copyContent() method.
4867
     *
4868
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
4869
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
4870
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
4871
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
4872
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
4873
     */
4874
    public function testCopyContentInTransactionWithRollback()
4875
    {
4876
        $repository = $this->getRepository();
4877
4878
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4879
        $locationId = $this->generateId('location', self::ADMINISTRATORS_USER_GROUP_LOCATION_ID);
4880
4881
        // Load content object to copy
4882
        $content = $this->contentService->loadContent($contentId);
4883
4884
        // Create new target location
4885
        $locationCreate = $this->locationService->newLocationCreateStruct($locationId);
4886
4887
        // Start a new transaction
4888
        $repository->beginTransaction();
4889
4890
        try {
4891
            // Copy content with all versions and drafts
4892
            $this->contentService->copyContent(
4893
                $content->contentInfo,
4894
                $locationCreate
4895
            );
4896
        } catch (Exception $e) {
4897
            // Cleanup hanging transaction on error
4898
            $repository->rollback();
4899
            throw $e;
4900
        }
4901
4902
        // Rollback all changes
4903
        $repository->rollback();
4904
4905
        $this->refreshSearch($repository);
4906
4907
        // This array will only contain a single admin user object
4908
        $locations = $this->locationService->loadLocationChildren(
4909
            $this->locationService->loadLocation($locationId)
4910
        )->locations;
4911
4912
        $this->assertEquals(1, count($locations));
4913
    }
4914
4915
    /**
4916
     * Test for the copyContent() method.
4917
     *
4918
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
4919
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
4920
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
4921
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
4922
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
4923
     */
4924
    public function testCopyContentInTransactionWithCommit()
4925
    {
4926
        $repository = $this->getRepository();
4927
4928
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4929
        $locationId = $this->generateId('location', self::ADMINISTRATORS_USER_GROUP_LOCATION_ID);
4930
4931
        // Load content object to copy
4932
        $content = $this->contentService->loadContent($contentId);
4933
4934
        // Create new target location
4935
        $locationCreate = $this->locationService->newLocationCreateStruct($locationId);
4936
4937
        // Start a new transaction
4938
        $repository->beginTransaction();
4939
4940
        try {
4941
            // Copy content with all versions and drafts
4942
            $this->contentService->copyContent(
4943
                $content->contentInfo,
4944
                $locationCreate
4945
            );
4946
4947
            // Commit all changes
4948
            $repository->commit();
4949
        } catch (Exception $e) {
4950
            // Cleanup hanging transaction on error
4951
            $repository->rollback();
4952
            throw $e;
4953
        }
4954
4955
        $this->refreshSearch($repository);
4956
4957
        // This will contain the admin user and the new child location
4958
        $locations = $this->locationService->loadLocationChildren(
4959
            $this->locationService->loadLocation($locationId)
4960
        )->locations;
4961
4962
        $this->assertEquals(2, count($locations));
4963
    }
4964
4965
    public function testURLAliasesCreatedForNewContent()
4966
    {
4967
        $urlAliasService = $this->getRepository()->getURLAliasService();
4968
4969
        $draft = $this->createContentDraftVersion1();
4970
4971
        // Automatically creates a new URLAlias for the content
4972
        $liveContent = $this->contentService->publishVersion($draft->getVersionInfo());
4973
4974
        $location = $this->locationService->loadLocation(
4975
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
4976
        );
4977
4978
        $aliases = $urlAliasService->listLocationAliases($location, false);
4979
4980
        $this->assertAliasesCorrect(
4981
            [
4982
                '/Design/Plain-site/An-awesome-forum' => [
4983
                    'type' => URLAlias::LOCATION,
4984
                    'destination' => $location->id,
4985
                    'path' => '/Design/Plain-site/An-awesome-forum',
4986
                    'languageCodes' => [self::ENG_US],
4987
                    'isHistory' => false,
4988
                    'isCustom' => false,
4989
                    'forward' => false,
4990
                ],
4991
            ],
4992
            $aliases
4993
        );
4994
    }
4995
4996
    public function testURLAliasesCreatedForUpdatedContent()
4997
    {
4998
        $urlAliasService = $this->getRepository()->getURLAliasService();
4999
5000
        $draft = $this->createUpdatedDraftVersion2();
5001
5002
        $location = $this->locationService->loadLocation(
5003
            $draft->getVersionInfo()->getContentInfo()->mainLocationId
5004
        );
5005
5006
        // Load and assert URL aliases before publishing updated Content, so that
5007
        // SPI cache is warmed up and cache invalidation is also tested.
5008
        $aliases = $urlAliasService->listLocationAliases($location, false);
5009
5010
        $this->assertAliasesCorrect(
5011
            [
5012
                '/Design/Plain-site/An-awesome-forum' => [
5013
                    'type' => URLAlias::LOCATION,
5014
                    'destination' => $location->id,
5015
                    'path' => '/Design/Plain-site/An-awesome-forum',
5016
                    'languageCodes' => [self::ENG_US],
5017
                    'alwaysAvailable' => true,
5018
                    'isHistory' => false,
5019
                    'isCustom' => false,
5020
                    'forward' => false,
5021
                ],
5022
            ],
5023
            $aliases
5024
        );
5025
5026
        // Automatically marks old aliases for the content as history
5027
        // and creates new aliases, based on the changes
5028
        $liveContent = $this->contentService->publishVersion($draft->getVersionInfo());
5029
5030
        $location = $this->locationService->loadLocation(
5031
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5032
        );
5033
5034
        $aliases = $urlAliasService->listLocationAliases($location, false);
5035
5036
        $this->assertAliasesCorrect(
5037
            [
5038
                '/Design/Plain-site/An-awesome-forum2' => [
5039
                    'type' => URLAlias::LOCATION,
5040
                    'destination' => $location->id,
5041
                    'path' => '/Design/Plain-site/An-awesome-forum2',
5042
                    'languageCodes' => [self::ENG_US],
5043
                    'alwaysAvailable' => true,
5044
                    'isHistory' => false,
5045
                    'isCustom' => false,
5046
                    'forward' => false,
5047
                ],
5048
                '/Design/Plain-site/An-awesome-forum23' => [
5049
                    'type' => URLAlias::LOCATION,
5050
                    'destination' => $location->id,
5051
                    'path' => '/Design/Plain-site/An-awesome-forum23',
5052
                    'languageCodes' => [self::ENG_GB],
5053
                    'alwaysAvailable' => true,
5054
                    'isHistory' => false,
5055
                    'isCustom' => false,
5056
                    'forward' => false,
5057
                ],
5058
            ],
5059
            $aliases
5060
        );
5061
    }
5062
5063
    public function testCustomURLAliasesNotHistorizedOnUpdatedContent()
5064
    {
5065
        $urlAliasService = $this->getRepository()->getURLAliasService();
5066
5067
        $content = $this->createContentVersion1();
5068
5069
        // Create a custom URL alias
5070
        $urlAliasService->createUrlAlias(
5071
            $this->locationService->loadLocation(
5072
                $content->getVersionInfo()->getContentInfo()->mainLocationId
5073
            ),
5074
            '/my/fancy/story-about-ez-publish',
5075
            self::ENG_US
5076
        );
5077
5078
        $draftVersion2 = $this->contentService->createContentDraft($content->contentInfo);
5079
5080
        $contentUpdate = $this->contentService->newContentUpdateStruct();
5081
        $contentUpdate->initialLanguageCode = self::ENG_US;
5082
        $contentUpdate->setField('name', 'Amazing Bielefeld forum');
5083
5084
        $draftVersion2 = $this->contentService->updateContent(
5085
            $draftVersion2->getVersionInfo(),
5086
            $contentUpdate
5087
        );
5088
5089
        // Only marks auto-generated aliases as history
5090
        // the custom one is left untouched
5091
        $liveContent = $this->contentService->publishVersion($draftVersion2->getVersionInfo());
5092
5093
        $location = $this->locationService->loadLocation(
5094
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5095
        );
5096
5097
        $aliases = $urlAliasService->listLocationAliases($location);
5098
5099
        $this->assertAliasesCorrect(
5100
            [
5101
                '/my/fancy/story-about-ez-publish' => [
5102
                    'type' => URLAlias::LOCATION,
5103
                    'destination' => $location->id,
5104
                    'path' => '/my/fancy/story-about-ez-publish',
5105
                    'languageCodes' => [self::ENG_US],
5106
                    'isHistory' => false,
5107
                    'isCustom' => true,
5108
                    'forward' => false,
5109
                    'alwaysAvailable' => false,
5110
                ],
5111
            ],
5112
            $aliases
5113
        );
5114
    }
5115
5116
    /**
5117
     * Test to ensure that old versions are not affected by updates to newer
5118
     * drafts.
5119
     */
5120
    public function testUpdatingDraftDoesNotUpdateOldVersions()
5121
    {
5122
        $contentVersion2 = $this->createContentVersion2();
5123
5124
        $loadedContent1 = $this->contentService->loadContent($contentVersion2->id, null, 1);
5125
        $loadedContent2 = $this->contentService->loadContent($contentVersion2->id, null, 2);
5126
5127
        $this->assertNotEquals(
5128
            $loadedContent1->getFieldValue('name', self::ENG_US),
5129
            $loadedContent2->getFieldValue('name', self::ENG_US)
5130
        );
5131
    }
5132
5133
    /**
5134
     * Test scenario with writer and publisher users.
5135
     * Writer can only create content. Publisher can publish this content.
5136
     */
5137
    public function testPublishWorkflow()
5138
    {
5139
        $this->createRoleWithPolicies('Publisher', [
5140
            ['module' => 'content', 'function' => 'read'],
5141
            ['module' => 'content', 'function' => 'create'],
5142
            ['module' => 'content', 'function' => 'publish'],
5143
        ]);
5144
5145
        $this->createRoleWithPolicies('Writer', [
5146
            ['module' => 'content', 'function' => 'read'],
5147
            ['module' => 'content', 'function' => 'create'],
5148
        ]);
5149
5150
        $writerUser = $this->createCustomUserWithLogin(
5151
            'writer',
5152
            '[email protected]',
5153
            self::WRITERS_USER_GROUP_NAME,
5154
            'Writer'
5155
        );
5156
5157
        $publisherUser = $this->createCustomUserWithLogin(
5158
            'publisher',
5159
            '[email protected]',
5160
            'Publishers',
5161
            'Publisher'
5162
        );
5163
5164
        $this->permissionResolver->setCurrentUserReference($writerUser);
5165
        $draft = $this->createContentDraftVersion1();
5166
5167
        $this->permissionResolver->setCurrentUserReference($publisherUser);
5168
        $content = $this->contentService->publishVersion($draft->versionInfo);
5169
5170
        $this->contentService->loadContent($content->id);
5171
    }
5172
5173
    /**
5174
     * Test publish / content policy is required to be able to publish content.
5175
     */
5176
    public function testPublishContentWithoutPublishPolicyThrowsException()
5177
    {
5178
        $this->createRoleWithPolicies('Writer', [
5179
            ['module' => 'content', 'function' => 'read'],
5180
            ['module' => 'content', 'function' => 'create'],
5181
            ['module' => 'content', 'function' => 'edit'],
5182
        ]);
5183
        $writerUser = $this->createCustomUserWithLogin(
5184
            'writer',
5185
            '[email protected]',
5186
            self::WRITERS_USER_GROUP_NAME,
5187
            'Writer'
5188
        );
5189
        $this->permissionResolver->setCurrentUserReference($writerUser);
5190
5191
        $this->expectException(CoreUnauthorizedException::class);
5192
        $this->expectExceptionMessageRegExp('/User does not have access to \'publish\' \'content\'/');
5193
5194
        $this->createContentVersion1();
5195
    }
5196
5197
    /**
5198
     * Test removal of the specific translation from all the Versions of a Content Object.
5199
     *
5200
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5201
     */
5202
    public function testDeleteTranslation()
5203
    {
5204
        $content = $this->createContentVersion2();
5205
5206
        // create multiple versions to exceed archive limit
5207
        for ($i = 0; $i < 5; ++$i) {
5208
            $contentDraft = $this->contentService->createContentDraft($content->contentInfo);
5209
            $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
5210
            $contentDraft = $this->contentService->updateContent(
5211
                $contentDraft->versionInfo,
5212
                $contentUpdateStruct
5213
            );
5214
            $this->contentService->publishVersion($contentDraft->versionInfo);
5215
        }
5216
5217
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_GB);
5218
5219
        $this->assertTranslationDoesNotExist(self::ENG_GB, $content->id);
5220
    }
5221
5222
    /**
5223
     * Test deleting a Translation which is initial for some Version, updates initialLanguageCode
5224
     * with mainLanguageCode (assuming they are different).
5225
     */
5226
    public function testDeleteTranslationUpdatesInitialLanguageCodeVersion()
5227
    {
5228
        $content = $this->createContentVersion2();
5229
        // create another, copied, version
5230
        $contentDraft = $this->contentService->updateContent(
5231
            $this->contentService->createContentDraft($content->contentInfo)->versionInfo,
5232
            $this->contentService->newContentUpdateStruct()
5233
        );
5234
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
5235
5236
        // remove first version with only one translation as it is not the subject of this test
5237
        $this->contentService->deleteVersion(
5238
            $this->contentService->loadVersionInfo($publishedContent->contentInfo, 1)
5239
        );
5240
5241
        // sanity check
5242
        self::assertEquals(self::ENG_US, $content->contentInfo->mainLanguageCode);
5243
        self::assertEquals(self::ENG_US, $content->versionInfo->initialLanguageCode);
5244
5245
        // update mainLanguageCode so it is different than initialLanguageCode for Version
5246
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
5247
        $contentMetadataUpdateStruct->mainLanguageCode = self::ENG_GB;
5248
        $content = $this->contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
5249
5250
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_US);
5251
5252
        $this->assertTranslationDoesNotExist(self::ENG_US, $content->id);
5253
    }
5254
5255
    /**
5256
     * Test removal of the specific translation properly updates languages of the URL alias.
5257
     *
5258
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5259
     */
5260
    public function testDeleteTranslationUpdatesUrlAlias()
5261
    {
5262
        $urlAliasService = $this->getRepository()->getURLAliasService();
5263
5264
        $content = $this->createContentVersion2();
5265
        $mainLocation = $this->locationService->loadLocation($content->contentInfo->mainLocationId);
5266
5267
        // create custom URL alias for Content main Location
5268
        $urlAliasService->createUrlAlias($mainLocation, '/my-custom-url', self::ENG_GB);
5269
5270
        // create secondary Location for Content
5271
        $secondaryLocation = $this->locationService->createLocation(
5272
            $content->contentInfo,
5273
            $this->locationService->newLocationCreateStruct(2)
5274
        );
5275
5276
        // create custom URL alias for Content secondary Location
5277
        $urlAliasService->createUrlAlias($secondaryLocation, '/my-secondary-url', self::ENG_GB);
5278
5279
        // delete Translation
5280
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_GB);
5281
5282
        foreach ([$mainLocation, $secondaryLocation] as $location) {
5283
            // check auto-generated URL aliases
5284
            foreach ($urlAliasService->listLocationAliases($location, false) as $alias) {
5285
                self::assertNotContains(self::ENG_GB, $alias->languageCodes);
5286
            }
5287
5288
            // check custom URL aliases
5289
            foreach ($urlAliasService->listLocationAliases($location) as $alias) {
5290
                self::assertNotContains(self::ENG_GB, $alias->languageCodes);
5291
            }
5292
        }
5293
    }
5294
5295
    /**
5296
     * Test removal of a main translation throws BadStateException.
5297
     *
5298
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5299
     */
5300
    public function testDeleteTranslationMainLanguageThrowsBadStateException()
5301
    {
5302
        $content = $this->createContentVersion2();
5303
5304
        // delete first version which has only one translation
5305
        $this->contentService->deleteVersion($this->contentService->loadVersionInfo($content->contentInfo, 1));
5306
5307
        // try to delete main translation
5308
        $this->expectException(BadStateException::class);
5309
        $this->expectExceptionMessage('Specified translation is the main translation of the Content Object');
5310
5311
        $this->contentService->deleteTranslation($content->contentInfo, $content->contentInfo->mainLanguageCode);
5312
    }
5313
5314
    /**
5315
     * Test removal of a Translation is possible when some archived Versions have only this Translation.
5316
     *
5317
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5318
     */
5319
    public function testDeleteTranslationDeletesSingleTranslationVersions()
5320
    {
5321
        // content created by the createContentVersion1 method has eng-US translation only.
5322
        $content = $this->createContentVersion1();
5323
5324
        // create new version and add eng-GB translation
5325
        $contentDraft = $this->contentService->createContentDraft($content->contentInfo);
5326
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
5327
        $contentUpdateStruct->setField('name', 'Awesome Board', self::ENG_GB);
5328
        $contentDraft = $this->contentService->updateContent($contentDraft->versionInfo, $contentUpdateStruct);
5329
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
5330
5331
        // update mainLanguageCode to avoid exception related to that
5332
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
5333
        $contentMetadataUpdateStruct->mainLanguageCode = self::ENG_GB;
5334
5335
        $content = $this->contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
5336
5337
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_US);
5338
5339
        $this->assertTranslationDoesNotExist(self::ENG_US, $content->id);
5340
    }
5341
5342
    /**
5343
     * Test removal of the translation by the user who is not allowed to delete a content
5344
     * throws UnauthorizedException.
5345
     *
5346
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5347
     */
5348
    public function testDeleteTranslationThrowsUnauthorizedException()
5349
    {
5350
        $content = $this->createContentVersion2();
5351
5352
        // create user that can read/create/edit but cannot delete content
5353
        $this->createRoleWithPolicies('Writer', [
5354
            ['module' => 'content', 'function' => 'read'],
5355
            ['module' => 'content', 'function' => 'versionread'],
5356
            ['module' => 'content', 'function' => 'create'],
5357
            ['module' => 'content', 'function' => 'edit'],
5358
        ]);
5359
        $writerUser = $this->createCustomUserWithLogin(
5360
            'writer',
5361
            '[email protected]',
5362
            self::WRITERS_USER_GROUP_NAME,
5363
            'Writer'
5364
        );
5365
        $this->permissionResolver->setCurrentUserReference($writerUser);
5366
5367
        $this->expectException(UnauthorizedException::class);
5368
        $this->expectExceptionMessage('User does not have access to \'remove\' \'content\'');
5369
5370
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_GB);
5371
    }
5372
5373
    /**
5374
     * Test removal of a non-existent translation throws InvalidArgumentException.
5375
     *
5376
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5377
     */
5378
    public function testDeleteTranslationThrowsInvalidArgumentException()
5379
    {
5380
        // content created by the createContentVersion1 method has eng-US translation only.
5381
        $content = $this->createContentVersion1();
5382
5383
        $this->expectException(APIInvalidArgumentException::class);
5384
        $this->expectExceptionMessage('Argument \'$languageCode\' is invalid: ger-DE does not exist in the Content item');
5385
5386
        $this->contentService->deleteTranslation($content->contentInfo, self::GER_DE);
5387
    }
5388
5389
    /**
5390
     * Test deleting a Translation from Draft.
5391
     *
5392
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5393
     */
5394
    public function testDeleteTranslationFromDraft()
5395
    {
5396
        $languageCode = self::ENG_GB;
5397
        $content = $this->createMultipleLanguageContentVersion2();
5398
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5399
        $draft = $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5400
        $content = $this->contentService->publishVersion($draft->versionInfo);
5401
5402
        $loadedContent = $this->contentService->loadContent($content->id);
5403
        self::assertNotContains($languageCode, $loadedContent->versionInfo->languageCodes);
5404
        self::assertEmpty($loadedContent->getFieldsByLanguage($languageCode));
5405
    }
5406
5407
    /**
5408
     * Get values for multilingual field.
5409
     *
5410
     * @return array
5411
     */
5412
    public function providerForDeleteTranslationFromDraftRemovesUrlAliasOnPublishing()
5413
    {
5414
        return [
5415
            [
5416
                [self::ENG_US => 'US Name', self::ENG_GB => 'GB Name'],
5417
            ],
5418
            [
5419
                [self::ENG_US => 'Same Name', self::ENG_GB => 'Same Name'],
5420
            ],
5421
        ];
5422
    }
5423
5424
    /**
5425
     * Test deleting a Translation from Draft removes previously stored URL aliases for published Content.
5426
     *
5427
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5428
     *
5429
     * @dataProvider providerForDeleteTranslationFromDraftRemovesUrlAliasOnPublishing
5430
     *
5431
     * @param string[] $fieldValues translated field values
5432
     *
5433
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
5434
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
5435
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
5436
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
5437
     */
5438
    public function testDeleteTranslationFromDraftRemovesUrlAliasOnPublishing(array $fieldValues)
5439
    {
5440
        $urlAliasService = $this->getRepository()->getURLAliasService();
5441
5442
        // set language code to be removed
5443
        $languageCode = self::ENG_GB;
5444
        $draft = $this->createMultilingualContentDraft(
5445
            'folder',
5446
            2,
5447
            self::ENG_US,
5448
            [
5449
                'name' => [
5450
                    self::ENG_GB => $fieldValues[self::ENG_GB],
5451
                    self::ENG_US => $fieldValues[self::ENG_US],
5452
                ],
5453
            ]
5454
        );
5455
        $content = $this->contentService->publishVersion($draft->versionInfo);
5456
5457
        // create secondary location
5458
        $this->locationService->createLocation(
5459
            $content->contentInfo,
5460
            $this->locationService->newLocationCreateStruct(5)
5461
        );
5462
5463
        // sanity check
5464
        $locations = $this->locationService->loadLocations($content->contentInfo);
5465
        self::assertCount(2, $locations, 'Sanity check: Expected to find 2 Locations');
5466
        foreach ($locations as $location) {
5467
            $urlAliasService->createUrlAlias($location, '/us-custom_' . $location->id, self::ENG_US);
5468
            $urlAliasService->createUrlAlias($location, '/gb-custom_' . $location->id, self::ENG_GB);
5469
5470
            // check default URL aliases
5471
            $aliases = $urlAliasService->listLocationAliases($location, false, $languageCode);
5472
            self::assertNotEmpty($aliases, 'Sanity check: URL alias for the translation does not exist');
5473
5474
            // check custom URL aliases
5475
            $aliases = $urlAliasService->listLocationAliases($location, true, $languageCode);
5476
            self::assertNotEmpty($aliases, 'Sanity check: Custom URL alias for the translation does not exist');
5477
        }
5478
5479
        // delete translation and publish new version
5480
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5481
        $draft = $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5482
        $this->contentService->publishVersion($draft->versionInfo);
5483
5484
        // check that aliases does not exist
5485
        foreach ($locations as $location) {
5486
            // check default URL aliases
5487
            $aliases = $urlAliasService->listLocationAliases($location, false, $languageCode);
5488
            self::assertEmpty($aliases, 'URL alias for the deleted translation still exists');
5489
5490
            // check custom URL aliases
5491
            $aliases = $urlAliasService->listLocationAliases($location, true, $languageCode);
5492
            self::assertEmpty($aliases, 'Custom URL alias for the deleted translation still exists');
5493
        }
5494
    }
5495
5496
    /**
5497
     * Test that URL aliases for deleted Translations are properly archived.
5498
     */
5499
    public function testDeleteTranslationFromDraftArchivesUrlAliasOnPublishing()
5500
    {
5501
        $urlAliasService = $this->getRepository()->getURLAliasService();
5502
5503
        $content = $this->contentService->publishVersion(
5504
            $this->createMultilingualContentDraft(
5505
                'folder',
5506
                2,
5507
                self::ENG_US,
5508
                [
5509
                    'name' => [
5510
                        self::ENG_GB => 'BritishEnglishContent',
5511
                        self::ENG_US => 'AmericanEnglishContent',
5512
                    ],
5513
                ]
5514
            )->versionInfo
5515
        );
5516
5517
        $unrelatedContent = $this->contentService->publishVersion(
5518
            $this->createMultilingualContentDraft(
5519
                'folder',
5520
                2,
5521
                self::ENG_US,
5522
                [
5523
                    'name' => [
5524
                        self::ENG_GB => 'AnotherBritishContent',
5525
                        self::ENG_US => 'AnotherAmericanContent',
5526
                    ],
5527
                ]
5528
            )->versionInfo
5529
        );
5530
5531
        $urlAlias = $urlAliasService->lookup('/BritishEnglishContent');
5532
        self::assertFalse($urlAlias->isHistory);
5533
        self::assertEquals($urlAlias->path, '/BritishEnglishContent');
5534
        self::assertEquals($urlAlias->destination, $content->contentInfo->mainLocationId);
5535
5536
        $draft = $this->contentService->deleteTranslationFromDraft(
5537
            $this->contentService->createContentDraft($content->contentInfo)->versionInfo,
5538
            self::ENG_GB
5539
        );
5540
        $content = $this->contentService->publishVersion($draft->versionInfo);
5541
5542
        $urlAlias = $urlAliasService->lookup('/BritishEnglishContent');
5543
        self::assertTrue($urlAlias->isHistory);
5544
        self::assertEquals($urlAlias->path, '/BritishEnglishContent');
5545
        self::assertEquals($urlAlias->destination, $content->contentInfo->mainLocationId);
5546
5547
        $unrelatedUrlAlias = $urlAliasService->lookup('/AnotherBritishContent');
5548
        self::assertFalse($unrelatedUrlAlias->isHistory);
5549
        self::assertEquals($unrelatedUrlAlias->path, '/AnotherBritishContent');
5550
        self::assertEquals($unrelatedUrlAlias->destination, $unrelatedContent->contentInfo->mainLocationId);
5551
    }
5552
5553
    /**
5554
     * Test deleting a Translation from Draft which has single Translation throws BadStateException.
5555
     *
5556
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5557
     */
5558
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnSingleTranslation()
5559
    {
5560
        // create Content with single Translation
5561
        $publishedContent = $this->contentService->publishVersion(
5562
            $this->createContentDraft(
5563
                self::FORUM_IDENTIFIER,
5564
                2,
5565
                ['name' => 'Eng-US Version name']
5566
            )->versionInfo
5567
        );
5568
5569
        // update mainLanguageCode to avoid exception related to trying to delete main Translation
5570
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
5571
        $contentMetadataUpdateStruct->mainLanguageCode = self::ENG_GB;
5572
        $publishedContent = $this->contentService->updateContentMetadata(
5573
            $publishedContent->contentInfo,
5574
            $contentMetadataUpdateStruct
5575
        );
5576
5577
        // create single Translation Version from the first one
5578
        $draft = $this->contentService->createContentDraft(
5579
            $publishedContent->contentInfo,
5580
            $publishedContent->versionInfo
5581
        );
5582
5583
        $this->expectException(BadStateException::class);
5584
        $this->expectExceptionMessage('Specified Translation is the only one Content Object Version has');
5585
5586
        // attempt to delete Translation
5587
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, self::ENG_US);
5588
    }
5589
5590
    /**
5591
     * Test deleting the Main Translation from Draft throws BadStateException.
5592
     *
5593
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5594
     */
5595
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnMainTranslation()
5596
    {
5597
        $mainLanguageCode = self::ENG_US;
5598
        $draft = $this->createMultilingualContentDraft(
5599
            self::FORUM_IDENTIFIER,
5600
            2,
5601
            $mainLanguageCode,
5602
            [
5603
                'name' => [
5604
                    self::ENG_US => 'An awesome eng-US forum',
5605
                    self::ENG_GB => 'An awesome eng-GB forum',
5606
                ],
5607
            ]
5608
        );
5609
5610
        $this->expectException(BadStateException::class);
5611
        $this->expectExceptionMessage('Specified Translation is the main Translation of the Content Object');
5612
5613
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $mainLanguageCode);
5614
    }
5615
5616
    /**
5617
     * Test deleting the Translation from Published Version throws BadStateException.
5618
     *
5619
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5620
     */
5621
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnPublishedVersion()
5622
    {
5623
        $languageCode = self::ENG_US;
5624
        $content = $this->createMultipleLanguageContentVersion2();
5625
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5626
        $publishedContent = $this->contentService->publishVersion($draft->versionInfo);
5627
5628
        $this->expectException(BadStateException::class);
5629
        $this->expectExceptionMessage('Version is not a draft');
5630
5631
        $this->contentService->deleteTranslationFromDraft($publishedContent->versionInfo, $languageCode);
5632
    }
5633
5634
    /**
5635
     * Test deleting a Translation from Draft throws UnauthorizedException if user cannot edit Content.
5636
     *
5637
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5638
     */
5639
    public function testDeleteTranslationFromDraftThrowsUnauthorizedException()
5640
    {
5641
        $languageCode = self::ENG_GB;
5642
        $content = $this->createMultipleLanguageContentVersion2();
5643
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5644
5645
        // create user that can read/create/delete but cannot edit or content
5646
        $this->createRoleWithPolicies('Writer', [
5647
            ['module' => 'content', 'function' => 'read'],
5648
            ['module' => 'content', 'function' => 'versionread'],
5649
            ['module' => 'content', 'function' => 'create'],
5650
            ['module' => 'content', 'function' => 'delete'],
5651
        ]);
5652
        $writerUser = $this->createCustomUserWithLogin(
5653
            'user',
5654
            '[email protected]',
5655
            self::WRITERS_USER_GROUP_NAME,
5656
            'Writer'
5657
        );
5658
        $this->permissionResolver->setCurrentUserReference($writerUser);
5659
5660
        $this->expectException(UnauthorizedException::class);
5661
        $this->expectExceptionMessage('User does not have access to \'edit\' \'content\'');
5662
5663
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5664
    }
5665
5666
    /**
5667
     * Test deleting a non-existent Translation from Draft throws InvalidArgumentException.
5668
     *
5669
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5670
     */
5671
    public function testDeleteTranslationFromDraftThrowsInvalidArgumentException()
5672
    {
5673
        $languageCode = self::GER_DE;
5674
        $content = $this->createMultipleLanguageContentVersion2();
5675
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5676
        $this->expectException(APIInvalidArgumentException::class);
5677
        $this->expectExceptionMessageRegExp('/The Version \(ContentId=\d+, VersionNo=\d+\) is not translated into ger-DE/');
5678
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5679
    }
5680
5681
    /**
5682
     * Test loading list of Content items.
5683
     */
5684
    public function testLoadContentListByContentInfo()
5685
    {
5686
        $allLocationsCount = $this->locationService->getAllLocationsCount();
5687
        $contentInfoList = array_map(
5688
            function (Location $location) {
5689
                return $location->contentInfo;
5690
            },
5691
            $this->locationService->loadAllLocations(0, $allLocationsCount)
5692
        );
5693
5694
        $contentList = $this->contentService->loadContentListByContentInfo($contentInfoList);
5695
        self::assertCount(count($contentInfoList), $contentList);
5696
        foreach ($contentList as $content) {
5697
            try {
5698
                $loadedContent = $this->contentService->loadContent($content->id);
5699
                self::assertEquals($loadedContent, $content, "Failed to properly bulk-load Content {$content->id}");
5700
            } catch (NotFoundException $e) {
5701
                self::fail("Failed to load Content {$content->id}: {$e->getMessage()}");
5702
            } catch (UnauthorizedException $e) {
5703
                self::fail("Failed to load Content {$content->id}: {$e->getMessage()}");
5704
            }
5705
        }
5706
    }
5707
5708
    /**
5709
     * Test loading content versions after removing exactly two drafts.
5710
     *
5711
     * @see https://jira.ez.no/browse/EZP-30271
5712
     *
5713
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
5714
     */
5715
    public function testLoadVersionsAfterDeletingTwoDrafts()
5716
    {
5717
        $content = $this->createFolder([self::ENG_GB => 'Foo'], 2);
5718
5719
        // First update and publish
5720
        $modifiedContent = $this->updateFolder($content, [self::ENG_GB => 'Foo1']);
5721
        $content = $this->contentService->publishVersion($modifiedContent->versionInfo);
5722
5723
        // Second update and publish
5724
        $modifiedContent = $this->updateFolder($content, [self::ENG_GB => 'Foo2']);
5725
        $content = $this->contentService->publishVersion($modifiedContent->versionInfo);
5726
5727
        // Create drafts
5728
        $this->updateFolder($content, [self::ENG_GB => 'Foo3']);
5729
        $this->updateFolder($content, [self::ENG_GB => 'Foo4']);
5730
5731
        $versions = $this->contentService->loadVersions($content->contentInfo);
5732
5733
        foreach ($versions as $key => $version) {
5734
            if ($version->isDraft()) {
5735
                $this->contentService->deleteVersion($version);
5736
                unset($versions[$key]);
5737
            }
5738
        }
5739
5740
        $this->assertEquals($versions, $this->contentService->loadVersions($content->contentInfo));
5741
    }
5742
5743
    /**
5744
     * Tests loading list of content versions of status draft.
5745
     */
5746
    public function testLoadVersionsOfStatusDraft()
5747
    {
5748
        $content = $this->createContentVersion1();
5749
5750
        $this->contentService->createContentDraft($content->contentInfo);
5751
        $this->contentService->createContentDraft($content->contentInfo);
5752
        $this->contentService->createContentDraft($content->contentInfo);
5753
5754
        $versions = $this->contentService->loadVersions($content->contentInfo, VersionInfo::STATUS_DRAFT);
5755
5756
        $this->assertSame(\count($versions), 3);
5757
    }
5758
5759
    /**
5760
     * Tests loading list of content versions of status archived.
5761
     */
5762
    public function testLoadVersionsOfStatusArchived()
5763
    {
5764
        $content = $this->createContentVersion1();
5765
5766
        $draft1 = $this->contentService->createContentDraft($content->contentInfo);
5767
        $this->contentService->publishVersion($draft1->versionInfo);
5768
5769
        $draft2 = $this->contentService->createContentDraft($content->contentInfo);
5770
        $this->contentService->publishVersion($draft2->versionInfo);
5771
5772
        $versions = $this->contentService->loadVersions($content->contentInfo, VersionInfo::STATUS_ARCHIVED);
5773
5774
        $this->assertSame(\count($versions), 2);
5775
    }
5776
5777
    /**
5778
     * Asserts that all aliases defined in $expectedAliasProperties with the
5779
     * given properties are available in $actualAliases and not more.
5780
     *
5781
     * @param array $expectedAliasProperties
5782
     * @param array $actualAliases
5783
     */
5784
    private function assertAliasesCorrect(array $expectedAliasProperties, array $actualAliases)
5785
    {
5786
        foreach ($actualAliases as $actualAlias) {
5787
            if (!isset($expectedAliasProperties[$actualAlias->path])) {
5788
                $this->fail(
5789
                    sprintf(
5790
                        'Alias with path "%s" in languages "%s" not expected.',
5791
                        $actualAlias->path,
5792
                        implode(', ', $actualAlias->languageCodes)
5793
                    )
5794
                );
5795
            }
5796
5797
            foreach ($expectedAliasProperties[$actualAlias->path] as $propertyName => $propertyValue) {
5798
                $this->assertEquals(
5799
                    $propertyValue,
5800
                    $actualAlias->$propertyName,
5801
                    sprintf(
5802
                        'Property $%s incorrect on alias with path "%s" in languages "%s".',
5803
                        $propertyName,
5804
                        $actualAlias->path,
5805
                        implode(', ', $actualAlias->languageCodes)
5806
                    )
5807
                );
5808
            }
5809
5810
            unset($expectedAliasProperties[$actualAlias->path]);
5811
        }
5812
5813
        if (!empty($expectedAliasProperties)) {
5814
            $this->fail(
5815
                sprintf(
5816
                    'Missing expected aliases with paths "%s".',
5817
                    implode('", "', array_keys($expectedAliasProperties))
5818
                )
5819
            );
5820
        }
5821
    }
5822
5823
    /**
5824
     * Asserts that the given fields are equal to the default fields fixture.
5825
     *
5826
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
5827
     */
5828
    private function assertAllFieldsEquals(array $fields)
5829
    {
5830
        $actual = $this->normalizeFields($fields);
5831
        $expected = $this->normalizeFields($this->createFieldsFixture());
5832
5833
        $this->assertEquals($expected, $actual);
5834
    }
5835
5836
    /**
5837
     * Asserts that the given fields are equal to a language filtered set of the
5838
     * default fields fixture.
5839
     *
5840
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
5841
     * @param string $languageCode
5842
     */
5843
    private function assertLocaleFieldsEquals(array $fields, $languageCode)
5844
    {
5845
        $actual = $this->normalizeFields($fields);
5846
5847
        $expected = [];
5848
        foreach ($this->normalizeFields($this->createFieldsFixture()) as $field) {
5849
            if ($field->languageCode !== $languageCode) {
5850
                continue;
5851
            }
5852
            $expected[] = $field;
5853
        }
5854
5855
        $this->assertEquals($expected, $actual);
5856
    }
5857
5858
    /**
5859
     * This method normalizes a set of fields and returns a normalized set.
5860
     *
5861
     * Normalization means it resets the storage specific field id to zero and
5862
     * it sorts the field by their identifier and their language code. In
5863
     * addition, the field value is removed, since this one depends on the
5864
     * specific FieldType, which is tested in a dedicated integration test.
5865
     *
5866
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
5867
     *
5868
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
5869
     */
5870
    private function normalizeFields(array $fields)
5871
    {
5872
        $normalized = [];
5873
        foreach ($fields as $field) {
5874
            $normalized[] = new Field(
5875
                [
5876
                    'id' => 0,
5877
                    'value' => $field->value !== null,
5878
                    'languageCode' => $field->languageCode,
5879
                    'fieldDefIdentifier' => $field->fieldDefIdentifier,
5880
                    'fieldTypeIdentifier' => $field->fieldTypeIdentifier,
5881
                ]
5882
            );
5883
        }
5884
        usort(
5885
            $normalized,
5886
            function ($field1, $field2) {
5887
                if (0 === ($return = strcasecmp($field1->fieldDefIdentifier, $field2->fieldDefIdentifier))) {
5888
                    return strcasecmp($field1->languageCode, $field2->languageCode);
5889
                }
5890
5891
                return $return;
5892
            }
5893
        );
5894
5895
        return $normalized;
5896
    }
5897
5898
    /**
5899
     * Asserts that given Content has default ContentStates.
5900
     *
5901
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
5902
     */
5903
    private function assertDefaultContentStates(ContentInfo $contentInfo)
5904
    {
5905
        $objectStateService = $this->getRepository()->getObjectStateService();
5906
5907
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
5908
5909
        foreach ($objectStateGroups as $objectStateGroup) {
5910
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
5911
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
5912
                // Only check the first object state which is the default one.
5913
                $this->assertEquals(
5914
                    $objectState,
5915
                    $contentState
5916
                );
5917
                break;
5918
            }
5919
        }
5920
    }
5921
5922
    /**
5923
     * Assert that given Content has no references to a translation specified by the $languageCode.
5924
     *
5925
     * @param string $languageCode
5926
     * @param int $contentId
5927
     */
5928
    private function assertTranslationDoesNotExist($languageCode, $contentId)
5929
    {
5930
        $content = $this->contentService->loadContent($contentId);
5931
5932
        foreach ($content->fields as $field) {
5933
            /** @var array $field */
5934
            self::assertArrayNotHasKey($languageCode, $field);
5935
            self::assertNotEquals($languageCode, $content->contentInfo->mainLanguageCode);
5936
            self::assertArrayNotHasKey($languageCode, $content->versionInfo->getNames());
5937
            self::assertNotEquals($languageCode, $content->versionInfo->initialLanguageCode);
5938
            self::assertNotContains($languageCode, $content->versionInfo->languageCodes);
5939
        }
5940
        foreach ($this->contentService->loadVersions($content->contentInfo) as $versionInfo) {
5941
            self::assertArrayNotHasKey($languageCode, $versionInfo->getNames());
5942
            self::assertNotEquals($languageCode, $versionInfo->contentInfo->mainLanguageCode);
5943
            self::assertNotEquals($languageCode, $versionInfo->initialLanguageCode);
5944
            self::assertNotContains($languageCode, $versionInfo->languageCodes);
5945
        }
5946
    }
5947
5948
    /**
5949
     * Returns the default fixture of fields used in most tests.
5950
     *
5951
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
5952
     */
5953
    private function createFieldsFixture()
5954
    {
5955
        return [
5956
            new Field(
5957
                [
5958
                    'id' => 0,
5959
                    'value' => 'Foo',
5960
                    'languageCode' => self::ENG_US,
5961
                    'fieldDefIdentifier' => 'description',
5962
                    'fieldTypeIdentifier' => 'ezrichtext',
5963
                ]
5964
            ),
5965
            new Field(
5966
                [
5967
                    'id' => 0,
5968
                    'value' => 'Bar',
5969
                    'languageCode' => self::ENG_GB,
5970
                    'fieldDefIdentifier' => 'description',
5971
                    'fieldTypeIdentifier' => 'ezrichtext',
5972
                ]
5973
            ),
5974
            new Field(
5975
                [
5976
                    'id' => 0,
5977
                    'value' => 'An awesome multi-lang forum²',
5978
                    'languageCode' => self::ENG_US,
5979
                    'fieldDefIdentifier' => 'name',
5980
                    'fieldTypeIdentifier' => 'ezstring',
5981
                ]
5982
            ),
5983
            new Field(
5984
                [
5985
                    'id' => 0,
5986
                    'value' => 'An awesome multi-lang forum²³',
5987
                    'languageCode' => self::ENG_GB,
5988
                    'fieldDefIdentifier' => 'name',
5989
                    'fieldTypeIdentifier' => 'ezstring',
5990
                ]
5991
            ),
5992
        ];
5993
    }
5994
5995
    /**
5996
     * Gets expected property values for the "Media" ContentInfo ValueObject.
5997
     *
5998
     * @return array
5999
     */
6000
    private function getExpectedMediaContentInfoProperties()
6001
    {
6002
        return [
6003
            'id' => self::MEDIA_CONTENT_ID,
6004
            'contentTypeId' => 1,
6005
            'name' => 'Media',
6006
            'sectionId' => 3,
6007
            'currentVersionNo' => 1,
6008
            'published' => true,
6009
            'ownerId' => 14,
6010
            'modificationDate' => $this->createDateTime(1060695457),
6011
            'publishedDate' => $this->createDateTime(1060695457),
6012
            'alwaysAvailable' => 1,
6013
            'remoteId' => self::MEDIA_REMOTE_ID,
6014
            'mainLanguageCode' => self::ENG_US,
6015
            'mainLocationId' => 43,
6016
            'status' => ContentInfo::STATUS_PUBLISHED,
6017
        ];
6018
    }
6019
6020
    /**
6021
     * @covers \eZ\Publish\API\Repository\ContentService::hideContent
6022
     *
6023
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
6024
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
6025
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException
6026
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6027
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
6028
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6029
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6030
     */
6031
    public function testHideContent(): void
6032
    {
6033
        $contentTypeService = $this->getRepository()->getContentTypeService();
6034
6035
        $locationCreateStructs = array_map(
6036
            function (Location $parentLocation) {
6037
                return $this->locationService->newLocationCreateStruct($parentLocation->id);
6038
            },
6039
            $this->createParentLocationsForHideReveal(2)
6040
        );
6041
6042
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6043
6044
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6045
        $contentCreate->setField('name', 'Folder to hide');
6046
6047
        $content = $this->contentService->createContent(
6048
            $contentCreate,
6049
            $locationCreateStructs
6050
        );
6051
6052
        $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6053
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6054
6055
        // Sanity check
6056
        $this->assertCount(3, $locations);
6057
        $this->assertCount(0, $this->filterHiddenLocations($locations));
6058
6059
        $this->contentService->hideContent($publishedContent->contentInfo);
6060
6061
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6062
        $this->assertCount(3, $locations);
6063
        $this->assertCount(3, $this->filterHiddenLocations($locations));
6064
    }
6065
6066
    /**
6067
     * @covers \eZ\Publish\API\Repository\ContentService::revealContent
6068
     *
6069
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6070
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6071
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6072
     */
6073
    public function testRevealContent()
6074
    {
6075
        $contentTypeService = $this->getRepository()->getContentTypeService();
6076
6077
        $locationCreateStructs = array_map(
6078
            function (Location $parentLocation) {
6079
                return $this->locationService->newLocationCreateStruct($parentLocation->id);
6080
            },
6081
            $this->createParentLocationsForHideReveal(2)
6082
        );
6083
6084
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6085
6086
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6087
        $contentCreate->setField('name', 'Folder to hide');
6088
6089
        $locationCreateStructs[0]->hidden = true;
6090
6091
        $content = $this->contentService->createContent(
6092
            $contentCreate,
6093
            $locationCreateStructs
6094
        );
6095
6096
        $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6097
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6098
6099
        // Sanity check
6100
        $hiddenLocations = $this->filterHiddenLocations($locations);
6101
        $this->assertCount(3, $locations);
6102
        $this->assertCount(1, $hiddenLocations);
6103
6104
        $this->contentService->hideContent($publishedContent->contentInfo);
6105
        $this->assertCount(
6106
            3,
6107
            $this->filterHiddenLocations(
6108
                $this->locationService->loadLocations($publishedContent->contentInfo)
6109
            )
6110
        );
6111
6112
        $this->contentService->revealContent($publishedContent->contentInfo);
6113
6114
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6115
        $hiddenLocationsAfterReveal = $this->filterHiddenLocations($locations);
6116
        $this->assertCount(3, $locations);
6117
        $this->assertCount(1, $hiddenLocationsAfterReveal);
6118
        $this->assertEquals($hiddenLocations, $hiddenLocationsAfterReveal);
6119
    }
6120
6121
    /**
6122
     * @depends testRevealContent
6123
     */
6124
    public function testRevealContentWithHiddenParent()
6125
    {
6126
        $contentTypeService = $this->getRepository()->getContentTypeService();
6127
6128
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6129
6130
        $contentNames = [
6131
            'Parent Content',
6132
            'Child (Nesting 1)',
6133
            'Child (Nesting 2)',
6134
            'Child (Nesting 3)',
6135
            'Child (Nesting 4)',
6136
        ];
6137
6138
        $parentLocation = $this->locationService->newLocationCreateStruct(
6139
            $this->generateId('location', 2)
6140
        );
6141
6142
        /** @var Content[] $contents */
6143
        $contents = [];
6144
6145
        foreach ($contentNames as $contentName) {
6146
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6147
            $contentCreate->setField('name', $contentName);
6148
6149
            $content = $this->contentService->createContent($contentCreate, [$parentLocation]);
6150
            $contents[] = $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6151
6152
            $parentLocation = $this->locationService->newLocationCreateStruct(
6153
                $this->generateId('location', $publishedContent->contentInfo->mainLocationId)
6154
            );
6155
        }
6156
6157
        $this->contentService->hideContent($contents[0]->contentInfo);
6158
        $this->contentService->hideContent($contents[2]->contentInfo);
6159
        $this->contentService->revealContent($contents[2]->contentInfo);
6160
6161
        $parentContent = $this->contentService->loadContent($contents[0]->id);
6162
        $parentLocation = $this->locationService->loadLocation($parentContent->contentInfo->mainLocationId);
6163
        $parentSublocations = $this->locationService->loadLocationList([
6164
            $contents[1]->contentInfo->mainLocationId,
6165
            $contents[2]->contentInfo->mainLocationId,
6166
            $contents[3]->contentInfo->mainLocationId,
6167
            $contents[4]->contentInfo->mainLocationId,
6168
        ]);
6169
6170
        // Parent remains invisible
6171
        self::assertTrue($parentLocation->invisible);
6172
6173
        // All parent sublocations remain invisible as well
6174
        foreach ($parentSublocations as $parentSublocation) {
6175
            self::assertTrue($parentSublocation->invisible);
6176
        }
6177
    }
6178
6179
    /**
6180
     * @depends testRevealContent
6181
     */
6182
    public function testRevealContentWithHiddenChildren()
6183
    {
6184
        $contentTypeService = $this->getRepository()->getContentTypeService();
6185
6186
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6187
6188
        $contentNames = [
6189
            'Parent Content',
6190
            'Child (Nesting 1)',
6191
            'Child (Nesting 2)',
6192
            'Child (Nesting 3)',
6193
            'Child (Nesting 4)',
6194
        ];
6195
6196
        $parentLocation = $this->locationService->newLocationCreateStruct(
6197
            $this->generateId('location', 2)
6198
        );
6199
6200
        /** @var Content[] $contents */
6201
        $contents = [];
6202
6203
        foreach ($contentNames as $contentName) {
6204
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6205
            $contentCreate->setField('name', $contentName);
6206
6207
            $content = $this->contentService->createContent($contentCreate, [$parentLocation]);
6208
            $contents[] = $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6209
6210
            $parentLocation = $this->locationService->newLocationCreateStruct(
6211
                $this->generateId('location', $publishedContent->contentInfo->mainLocationId)
6212
            );
6213
        }
6214
6215
        $this->contentService->hideContent($contents[0]->contentInfo);
6216
        $this->contentService->hideContent($contents[2]->contentInfo);
6217
        $this->contentService->revealContent($contents[0]->contentInfo);
6218
6219
        $directChildContent = $this->contentService->loadContent($contents[1]->id);
6220
        $directChildLocation = $this->locationService->loadLocation($directChildContent->contentInfo->mainLocationId);
6221
6222
        $childContent = $this->contentService->loadContent($contents[2]->id);
6223
        $childLocation = $this->locationService->loadLocation($childContent->contentInfo->mainLocationId);
6224
        $childSublocations = $this->locationService->loadLocationList([
6225
            $contents[3]->contentInfo->mainLocationId,
6226
            $contents[4]->contentInfo->mainLocationId,
6227
        ]);
6228
6229
        // Direct child content is not hidden
6230
        self::assertFalse($directChildContent->contentInfo->isHidden);
6231
6232
        // Direct child content location is still invisible
6233
        self::assertFalse($directChildLocation->invisible);
6234
6235
        // Child content is still hidden
6236
        self::assertTrue($childContent->contentInfo->isHidden);
6237
6238
        // Child content location is still invisible
6239
        self::assertTrue($childLocation->invisible);
6240
6241
        // All childs sublocations remain invisible as well
6242
        foreach ($childSublocations as $childSublocation) {
6243
            self::assertTrue($childSublocation->invisible);
6244
        }
6245
    }
6246
6247
    public function testHideContentWithParentLocation()
6248
    {
6249
        $contentTypeService = $this->getRepository()->getContentTypeService();
6250
6251
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6252
6253
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6254
        $contentCreate->setField('name', 'Parent');
6255
6256
        $content = $this->contentService->createContent(
6257
            $contentCreate,
6258
            [
6259
                $this->locationService->newLocationCreateStruct(
6260
                    $this->generateId('location', 2)
6261
                ),
6262
            ]
6263
        );
6264
6265
        $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6266
6267
        $this->contentService->hideContent($publishedContent->contentInfo);
6268
6269
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6270
6271
        $childContentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6272
        $childContentCreate->setField('name', 'Child');
6273
6274
        $childContent = $this->contentService->createContent(
6275
            $childContentCreate,
6276
            [
6277
                $this->locationService->newLocationCreateStruct(
6278
                    $locations[0]->id
6279
                ),
6280
            ]
6281
        );
6282
6283
        $publishedChildContent = $this->contentService->publishVersion($childContent->versionInfo);
6284
6285
        $childLocations = $this->locationService->loadLocations($publishedChildContent->contentInfo);
6286
6287
        $this->assertTrue($locations[0]->hidden);
6288
        $this->assertTrue($locations[0]->invisible);
6289
6290
        $this->assertFalse($childLocations[0]->hidden);
6291
        $this->assertTrue($childLocations[0]->invisible);
6292
    }
6293
6294
    public function testChangeContentName()
6295
    {
6296
        $contentDraft = $this->createContentDraft(
6297
            'folder',
6298
            $this->generateId('location', 2),
6299
            [
6300
                'name' => 'Marco',
6301
            ]
6302
        );
6303
6304
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
6305
        $contentMetadataUpdateStruct = new ContentMetadataUpdateStruct([
6306
            'name' => 'Polo',
6307
        ]);
6308
        $this->contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
6309
6310
        $updatedContent = $this->contentService->loadContent($publishedContent->id);
6311
6312
        $this->assertEquals('Marco', $publishedContent->contentInfo->name);
6313
        $this->assertEquals('Polo', $updatedContent->contentInfo->name);
6314
    }
6315
6316
    public function testCopyTranslationsFromPublishedToDraft()
6317
    {
6318
        $contentDraft = $this->createContentDraft(
6319
            'folder',
6320
            $this->generateId('location', 2),
6321
            [
6322
                'name' => 'Folder US',
6323
            ]
6324
        );
6325
6326
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
6327
6328
        $deDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6329
6330
        $contentUpdateStruct = new ContentUpdateStruct([
6331
            'initialLanguageCode' => self::GER_DE,
6332
            'fields' => $contentDraft->getFields(),
6333
        ]);
6334
6335
        $contentUpdateStruct->setField('name', 'Folder GER', self::GER_DE);
6336
6337
        $deContent = $this->contentService->updateContent($deDraft->versionInfo, $contentUpdateStruct);
6338
6339
        $updatedContent = $this->contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6340
        $this->assertEquals(
6341
            [
6342
                self::ENG_US => 'Folder US',
6343
                self::GER_DE => 'Folder GER',
6344
            ],
6345
            $updatedContent->fields['name']
6346
        );
6347
6348
        $gbDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6349
6350
        $contentUpdateStruct = new ContentUpdateStruct([
6351
            'initialLanguageCode' => self::ENG_GB,
6352
            'fields' => $contentDraft->getFields(),
6353
        ]);
6354
6355
        $contentUpdateStruct->setField('name', 'Folder GB', self::ENG_GB);
6356
6357
        $gbContent = $this->contentService->updateContent($gbDraft->versionInfo, $contentUpdateStruct);
6358
        $this->contentService->publishVersion($gbDraft->versionInfo);
6359
        $updatedContent = $this->contentService->loadContent($gbContent->id, null, $gbContent->versionInfo->versionNo);
6360
        $this->assertEquals(
6361
            [
6362
                self::ENG_US => 'Folder US',
6363
                self::ENG_GB => 'Folder GB',
6364
            ],
6365
            $updatedContent->fields['name']
6366
        );
6367
6368
        $dePublished = $this->contentService->publishVersion($deDraft->versionInfo);
6369
        $this->assertEquals(
6370
            [
6371
                self::ENG_US => 'Folder US',
6372
                self::GER_DE => 'Folder GER',
6373
                self::ENG_GB => 'Folder GB',
6374
            ],
6375
            $dePublished->fields['name']
6376
        );
6377
    }
6378
6379
    public function testCopyTranslationsFromInvalidPublishedContentToDraft()
6380
    {
6381
        $contentTypeService = $this->getRepository()->getContentTypeService();
6382
6383
        // Create content type for testing
6384
        $contentTypeCreateStruct = $contentTypeService->newContentTypeCreateStruct('test_copy_translation');
6385
        $contentTypeCreateStruct->mainLanguageCode = 'eng-US';
6386
        $contentTypeCreateStruct->names = ['eng-US' => 'Test Content Type for Copy Translations'];
6387
        $fieldDefinition = $contentTypeService->newFieldDefinitionCreateStruct('name', 'ezstring');
6388
        $fieldDefinition->position = 1;
6389
        $contentTypeCreateStruct->addFieldDefinition($fieldDefinition);
6390
        $contentTypeService->publishContentTypeDraft(
6391
            $contentTypeService->createContentType(
6392
                $contentTypeCreateStruct,
6393
                [$contentTypeService->loadContentTypeGroupByIdentifier('Content')]
6394
            )
6395
        );
6396
        $contentType = $contentTypeService->loadContentTypeByIdentifier('test_copy_translation');
6397
6398
        // Create entry content
6399
        $contentDraft = $this->createContentDraft(
6400
            'test_copy_translation',
6401
            $this->generateId('location', 2),
6402
            [
6403
                'name' => 'Folder US',
6404
            ]
6405
        );
6406
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
6407
6408
        // Create translation draft that would act as an OLD version
6409
        $deDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6410
        $contentUpdateStruct = new ContentUpdateStruct([
6411
            'initialLanguageCode' => self::GER_DE,
6412
            'fields' => $contentDraft->getFields(),
6413
        ]);
6414
6415
        $contentUpdateStruct->setField('name', 'Folder GER', self::GER_DE);
6416
        $deContent = $this->contentService->updateContent($deDraft->versionInfo, $contentUpdateStruct);
6417
6418
        // Update published version, as copying is only done when there is a diff between published and draft
6419
        $gbDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6420
        $contentUpdateStruct = new ContentUpdateStruct([
6421
            'initialLanguageCode' => self::ENG_US,
6422
        ]);
6423
        $contentUpdateStruct->setField('name', 'Folder US 2', self::ENG_US);
6424
6425
        $gbContent = $this->contentService->updateContent($gbDraft->versionInfo, $contentUpdateStruct);
6426
        $this->contentService->publishVersion($gbContent->versionInfo);
6427
6428
        // Update content type with new required field
6429
        $contentTypeDraft = $contentTypeService->createContentTypeDraft($contentType);
6430
        $fieldDefinition = $contentTypeService->newFieldDefinitionCreateStruct('req_field', 'ezstring');
6431
        $fieldDefinition->position = 2;
6432
        $fieldDefinition->isRequired = true;
6433
        $contentTypeService->addFieldDefinition($contentTypeDraft, $fieldDefinition);
6434
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
6435
6436
        // Reload previous german draft, it is now in invalid state for both ENG_US and GER_DE
6437
        $invalidContentDraft = $this->contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6438
        $contentUpdateStruct = new ContentUpdateStruct([
6439
            'initialLanguageCode' => self::GER_DE,
6440
        ]);
6441
        $contentUpdateStruct->setField('req_field', 'Required field DE', self::GER_DE);
6442
6443
        $this->contentService->updateContent($invalidContentDraft->versionInfo, $contentUpdateStruct);
6444
        $this->contentService->publishVersion($invalidContentDraft->versionInfo, [self::GER_DE]);
6445
6446
        $publishedContent = $this->contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6447
6448
        $this->assertEquals(
6449
            [
6450
                self::GER_DE => 'Folder GER',
6451
                self::ENG_US => 'Folder US 2',
6452
            ],
6453
            $publishedContent->fields['name']
6454
        );
6455
        // Missing values were copied from last updated draft
6456
        $this->assertEquals(
6457
            [
6458
                self::GER_DE => 'Required field DE',
6459
                self::ENG_US => 'Required field DE',
6460
            ],
6461
            $publishedContent->fields['req_field']
6462
        );
6463
    }
6464
6465
    /**
6466
     * Create structure of parent folders with Locations to be used for Content hide/reveal tests.
6467
     *
6468
     * @param int $parentLocationId
6469
     *
6470
     * @return \eZ\Publish\API\Repository\Values\Content\Location[] A list of Locations aimed to be parents
6471
     *
6472
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6473
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6474
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6475
     */
6476
    private function createParentLocationsForHideReveal(int $parentLocationId): array
6477
    {
6478
        $parentFoldersLocationsIds = [
6479
            $this->createFolder([self::ENG_US => 'P1'], $parentLocationId)->contentInfo->mainLocationId,
6480
            $this->createFolder([self::ENG_US => 'P2'], $parentLocationId)->contentInfo->mainLocationId,
6481
            $this->createFolder([self::ENG_US => 'P3'], $parentLocationId)->contentInfo->mainLocationId,
6482
        ];
6483
6484
        return array_values($this->locationService->loadLocationList($parentFoldersLocationsIds));
6485
    }
6486
6487
    /**
6488
     * Filter Locations list by hidden only.
6489
     *
6490
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
6491
     *
6492
     * @return array
6493
     */
6494
    private function filterHiddenLocations(array $locations): array
6495
    {
6496
        return array_values(
6497
            array_filter(
6498
                $locations,
6499
                function (Location $location) {
6500
                    return $location->hidden;
6501
                }
6502
            )
6503
        );
6504
    }
6505
6506
    public function testPublishVersionWithSelectedLanguages()
6507
    {
6508
        $publishedContent = $this->createFolder(
6509
            [
6510
                self::ENG_US => 'Published US',
6511
                self::GER_DE => 'Published DE',
6512
            ],
6513
            $this->generateId('location', 2)
6514
        );
6515
6516
        $draft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6517
        $contentUpdateStruct = new ContentUpdateStruct([
6518
            'initialLanguageCode' => self::ENG_US,
6519
        ]);
6520
        $contentUpdateStruct->setField('name', 'Draft 1 US', self::ENG_US);
6521
        $contentUpdateStruct->setField('name', 'Draft 1 DE', self::GER_DE);
6522
6523
        $this->contentService->updateContent($draft->versionInfo, $contentUpdateStruct);
6524
6525
        $this->contentService->publishVersion($draft->versionInfo, [self::GER_DE]);
6526
        $content = $this->contentService->loadContent($draft->contentInfo->id);
6527
        $this->assertEquals(
6528
            [
6529
                self::ENG_US => 'Published US',
6530
                self::GER_DE => 'Draft 1 DE',
6531
            ],
6532
            $content->fields['name']
6533
        );
6534
    }
6535
6536
    public function testCreateContentWithRomanianSpecialCharsInTitle()
6537
    {
6538
        $baseName = 'ȘșțȚdfdf';
6539
        $expectedPath = '/SstTdfdf';
6540
6541
        $this->createFolder([self::ENG_US => $baseName], 2);
6542
6543
        $urlAliasService = $this->getRepository()->getURLAliasService();
6544
        $urlAlias = $urlAliasService->lookup($expectedPath);
6545
        $this->assertSame($expectedPath, $urlAlias->path);
6546
    }
6547
6548
    /**
6549
     * @param int $amountOfDrafts
6550
     *
6551
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6552
     */
6553
    private function createContentDrafts(int $amountOfDrafts): void
6554
    {
6555
        if (0 >= $amountOfDrafts) {
6556
            throw new InvalidArgumentException('$amountOfDrafts', 'Must be greater then 0');
6557
        }
6558
6559
        $publishedContent = $this->createContentVersion1();
6560
6561
        for ($i = 1; $i <= $amountOfDrafts; ++$i) {
6562
            $this->contentService->createContentDraft($publishedContent->contentInfo);
6563
        }
6564
    }
6565
6566
    /**
6567
     * @param array $limitationValues
6568
     *
6569
     * @return \eZ\Publish\API\Repository\Values\User\User
6570
     *
6571
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6572
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6573
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6574
     */
6575
    private function createUserWithVersionReadLimitations(array $limitationValues = []): User
6576
    {
6577
        $limitations = [
6578
            new LocationLimitation(['limitationValues' => $limitationValues]),
6579
        ];
6580
6581
        return $this->createUserWithPolicies(
6582
            'user',
6583
            [
6584
                ['module' => 'content', 'function' => 'versionread', 'limitations' => $limitations],
6585
                ['module' => 'content', 'function' => 'create'],
6586
                ['module' => 'content', 'function' => 'read'],
6587
                ['module' => 'content', 'function' => 'edit'],
6588
            ]
6589
        );
6590
    }
6591
6592
    /**
6593
     * @param \eZ\Publish\API\Repository\Values\Content\Content[] $drafts
6594
     *
6595
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
6596
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6597
     *
6598
     * @return object
6599
     */
6600
    private function createContentWithReverseRelations(array $drafts)
6601
    {
6602
        $contentWithReverseRelations = new class() {
6603
            /** @var \eZ\Publish\API\Repository\Values\Content\Content */
6604
            public $content;
6605
6606
            /** @var \eZ\Publish\API\Repository\Values\Content\Content[] */
6607
            public $reverseRelations;
6608
        };
6609
        $content = $this->createContentVersion1();
6610
        $versionInfo = $content->getVersionInfo();
6611
        $contentInfo = $versionInfo->getContentInfo();
6612
        $contentWithReverseRelations->content = $content;
6613
6614
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $draft */
6615
        foreach ($drafts as $draft) {
6616
            $this->contentService->addRelation(
6617
                $draft->getVersionInfo(),
6618
                $contentInfo
6619
            );
6620
6621
            $contentWithReverseRelations->reverseRelations[] = $this->contentService->publishVersion($draft->getVersionInfo());
6622
        }
6623
6624
        return $contentWithReverseRelations;
6625
    }
6626
}
6627