Completed
Push — apply-code-style ( 1a43bf...37cc85 )
by
unknown
45:48
created

testCopyTranslationsFromInvalidPublishedContentToDraft()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 85

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 85
rs 8.3272
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
     *
1827
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1828
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1829
     */
1830
    public function testPublishVersionNotCreatingUnlimitedArchives()
1831
    {
1832
        $content = $this->createContentVersion1();
1833
1834
        // load first to make sure list gets updated also (cache)
1835
        $versionInfoList = $this->contentService->loadVersions($content->contentInfo);
1836
        $this->assertEquals(1, count($versionInfoList));
1837
        $this->assertEquals(1, $versionInfoList[0]->versionNo);
1838
1839
        // Create a new draft with versionNo = 2
1840
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1841
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1842
1843
        // Create a new draft with versionNo = 3
1844
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1845
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1846
1847
        // Create a new draft with versionNo = 4
1848
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1849
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1850
1851
        // Create a new draft with versionNo = 5
1852
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1853
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1854
1855
        // Create a new draft with versionNo = 6
1856
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1857
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1858
1859
        // Create a new draft with versionNo = 7
1860
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1861
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1862
1863
        $versionInfoList = $this->contentService->loadVersions($content->contentInfo);
1864
1865
        $this->assertEquals(6, count($versionInfoList));
1866
        $this->assertEquals(2, $versionInfoList[0]->versionNo);
1867
        $this->assertEquals(7, $versionInfoList[5]->versionNo);
1868
1869
        $this->assertEquals(
1870
            [
1871
                VersionInfo::STATUS_ARCHIVED,
1872
                VersionInfo::STATUS_ARCHIVED,
1873
                VersionInfo::STATUS_ARCHIVED,
1874
                VersionInfo::STATUS_ARCHIVED,
1875
                VersionInfo::STATUS_ARCHIVED,
1876
                VersionInfo::STATUS_PUBLISHED,
1877
            ],
1878
            [
1879
                $versionInfoList[0]->status,
1880
                $versionInfoList[1]->status,
1881
                $versionInfoList[2]->status,
1882
                $versionInfoList[3]->status,
1883
                $versionInfoList[4]->status,
1884
                $versionInfoList[5]->status,
1885
            ]
1886
        );
1887
    }
1888
1889
    /**
1890
     * Test for the newContentMetadataUpdateStruct() method.
1891
     *
1892
     * @covers \eZ\Publish\API\Repository\ContentService::newContentMetadataUpdateStruct
1893
     * @group user
1894
     */
1895
    public function testNewContentMetadataUpdateStruct()
1896
    {
1897
        // Creates a new metadata update struct
1898
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
1899
1900
        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...
1901
            $this->assertNull($propertyValue, "Property '{$propertyName}' initial value should be null'");
1902
        }
1903
1904
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
1905
        $metadataUpdate->mainLanguageCode = self::ENG_GB;
1906
        $metadataUpdate->alwaysAvailable = false;
1907
1908
        $this->assertInstanceOf(
1909
            ContentMetadataUpdateStruct::class,
1910
            $metadataUpdate
1911
        );
1912
    }
1913
1914
    /**
1915
     * Test for the updateContentMetadata() method.
1916
     *
1917
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1918
     *
1919
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1920
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1921
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentMetadataUpdateStruct
1922
     * @group user
1923
     */
1924
    public function testUpdateContentMetadata()
1925
    {
1926
        $content = $this->createContentVersion1();
1927
1928
        // Creates a metadata update struct
1929
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
1930
1931
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
1932
        $metadataUpdate->mainLanguageCode = self::ENG_GB;
1933
        $metadataUpdate->alwaysAvailable = false;
1934
        $metadataUpdate->publishedDate = $this->createDateTime(441759600); // 1984/01/01
1935
        $metadataUpdate->modificationDate = $this->createDateTime(441759600); // 1984/01/01
1936
1937
        // Update the metadata of the published content object
1938
        $content = $this->contentService->updateContentMetadata(
1939
            $content->contentInfo,
1940
            $metadataUpdate
1941
        );
1942
1943
        $this->assertInstanceOf(
1944
            Content::class,
1945
            $content
1946
        );
1947
1948
        return $content;
1949
    }
1950
1951
    /**
1952
     * Test for the updateContentMetadata() method.
1953
     *
1954
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1955
     *
1956
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1957
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1958
     */
1959
    public function testUpdateContentMetadataSetsExpectedProperties($content)
1960
    {
1961
        $contentInfo = $content->contentInfo;
1962
1963
        $this->assertEquals(
1964
            [
1965
                'remoteId' => 'aaaabbbbccccddddeeeeffff11112222',
1966
                'sectionId' => $this->generateId('section', 1),
1967
                'alwaysAvailable' => false,
1968
                'currentVersionNo' => 1,
1969
                'mainLanguageCode' => self::ENG_GB,
1970
                'modificationDate' => $this->createDateTime(441759600),
1971
                '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...
1972
                'published' => true,
1973
                'publishedDate' => $this->createDateTime(441759600),
1974
            ],
1975
            [
1976
                'remoteId' => $contentInfo->remoteId,
1977
                'sectionId' => $contentInfo->sectionId,
1978
                'alwaysAvailable' => $contentInfo->alwaysAvailable,
1979
                'currentVersionNo' => $contentInfo->currentVersionNo,
1980
                'mainLanguageCode' => $contentInfo->mainLanguageCode,
1981
                'modificationDate' => $contentInfo->modificationDate,
1982
                'ownerId' => $contentInfo->ownerId,
1983
                'published' => $contentInfo->published,
1984
                'publishedDate' => $contentInfo->publishedDate,
1985
            ]
1986
        );
1987
    }
1988
1989
    /**
1990
     * Test for the updateContentMetadata() method.
1991
     *
1992
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1993
     *
1994
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1995
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1996
     */
1997
    public function testUpdateContentMetadataNotUpdatesContentVersion($content)
1998
    {
1999
        $this->assertEquals(1, $content->getVersionInfo()->versionNo);
2000
    }
2001
2002
    /**
2003
     * Test for the updateContentMetadata() method.
2004
     *
2005
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2006
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
2007
     */
2008
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnDuplicateRemoteId()
2009
    {
2010
        $content = $this->createContentVersion1();
2011
2012
        // Creates a metadata update struct
2013
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
2014
        $metadataUpdate->remoteId = self::MEDIA_REMOTE_ID;
2015
2016
        $this->expectException(APIInvalidArgumentException::class);
2017
        // specified remoteId is already used by the "Media" page.
2018
        $this->contentService->updateContentMetadata(
2019
            $content->contentInfo,
2020
            $metadataUpdate
2021
        );
2022
    }
2023
2024
    /**
2025
     * Test for the updateContentMetadata() method.
2026
     *
2027
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContentMetadata
2028
     */
2029
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnNoMetadataPropertiesSet()
2030
    {
2031
        $contentInfo = $this->contentService->loadContentInfo(4);
2032
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
2033
2034
        $this->expectException(APIInvalidArgumentException::class);
2035
        $this->contentService->updateContentMetadata($contentInfo, $contentMetadataUpdateStruct);
2036
    }
2037
2038
    /**
2039
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata
2040
     *
2041
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2042
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2043
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2044
     */
2045
    public function testUpdateContentAlwaysAvailable(): void
2046
    {
2047
        $repository = $this->getRepository();
2048
        $contentService = $repository->getContentService();
2049
2050
        $folder = $this->createFolder(['eng-GB' => 'Folder'], 2);
2051
2052
        $contentMetadataUpdate = $contentService->newContentMetadataUpdateStruct();
2053
        $contentMetadataUpdate->alwaysAvailable = !$folder->contentInfo->alwaysAvailable;
2054
        $contentService->updateContentMetadata($folder->contentInfo, $contentMetadataUpdate);
2055
2056
        $reloadedFolder = $contentService->loadContent($folder->id);
2057
        self::assertEquals(
2058
            $contentMetadataUpdate->alwaysAvailable,
2059
            $reloadedFolder->contentInfo->alwaysAvailable
2060
        );
2061
    }
2062
2063
    /**
2064
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata
2065
     *
2066
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2067
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2068
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2069
     */
2070
    public function testUpdateContentMainTranslation(): void
2071
    {
2072
        $repository = $this->getRepository();
2073
        $contentService = $repository->getContentService();
2074
        $locationService = $repository->getLocationService();
2075
2076
        // create a Content Type which is not always available by default
2077
        $contentType = $this->createSimpleContentType(
2078
            'test_t',
2079
            self::ENG_GB,
2080
            [
2081
                'name' => 'ezstring',
2082
            ],
2083
            false
2084
        );
2085
2086
        $contentCreate = $contentService->newContentCreateStruct(
2087
            $contentType,
2088
            self::ENG_US
2089
        );
2090
        $contentCreate->setField('name', 'My Content');
2091
        $content = $contentService->publishVersion(
2092
            $contentService->createContent(
2093
                $contentCreate,
2094
                [$locationService->newLocationCreateStruct(2)]
2095
            )->getVersionInfo()
2096
        );
2097
        // perform sanity check
2098
        self::assertFalse($content->contentInfo->alwaysAvailable);
2099
2100
        $updateStruct = $contentService->newContentMetadataUpdateStruct();
2101
        $updateStruct->mainLanguageCode = self::ENG_GB;
2102
2103
        $contentService->updateContentMetadata($content->contentInfo, $updateStruct);
2104
2105
        $reloadedContent = $contentService->loadContent($content->id);
2106
        self::assertEquals(self::ENG_GB, $reloadedContent->contentInfo->mainLanguageCode);
2107
2108
        // check that other properties remained unchanged
2109
        self::assertStructPropertiesCorrect(
2110
            $content->contentInfo,
2111
            $reloadedContent->contentInfo,
2112
            [
2113
                'id',
2114
                'contentTypeId',
2115
                'name',
2116
                'sectionId',
2117
                'currentVersionNo',
2118
                'published',
2119
                'ownerId',
2120
                'alwaysAvailable',
2121
                'remoteId',
2122
                'mainLocationId',
2123
                'status',
2124
            ]
2125
        );
2126
    }
2127
2128
    /**
2129
     * Test for the deleteContent() method.
2130
     *
2131
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2132
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2133
     */
2134
    public function testDeleteContent()
2135
    {
2136
        $contentVersion2 = $this->createContentVersion2();
2137
2138
        // Load the locations for this content object
2139
        $locations = $this->locationService->loadLocations($contentVersion2->contentInfo);
2140
2141
        // This will delete the content, all versions and the associated locations
2142
        $this->contentService->deleteContent($contentVersion2->contentInfo);
2143
2144
        $this->expectException(NotFoundException::class);
2145
2146
        foreach ($locations as $location) {
2147
            $this->locationService->loadLocation($location->id);
2148
        }
2149
    }
2150
2151
    /**
2152
     * Test for the deleteContent() method.
2153
     *
2154
     * Test for issue EZP-21057:
2155
     * "contentService: Unable to delete a content with an empty file attribute"
2156
     *
2157
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2158
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2159
     */
2160
    public function testDeleteContentWithEmptyBinaryField()
2161
    {
2162
        $contentVersion = $this->createContentVersion1EmptyBinaryField();
2163
2164
        // Load the locations for this content object
2165
        $locations = $this->locationService->loadLocations($contentVersion->contentInfo);
2166
2167
        // This will delete the content, all versions and the associated locations
2168
        $this->contentService->deleteContent($contentVersion->contentInfo);
2169
2170
        $this->expectException(NotFoundException::class);
2171
2172
        foreach ($locations as $location) {
2173
            $this->locationService->loadLocation($location->id);
2174
        }
2175
    }
2176
2177
    public function testCountContentDraftsReturnsZeroByDefault(): void
2178
    {
2179
        $this->assertSame(0, $this->contentService->countContentDrafts());
2180
    }
2181
2182
    public function testCountContentDrafts(): void
2183
    {
2184
        // Create 5 drafts
2185
        $this->createContentDrafts(5);
2186
2187
        $this->assertSame(5, $this->contentService->countContentDrafts());
2188
    }
2189
2190
    public function testCountContentDraftsForUsers(): void
2191
    {
2192
        $newUser = $this->createUserWithPolicies(
2193
            'new_user',
2194
            [
2195
                ['module' => 'content', 'function' => 'create'],
2196
                ['module' => 'content', 'function' => 'read'],
2197
                ['module' => 'content', 'function' => 'publish'],
2198
                ['module' => 'content', 'function' => 'edit'],
2199
            ]
2200
        );
2201
2202
        $previousUser = $this->permissionResolver->getCurrentUserReference();
2203
2204
        // Set new editor as user
2205
        $this->permissionResolver->setCurrentUserReference($newUser);
2206
2207
        // Create a content draft as newUser
2208
        $publishedContent = $this->createContentVersion1();
2209
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2210
2211
        // Reset to previous current user
2212
        $this->permissionResolver->setCurrentUserReference($previousUser);
2213
2214
        // Now $contentDrafts for the previous current user and the new user
2215
        $newUserDrafts = $this->contentService->countContentDrafts($newUser);
2216
        $previousUserDrafts = $this->contentService->countContentDrafts();
2217
2218
        $this->assertSame(1, $newUserDrafts);
2219
        $this->assertSame(0, $previousUserDrafts);
2220
    }
2221
2222
    /**
2223
     * Test for the loadContentDrafts() method.
2224
     *
2225
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2226
     */
2227
    public function testLoadContentDraftsReturnsEmptyArrayByDefault()
2228
    {
2229
        $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...
2230
2231
        $this->assertSame([], $contentDrafts);
2232
    }
2233
2234
    /**
2235
     * Test for the loadContentDrafts() method.
2236
     *
2237
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2238
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
2239
     */
2240
    public function testLoadContentDrafts()
2241
    {
2242
        // "Media" content object
2243
        $mediaContentInfo = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
2244
2245
        // "eZ Publish Demo Design ..." content object
2246
        $demoDesignContentInfo = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
2247
2248
        // Create some drafts
2249
        $this->contentService->createContentDraft($mediaContentInfo);
2250
        $this->contentService->createContentDraft($demoDesignContentInfo);
2251
2252
        // Now $contentDrafts should contain two drafted versions
2253
        $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...
2254
2255
        $actual = [
2256
            $draftedVersions[0]->status,
2257
            $draftedVersions[0]->getContentInfo()->remoteId,
2258
            $draftedVersions[1]->status,
2259
            $draftedVersions[1]->getContentInfo()->remoteId,
2260
        ];
2261
        sort($actual, SORT_STRING);
2262
2263
        $this->assertEquals(
2264
            [
2265
                VersionInfo::STATUS_DRAFT,
2266
                VersionInfo::STATUS_DRAFT,
2267
                self::DEMO_DESIGN_REMOTE_ID,
2268
                self::MEDIA_REMOTE_ID,
2269
            ],
2270
            $actual
2271
        );
2272
    }
2273
2274
    /**
2275
     * Test for the loadContentDrafts() method.
2276
     *
2277
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts($user)
2278
     */
2279
    public function testLoadContentDraftsWithFirstParameter()
2280
    {
2281
        $user = $this->createUserVersion1();
2282
2283
        // Get current user
2284
        $oldCurrentUser = $this->permissionResolver->getCurrentUserReference();
2285
2286
        // Set new editor as user
2287
        $this->permissionResolver->setCurrentUserReference($user);
2288
2289
        // "Media" content object
2290
        $mediaContentInfo = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
2291
2292
        // Create a content draft
2293
        $this->contentService->createContentDraft($mediaContentInfo);
2294
2295
        // Reset to previous current user
2296
        $this->permissionResolver->setCurrentUserReference($oldCurrentUser);
2297
2298
        // Now $contentDrafts for the previous current user and the new user
2299
        $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...
2300
        $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...
2301
2302
        $this->assertSame([], $oldCurrentUserDrafts);
2303
2304
        $this->assertEquals(
2305
            [
2306
                VersionInfo::STATUS_DRAFT,
2307
                self::MEDIA_REMOTE_ID,
2308
            ],
2309
            [
2310
                $newCurrentUserDrafts[0]->status,
2311
                $newCurrentUserDrafts[0]->getContentInfo()->remoteId,
2312
            ]
2313
        );
2314
        $this->assertTrue($newCurrentUserDrafts[0]->isDraft());
2315
        $this->assertFalse($newCurrentUserDrafts[0]->isArchived());
2316
        $this->assertFalse($newCurrentUserDrafts[0]->isPublished());
2317
    }
2318
2319
    /**
2320
     * Test for the loadContentDraftList() method.
2321
     *
2322
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2323
     */
2324
    public function testLoadContentDraftListWithPaginationParameters()
2325
    {
2326
        // Create some drafts
2327
        $publishedContent = $this->createContentVersion1();
2328
        $draftContentA = $this->contentService->createContentDraft($publishedContent->contentInfo);
2329
        $draftContentB = $this->contentService->createContentDraft($draftContentA->contentInfo);
2330
        $draftContentC = $this->contentService->createContentDraft($draftContentB->contentInfo);
2331
        $draftContentD = $this->contentService->createContentDraft($draftContentC->contentInfo);
2332
        $draftContentE = $this->contentService->createContentDraft($draftContentD->contentInfo);
2333
2334
        $draftsOnPage1 = $this->contentService->loadContentDraftList(null, 0, 2);
2335
        $draftsOnPage2 = $this->contentService->loadContentDraftList(null, 2, 2);
2336
2337
        $this->assertSame(5, $draftsOnPage1->totalCount);
2338
        $this->assertSame(5, $draftsOnPage2->totalCount);
2339
        $this->assertEquals($draftContentE->getVersionInfo(), $draftsOnPage1->items[0]->getVersionInfo());
2340
        $this->assertEquals($draftContentD->getVersionInfo(), $draftsOnPage1->items[1]->getVersionInfo());
2341
        $this->assertEquals($draftContentC->getVersionInfo(), $draftsOnPage2->items[0]->getVersionInfo());
2342
        $this->assertEquals($draftContentB->getVersionInfo(), $draftsOnPage2->items[1]->getVersionInfo());
2343
    }
2344
2345
    /**
2346
     * Test for the loadContentDraftList() method.
2347
     *
2348
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts($user)
2349
     */
2350
    public function testLoadContentDraftListWithForUserWithLimitation()
2351
    {
2352
        $oldUser = $this->permissionResolver->getCurrentUserReference();
2353
2354
        $parentContent = $this->createFolder(['eng-US' => 'parentFolder'], 2);
2355
        $content = $this->createFolder(['eng-US' => 'parentFolder'], $parentContent->contentInfo->mainLocationId);
2356
2357
        // User has limitation to read versions only for `$content`, not for `$parentContent`
2358
        $newUser = $this->createUserWithVersionReadLimitations([$content->contentInfo->mainLocationId]);
2359
2360
        $this->permissionResolver->setCurrentUserReference($newUser);
2361
2362
        $contentDraftUnauthorized = $this->contentService->createContentDraft($parentContent->contentInfo);
2363
        $contentDraftA = $this->contentService->createContentDraft($content->contentInfo);
2364
        $contentDraftB = $this->contentService->createContentDraft($content->contentInfo);
2365
2366
        $newUserDraftList = $this->contentService->loadContentDraftList($newUser, 0);
2367
        $this->assertSame(3, $newUserDraftList->totalCount);
2368
        $this->assertEquals($contentDraftB->getVersionInfo(), $newUserDraftList->items[0]->getVersionInfo());
2369
        $this->assertEquals($contentDraftA->getVersionInfo(), $newUserDraftList->items[1]->getVersionInfo());
2370
        $this->assertEquals(
2371
            new UnauthorizedContentDraftListItem('content', 'versionread', ['contentId' => $contentDraftUnauthorized->id]),
2372
            $newUserDraftList->items[2]
2373
        );
2374
2375
        // Reset to previous user
2376
        $this->permissionResolver->setCurrentUserReference($oldUser);
2377
2378
        $oldUserDraftList = $this->contentService->loadContentDraftList();
2379
2380
        $this->assertSame(0, $oldUserDraftList->totalCount);
2381
        $this->assertSame([], $oldUserDraftList->items);
2382
    }
2383
2384
    /**
2385
     * Test for the loadContentDraftList() method.
2386
     *
2387
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2388
     */
2389
    public function testLoadAllContentDrafts()
2390
    {
2391
        // Create more drafts then default pagination limit
2392
        $this->createContentDrafts(12);
2393
2394
        $this->assertCount(12, $this->contentService->loadContentDraftList());
2395
    }
2396
2397
    /**
2398
     * Test for the loadVersionInfo() method.
2399
     *
2400
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo($contentInfo, $versionNo)
2401
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2402
     */
2403
    public function testLoadVersionInfoWithSecondParameter()
2404
    {
2405
        $publishedContent = $this->createContentVersion1();
2406
2407
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2408
2409
        // Will return the VersionInfo of the $draftContent
2410
        $versionInfo = $this->contentService->loadVersionInfoById($publishedContent->id, 2);
2411
2412
        $this->assertEquals(2, $versionInfo->versionNo);
2413
2414
        // Check that ContentInfo contained in VersionInfo has correct main Location id set
2415
        $this->assertEquals(
2416
            $publishedContent->getVersionInfo()->getContentInfo()->mainLocationId,
2417
            $versionInfo->getContentInfo()->mainLocationId
2418
        );
2419
    }
2420
2421
    /**
2422
     * Test for the loadVersionInfo() method.
2423
     *
2424
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo($contentInfo, $versionNo)
2425
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoWithSecondParameter
2426
     */
2427
    public function testLoadVersionInfoThrowsNotFoundExceptionWithSecondParameter()
2428
    {
2429
        $draft = $this->createContentDraftVersion1();
2430
2431
        $this->expectException(NotFoundException::class);
2432
2433
        // This call will fail with a "NotFoundException", because not versionNo 2 exists for this content object.
2434
        $this->contentService->loadVersionInfo($draft->contentInfo, 2);
2435
    }
2436
2437
    /**
2438
     * Test for the loadVersionInfoById() method.
2439
     *
2440
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById($contentId, $versionNo)
2441
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoWithSecondParameter
2442
     */
2443
    public function testLoadVersionInfoByIdWithSecondParameter()
2444
    {
2445
        $publishedContent = $this->createContentVersion1();
2446
2447
        $draftContent = $this->contentService->createContentDraft($publishedContent->contentInfo);
2448
2449
        // Will return the VersionInfo of the $draftContent
2450
        $versionInfo = $this->contentService->loadVersionInfoById($publishedContent->id, 2);
2451
2452
        $this->assertEquals(2, $versionInfo->versionNo);
2453
2454
        // Check that ContentInfo contained in VersionInfo has correct main Location id set
2455
        $this->assertEquals(
2456
            $publishedContent->getVersionInfo()->getContentInfo()->mainLocationId,
2457
            $versionInfo->getContentInfo()->mainLocationId
2458
        );
2459
2460
        return [
2461
            'versionInfo' => $versionInfo,
2462
            'draftContent' => $draftContent,
2463
        ];
2464
    }
2465
2466
    /**
2467
     * Test for the returned value of the loadVersionInfoById() method.
2468
     *
2469
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoByIdWithSecondParameter
2470
     * @covers \eZ\Publish\API\Repository\ContentService::loadVersionInfoById
2471
     *
2472
     * @param array $data
2473
     */
2474
    public function testLoadVersionInfoByIdWithSecondParameterSetsExpectedVersionInfo(array $data)
2475
    {
2476
        /** @var VersionInfo $versionInfo */
2477
        $versionInfo = $data['versionInfo'];
2478
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $draftContent */
2479
        $draftContent = $data['draftContent'];
2480
2481
        $this->assertPropertiesCorrect(
2482
            [
2483
                'names' => [
2484
                    self::ENG_US => 'An awesome forum',
2485
                ],
2486
                'contentInfo' => new ContentInfo([
2487
                    'id' => $draftContent->contentInfo->id,
2488
                    'contentTypeId' => 28,
2489
                    'name' => 'An awesome forum',
2490
                    'sectionId' => 1,
2491
                    'currentVersionNo' => 1,
2492
                    'published' => true,
2493
                    'ownerId' => 14,
2494
                    // this Content Object is created at the test runtime
2495
                    'modificationDate' => $versionInfo->contentInfo->modificationDate,
2496
                    'publishedDate' => $versionInfo->contentInfo->publishedDate,
2497
                    'alwaysAvailable' => 1,
2498
                    'remoteId' => 'abcdef0123456789abcdef0123456789',
2499
                    'mainLanguageCode' => self::ENG_US,
2500
                    'mainLocationId' => $draftContent->contentInfo->mainLocationId,
2501
                    'status' => ContentInfo::STATUS_PUBLISHED,
2502
                ]),
2503
                'id' => $draftContent->versionInfo->id,
2504
                'versionNo' => 2,
2505
                'creatorId' => 14,
2506
                'status' => 0,
2507
                'initialLanguageCode' => self::ENG_US,
2508
                'languageCodes' => [
2509
                    self::ENG_US,
2510
                ],
2511
            ],
2512
            $versionInfo
2513
        );
2514
    }
2515
2516
    /**
2517
     * Test for the loadVersionInfoById() method.
2518
     *
2519
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById($contentId, $versionNo)
2520
     */
2521
    public function testLoadVersionInfoByIdThrowsNotFoundExceptionWithSecondParameter()
2522
    {
2523
        $content = $this->createContentVersion1();
2524
2525
        $this->expectException(NotFoundException::class);
2526
2527
        // This call will fail with a "NotFoundException", because not versionNo 2 exists for this content object.
2528
        $this->contentService->loadVersionInfoById($content->id, 2);
2529
    }
2530
2531
    /**
2532
     * Test for the loadContentByVersionInfo() method.
2533
     *
2534
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByVersionInfo($versionInfo, $languages)
2535
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
2536
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByVersionInfo
2537
     */
2538
    public function testLoadContentByVersionInfoWithSecondParameter()
2539
    {
2540
        $sectionId = $this->generateId('section', 1);
2541
        $contentTypeService = $this->getRepository()->getContentTypeService();
2542
2543
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
2544
2545
        $contentCreateStruct = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
2546
2547
        $contentCreateStruct->setField('name', 'Sindelfingen forum²');
2548
2549
        $contentCreateStruct->setField('name', 'Sindelfingen forum²³', self::ENG_GB);
2550
2551
        $contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
2552
        // $sectionId contains the ID of section 1
2553
        $contentCreateStruct->sectionId = $sectionId;
2554
        $contentCreateStruct->alwaysAvailable = true;
2555
2556
        // Create a new content draft
2557
        $content = $this->contentService->createContent($contentCreateStruct);
2558
2559
        // Now publish this draft
2560
        $publishedContent = $this->contentService->publishVersion($content->getVersionInfo());
2561
2562
        // Will return a content instance with fields in "eng-US"
2563
        $reloadedContent = $this->contentService->loadContentByVersionInfo(
2564
            $publishedContent->getVersionInfo(),
2565
            [
2566
                self::ENG_GB,
2567
            ],
2568
            false
2569
        );
2570
2571
        $actual = [];
2572
        foreach ($reloadedContent->getFields() as $field) {
2573
            $actual[] = new Field(
2574
                [
2575
                    'id' => 0,
2576
                    'value' => $field->value !== null, // Actual value tested by FieldType integration tests
2577
                    'languageCode' => $field->languageCode,
2578
                    'fieldDefIdentifier' => $field->fieldDefIdentifier,
2579
                ]
2580
            );
2581
        }
2582
        usort(
2583
            $actual,
2584
            function ($field1, $field2) {
2585
                if (0 === ($return = strcasecmp($field1->fieldDefIdentifier, $field2->fieldDefIdentifier))) {
2586
                    return strcasecmp($field1->languageCode, $field2->languageCode);
2587
                }
2588
2589
                return $return;
2590
            }
2591
        );
2592
2593
        $expected = [
2594
            new Field(
2595
                [
2596
                    'id' => 0,
2597
                    'value' => true,
2598
                    'languageCode' => self::ENG_GB,
2599
                    'fieldDefIdentifier' => 'description',
2600
                ]
2601
            ),
2602
            new Field(
2603
                [
2604
                    'id' => 0,
2605
                    'value' => true,
2606
                    'languageCode' => self::ENG_GB,
2607
                    'fieldDefIdentifier' => 'name',
2608
                ]
2609
            ),
2610
        ];
2611
2612
        $this->assertEquals($expected, $actual);
2613
    }
2614
2615
    /**
2616
     * Test for the loadContentByContentInfo() method.
2617
     *
2618
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages)
2619
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
2620
     */
2621
    public function testLoadContentByContentInfoWithLanguageParameters()
2622
    {
2623
        $sectionId = $this->generateId('section', 1);
2624
        $contentTypeService = $this->getRepository()->getContentTypeService();
2625
2626
        $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
2627
2628
        $contentCreateStruct = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
2629
2630
        $contentCreateStruct->setField('name', 'Sindelfingen forum²');
2631
2632
        $contentCreateStruct->setField('name', 'Sindelfingen forum²³', self::ENG_GB);
2633
2634
        $contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
2635
        // $sectionId contains the ID of section 1
2636
        $contentCreateStruct->sectionId = $sectionId;
2637
        $contentCreateStruct->alwaysAvailable = true;
2638
2639
        // Create a new content draft
2640
        $content = $this->contentService->createContent($contentCreateStruct);
2641
2642
        // Now publish this draft
2643
        $publishedContent = $this->contentService->publishVersion($content->getVersionInfo());
2644
2645
        // Will return a content instance with fields in "eng-US"
2646
        $reloadedContent = $this->contentService->loadContentByContentInfo(
2647
            $publishedContent->contentInfo,
2648
            [
2649
                self::ENG_US,
2650
            ],
2651
            null,
2652
            false
2653
        );
2654
2655
        $actual = $this->normalizeFields($reloadedContent->getFields());
2656
2657
        $expected = [
2658
            new Field(
2659
                [
2660
                    'id' => 0,
2661
                    'value' => true,
2662
                    'languageCode' => self::ENG_US,
2663
                    'fieldDefIdentifier' => 'description',
2664
                    'fieldTypeIdentifier' => 'ezrichtext',
2665
                ]
2666
            ),
2667
            new Field(
2668
                [
2669
                    'id' => 0,
2670
                    'value' => true,
2671
                    'languageCode' => self::ENG_US,
2672
                    'fieldDefIdentifier' => 'name',
2673
                    'fieldTypeIdentifier' => 'ezstring',
2674
                ]
2675
            ),
2676
        ];
2677
2678
        $this->assertEquals($expected, $actual);
2679
2680
        // Will return a content instance with fields in "eng-GB" (versions prior to 6.0.0-beta9 returned "eng-US" also)
2681
        $reloadedContent = $this->contentService->loadContentByContentInfo(
2682
            $publishedContent->contentInfo,
2683
            [
2684
                self::ENG_GB,
2685
            ],
2686
            null,
2687
            true
2688
        );
2689
2690
        $actual = $this->normalizeFields($reloadedContent->getFields());
2691
2692
        $expected = [
2693
            new Field(
2694
                [
2695
                    'id' => 0,
2696
                    'value' => true,
2697
                    'languageCode' => self::ENG_GB,
2698
                    'fieldDefIdentifier' => 'description',
2699
                    'fieldTypeIdentifier' => 'ezrichtext',
2700
                ]
2701
            ),
2702
            new Field(
2703
                [
2704
                    'id' => 0,
2705
                    'value' => true,
2706
                    'languageCode' => self::ENG_GB,
2707
                    'fieldDefIdentifier' => 'name',
2708
                    'fieldTypeIdentifier' => 'ezstring',
2709
                ]
2710
            ),
2711
        ];
2712
2713
        $this->assertEquals($expected, $actual);
2714
2715
        // Will return a content instance with fields in main language "eng-US", as "fre-FR" does not exists
2716
        $reloadedContent = $this->contentService->loadContentByContentInfo(
2717
            $publishedContent->contentInfo,
2718
            [
2719
                'fre-FR',
2720
            ],
2721
            null,
2722
            true
2723
        );
2724
2725
        $actual = $this->normalizeFields($reloadedContent->getFields());
2726
2727
        $expected = [
2728
            new Field(
2729
                [
2730
                    'id' => 0,
2731
                    'value' => true,
2732
                    'languageCode' => self::ENG_US,
2733
                    'fieldDefIdentifier' => 'description',
2734
                    'fieldTypeIdentifier' => 'ezrichtext',
2735
                ]
2736
            ),
2737
            new Field(
2738
                [
2739
                    'id' => 0,
2740
                    'value' => true,
2741
                    'languageCode' => self::ENG_US,
2742
                    'fieldDefIdentifier' => 'name',
2743
                    'fieldTypeIdentifier' => 'ezstring',
2744
                ]
2745
            ),
2746
        ];
2747
2748
        $this->assertEquals($expected, $actual);
2749
    }
2750
2751
    /**
2752
     * Test for the loadContentByContentInfo() method.
2753
     *
2754
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages, $versionNo)
2755
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
2756
     */
2757
    public function testLoadContentByContentInfoWithVersionNumberParameter()
2758
    {
2759
        $publishedContent = $this->createContentVersion1();
2760
2761
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2762
2763
        // This content instance is identical to $draftContent
2764
        $draftContentReloaded = $this->contentService->loadContentByContentInfo(
2765
            $publishedContent->contentInfo,
2766
            null,
2767
            2
2768
        );
2769
2770
        $this->assertEquals(
2771
            2,
2772
            $draftContentReloaded->getVersionInfo()->versionNo
2773
        );
2774
2775
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2776
        $this->assertEquals(
2777
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2778
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2779
        );
2780
    }
2781
2782
    /**
2783
     * Test for the loadContentByContentInfo() method.
2784
     *
2785
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages, $versionNo)
2786
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfoWithVersionNumberParameter
2787
     */
2788
    public function testLoadContentByContentInfoThrowsNotFoundExceptionWithVersionNumberParameter()
2789
    {
2790
        $content = $this->createContentVersion1();
2791
2792
        $this->expectException(NotFoundException::class);
2793
2794
        // This call will fail with a "NotFoundException", because no content with versionNo = 2 exists.
2795
        $this->contentService->loadContentByContentInfo($content->contentInfo, null, 2);
2796
    }
2797
2798
    /**
2799
     * Test for the loadContent() method.
2800
     *
2801
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages)
2802
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2803
     */
2804
    public function testLoadContentWithPrioritizedLanguages()
2805
    {
2806
        $draft = $this->createMultipleLanguageDraftVersion1();
2807
2808
        // This draft contains those fields localized with "eng-GB"
2809
        $draftLocalized = $this->contentService->loadContent($draft->id, [self::ENG_GB], null, false);
2810
2811
        $this->assertLocaleFieldsEquals($draftLocalized->getFields(), self::ENG_GB);
2812
2813
        return $draftLocalized;
2814
    }
2815
2816
    /**
2817
     * Test for the loadContent() method using undefined translation.
2818
     *
2819
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithPrioritizedLanguages
2820
     *
2821
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
2822
     */
2823
    public function testLoadContentWithPrioritizedLanguagesThrowsNotFoundException(Content $contentDraft)
2824
    {
2825
        $this->expectException(NotFoundException::class);
2826
2827
        $this->contentService->loadContent($contentDraft->id, [self::GER_DE], null, false);
2828
    }
2829
2830
    /**
2831
     * Test for the loadContent() method.
2832
     *
2833
     * @see \eZ\Publish\API\Repository\ContentService::loadContent
2834
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithPrioritizedLanguages
2835
     */
2836
    public function testLoadContentPassTroughPrioritizedLanguagesToContentType(Content $content): void
2837
    {
2838
        $contentTypeService = $this->getRepository()->getContentTypeService();
2839
2840
        $contentType = $contentTypeService->loadContentType(
2841
            $content->contentInfo->contentTypeId,
2842
            [self::ENG_GB]
2843
        );
2844
2845
        $this->assertEquals($contentType, $content->getContentType());
2846
    }
2847
2848
    /**
2849
     * Test for the loadContent() method.
2850
     *
2851
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages, $versionNo)
2852
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2853
     */
2854
    public function testLoadContentWithThirdParameter()
2855
    {
2856
        $publishedContent = $this->createContentVersion1();
2857
2858
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2859
2860
        // This content instance is identical to $draftContent
2861
        $draftContentReloaded = $this->contentService->loadContent($publishedContent->id, null, 2);
2862
2863
        $this->assertEquals(2, $draftContentReloaded->getVersionInfo()->versionNo);
2864
2865
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2866
        $this->assertEquals(
2867
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2868
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2869
        );
2870
    }
2871
2872
    /**
2873
     * Test for the loadContent() method.
2874
     *
2875
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages, $versionNo)
2876
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithThirdParameter
2877
     */
2878
    public function testLoadContentThrowsNotFoundExceptionWithThirdParameter()
2879
    {
2880
        $content = $this->createContentVersion1();
2881
2882
        $this->expectException(NotFoundException::class);
2883
2884
        // This call will fail with a "NotFoundException", because for this content object no versionNo=2 exists.
2885
        $this->contentService->loadContent($content->id, null, 2);
2886
    }
2887
2888
    /**
2889
     * Test for the loadContentByRemoteId() method.
2890
     *
2891
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages)
2892
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2893
     */
2894
    public function testLoadContentByRemoteIdWithSecondParameter()
2895
    {
2896
        $draft = $this->createMultipleLanguageDraftVersion1();
2897
2898
        $this->contentService->publishVersion($draft->versionInfo);
2899
2900
        // This draft contains those fields localized with "eng-GB"
2901
        $draftLocalized = $this->contentService->loadContentByRemoteId(
2902
            $draft->contentInfo->remoteId,
2903
            [self::ENG_GB],
2904
            null,
2905
            false
2906
        );
2907
2908
        $this->assertLocaleFieldsEquals($draftLocalized->getFields(), self::ENG_GB);
2909
    }
2910
2911
    /**
2912
     * Test for the loadContentByRemoteId() method.
2913
     *
2914
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages, $versionNo)
2915
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2916
     */
2917
    public function testLoadContentByRemoteIdWithThirdParameter()
2918
    {
2919
        $publishedContent = $this->createContentVersion1();
2920
2921
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2922
2923
        // This content instance is identical to $draftContent
2924
        $draftContentReloaded = $this->contentService->loadContentByRemoteId(
2925
            $publishedContent->contentInfo->remoteId,
2926
            null,
2927
            2
2928
        );
2929
2930
        $this->assertEquals(2, $draftContentReloaded->getVersionInfo()->versionNo);
2931
2932
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2933
        $this->assertEquals(
2934
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2935
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2936
        );
2937
    }
2938
2939
    /**
2940
     * Test for the loadContentByRemoteId() method.
2941
     *
2942
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages, $versionNo)
2943
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteIdWithThirdParameter
2944
     */
2945
    public function testLoadContentByRemoteIdThrowsNotFoundExceptionWithThirdParameter()
2946
    {
2947
        $content = $this->createContentVersion1();
2948
2949
        $this->expectException(NotFoundException::class);
2950
2951
        // This call will fail with a "NotFoundException", because for this content object no versionNo=2 exists.
2952
        $this->contentService->loadContentByRemoteId(
2953
            $content->contentInfo->remoteId,
2954
            null,
2955
            2
2956
        );
2957
    }
2958
2959
    /**
2960
     * Test that retrieval of translated name field respects prioritized language list.
2961
     *
2962
     * @dataProvider getPrioritizedLanguageList
2963
     *
2964
     * @param string[]|null $languageCodes
2965
     */
2966
    public function testLoadContentWithPrioritizedLanguagesList($languageCodes)
2967
    {
2968
        $content = $this->createContentVersion2();
2969
2970
        $content = $this->contentService->loadContent($content->id, $languageCodes);
2971
2972
        $expectedName = $content->getVersionInfo()->getName(
2973
            isset($languageCodes[0]) ? $languageCodes[0] : null
2974
        );
2975
        $nameValue = $content->getFieldValue('name');
2976
        /** @var \eZ\Publish\Core\FieldType\TextLine\Value $nameValue */
2977
        self::assertEquals($expectedName, $nameValue->text);
2978
        self::assertEquals($expectedName, $content->getVersionInfo()->getName());
2979
        // Also check value on shortcut method on content
2980
        self::assertEquals($expectedName, $content->getName());
2981
    }
2982
2983
    /**
2984
     * @return array
2985
     */
2986
    public function getPrioritizedLanguageList()
2987
    {
2988
        return [
2989
            [[self::ENG_US]],
2990
            [[self::ENG_GB]],
2991
            [[self::ENG_GB, self::ENG_US]],
2992
            [[self::ENG_US, self::ENG_GB]],
2993
        ];
2994
    }
2995
2996
    /**
2997
     * Test for the deleteVersion() method.
2998
     *
2999
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3000
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3001
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3002
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3003
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
3004
     */
3005
    public function testDeleteVersion()
3006
    {
3007
        $content = $this->createContentVersion1();
3008
3009
        // Create new draft, because published or last version of the Content can't be deleted
3010
        $draft = $this->contentService->createContentDraft(
3011
            $content->getVersionInfo()->getContentInfo()
3012
        );
3013
3014
        // Delete the previously created draft
3015
        $this->contentService->deleteVersion($draft->getVersionInfo());
3016
3017
        $versions = $this->contentService->loadVersions($content->getVersionInfo()->getContentInfo());
3018
3019
        $this->assertCount(1, $versions);
3020
        $this->assertEquals(
3021
            $content->getVersionInfo()->id,
3022
            $versions[0]->id
3023
        );
3024
    }
3025
3026
    /**
3027
     * Test for the deleteVersion() method.
3028
     *
3029
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3030
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3031
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3032
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3033
     */
3034
    public function testDeleteVersionThrowsBadStateExceptionOnPublishedVersion()
3035
    {
3036
        $content = $this->createContentVersion1();
3037
3038
        $this->expectException(BadStateException::class);
3039
3040
        // This call will fail with a "BadStateException", because the content version is currently published.
3041
        $this->contentService->deleteVersion($content->getVersionInfo());
3042
    }
3043
3044
    /**
3045
     * Test for the deleteVersion() method.
3046
     *
3047
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3048
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3049
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3050
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3051
     */
3052
    public function testDeleteVersionWorksIfOnlyVersionIsDraft()
3053
    {
3054
        $draft = $this->createContentDraftVersion1();
3055
3056
        $this->contentService->deleteVersion($draft->getVersionInfo());
3057
3058
        $this->expectException(NotFoundException::class);
3059
3060
        // This call will fail with a "NotFound", because we allow to delete content if remaining version is draft.
3061
        // Can normally only happen if there where always only a draft to begin with, simplifies UI edit API usage.
3062
        $this->contentService->loadContent($draft->id);
3063
    }
3064
3065
    /**
3066
     * Test for the loadVersions() method.
3067
     *
3068
     * @see \eZ\Publish\API\Repository\ContentService::loadVersions()
3069
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3070
     *
3071
     * @return VersionInfo[]
3072
     */
3073
    public function testLoadVersions()
3074
    {
3075
        $contentVersion2 = $this->createContentVersion2();
3076
3077
        // Load versions of this ContentInfo instance
3078
        $versions = $this->contentService->loadVersions($contentVersion2->contentInfo);
3079
3080
        $expectedVersionsOrder = [
3081
            $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 1),
3082
            $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 2),
3083
        ];
3084
3085
        $this->assertEquals($expectedVersionsOrder, $versions);
3086
3087
        return $versions;
3088
    }
3089
3090
    /**
3091
     * Test for the loadVersions() method.
3092
     *
3093
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersions
3094
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersions
3095
     *
3096
     * @param \eZ\Publish\API\Repository\Values\Content\VersionInfo[] $versions
3097
     */
3098
    public function testLoadVersionsSetsExpectedVersionInfo(array $versions)
3099
    {
3100
        $this->assertCount(2, $versions);
3101
3102
        $expectedVersions = [
3103
            [
3104
                'versionNo' => 1,
3105
                'creatorId' => 14,
3106
                'status' => VersionInfo::STATUS_ARCHIVED,
3107
                'initialLanguageCode' => self::ENG_US,
3108
                'languageCodes' => [self::ENG_US],
3109
            ],
3110
            [
3111
                'versionNo' => 2,
3112
                'creatorId' => 10,
3113
                'status' => VersionInfo::STATUS_PUBLISHED,
3114
                'initialLanguageCode' => self::ENG_US,
3115
                'languageCodes' => [self::ENG_US, self::ENG_GB],
3116
            ],
3117
        ];
3118
3119
        $this->assertPropertiesCorrect($expectedVersions[0], $versions[0]);
3120
        $this->assertPropertiesCorrect($expectedVersions[1], $versions[1]);
3121
        $this->assertEquals(
3122
            $versions[0]->creationDate->getTimestamp(),
3123
            $versions[1]->creationDate->getTimestamp(),
3124
            'Creation time did not match within delta of 2 seconds',
3125
            2
3126
        );
3127
        $this->assertEquals(
3128
            $versions[0]->modificationDate->getTimestamp(),
3129
            $versions[1]->modificationDate->getTimestamp(),
3130
            'Creation time did not match within delta of 2 seconds',
3131
            2
3132
        );
3133
        $this->assertTrue($versions[0]->isArchived());
3134
        $this->assertFalse($versions[0]->isDraft());
3135
        $this->assertFalse($versions[0]->isPublished());
3136
3137
        $this->assertTrue($versions[1]->isPublished());
3138
        $this->assertFalse($versions[1]->isDraft());
3139
        $this->assertFalse($versions[1]->isArchived());
3140
    }
3141
3142
    /**
3143
     * Test for the copyContent() method.
3144
     *
3145
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
3146
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3147
     * @group field-type
3148
     */
3149
    public function testCopyContent()
3150
    {
3151
        $parentLocationId = $this->generateId('location', 56);
3152
3153
        $contentVersion2 = $this->createMultipleLanguageContentVersion2();
3154
3155
        // Configure new target location
3156
        $targetLocationCreate = $this->locationService->newLocationCreateStruct($parentLocationId);
3157
3158
        $targetLocationCreate->priority = 42;
3159
        $targetLocationCreate->hidden = true;
3160
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3161
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3162
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3163
3164
        // Copy content with all versions and drafts
3165
        $contentCopied = $this->contentService->copyContent(
3166
            $contentVersion2->contentInfo,
3167
            $targetLocationCreate
3168
        );
3169
3170
        $this->assertInstanceOf(
3171
            Content::class,
3172
            $contentCopied
3173
        );
3174
3175
        $this->assertNotEquals(
3176
            $contentVersion2->contentInfo->remoteId,
3177
            $contentCopied->contentInfo->remoteId
3178
        );
3179
3180
        $this->assertNotEquals(
3181
            $contentVersion2->id,
3182
            $contentCopied->id
3183
        );
3184
3185
        $this->assertEquals(
3186
            2,
3187
            count($this->contentService->loadVersions($contentCopied->contentInfo))
3188
        );
3189
3190
        $this->assertEquals(2, $contentCopied->getVersionInfo()->versionNo);
3191
3192
        $this->assertAllFieldsEquals($contentCopied->getFields());
3193
3194
        $this->assertDefaultContentStates($contentCopied->contentInfo);
3195
3196
        $this->assertNotNull(
3197
            $contentCopied->contentInfo->mainLocationId,
3198
            'Expected main location to be set given we provided a LocationCreateStruct'
3199
        );
3200
    }
3201
3202
    /**
3203
     * Test for the copyContent() method with ezsettings.default.content.retain_owner_on_copy set to false
3204
     * See settings/test/integration_legacy.yml for service override.
3205
     *
3206
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
3207
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3208
     * @group field-type
3209
     */
3210
    public function testCopyContentWithNewOwner()
3211
    {
3212
        $parentLocationId = $this->generateId('location', 56);
3213
3214
        $userService = $this->getRepository()->getUserService();
3215
3216
        $owner = $this->createUser('new_owner', 'foo', 'bar');
3217
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $contentVersion2 */
3218
        $contentVersion2 = $this->createContentDraftVersion1(
3219
            $parentLocationId,
3220
            self::FORUM_IDENTIFIER,
3221
            'name',
3222
            $owner
3223
        );
3224
3225
        // Configure new target location
3226
        $targetLocationCreate = $this->locationService->newLocationCreateStruct($parentLocationId);
3227
3228
        $targetLocationCreate->priority = 42;
3229
        $targetLocationCreate->hidden = true;
3230
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3231
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3232
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3233
3234
        $this->contentService->publishVersion($contentVersion2->versionInfo);
3235
        $this->contentService->createContentDraft($contentVersion2->contentInfo);
3236
3237
        // Copy content with all versions and drafts
3238
        $contentCopied = $this->contentService->copyContent(
3239
            $contentVersion2->contentInfo,
3240
            $targetLocationCreate
3241
        );
3242
3243
        $this->assertEquals(
3244
            $owner->id,
3245
            $contentVersion2->contentInfo->ownerId
3246
        );
3247
        $newOwnerId = $userService->loadUserByLogin('admin')->getUserId();
3248
        $this->assertEquals(
3249
            $newOwnerId,
3250
            $contentCopied->contentInfo->ownerId
3251
        );
3252
        $versions = $this->contentService->loadVersions($contentCopied->contentInfo);
3253
        $this->assertCount(2, $versions);
3254
3255
        foreach ($versions as $version) {
3256
            $this->assertEquals(
3257
                $newOwnerId,
3258
                $version->creatorId
3259
            );
3260
        }
3261
    }
3262
3263
    /**
3264
     * Test for the copyContent() method.
3265
     *
3266
     * @see \eZ\Publish\API\Repository\ContentService::copyContent($contentInfo, $destinationLocationCreateStruct, $versionInfo)
3267
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
3268
     */
3269
    public function testCopyContentWithGivenVersion()
3270
    {
3271
        $parentLocationId = $this->generateId('location', 56);
3272
3273
        $contentVersion2 = $this->createContentVersion2();
3274
3275
        // Configure new target location
3276
        $targetLocationCreate = $this->locationService->newLocationCreateStruct($parentLocationId);
3277
3278
        $targetLocationCreate->priority = 42;
3279
        $targetLocationCreate->hidden = true;
3280
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3281
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3282
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3283
3284
        // Copy only the initial version
3285
        $contentCopied = $this->contentService->copyContent(
3286
            $contentVersion2->contentInfo,
3287
            $targetLocationCreate,
3288
            $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 1)
3289
        );
3290
3291
        $this->assertInstanceOf(
3292
            Content::class,
3293
            $contentCopied
3294
        );
3295
3296
        $this->assertNotEquals(
3297
            $contentVersion2->contentInfo->remoteId,
3298
            $contentCopied->contentInfo->remoteId
3299
        );
3300
3301
        $this->assertNotEquals(
3302
            $contentVersion2->id,
3303
            $contentCopied->id
3304
        );
3305
3306
        $this->assertEquals(
3307
            1,
3308
            count($this->contentService->loadVersions($contentCopied->contentInfo))
3309
        );
3310
3311
        $this->assertEquals(1, $contentCopied->getVersionInfo()->versionNo);
3312
3313
        $this->assertNotNull(
3314
            $contentCopied->contentInfo->mainLocationId,
3315
            'Expected main location to be set given we provided a LocationCreateStruct'
3316
        );
3317
    }
3318
3319
    /**
3320
     * Test for the addRelation() method.
3321
     *
3322
     * @return \eZ\Publish\API\Repository\Values\Content\Content
3323
     *
3324
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3325
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3326
     */
3327
    public function testAddRelation()
3328
    {
3329
        $draft = $this->createContentDraftVersion1();
3330
3331
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3332
3333
        // Create relation between new content object and "Media" page
3334
        $relation = $this->contentService->addRelation(
3335
            $draft->getVersionInfo(),
3336
            $media
3337
        );
3338
3339
        $this->assertInstanceOf(
3340
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Relation',
3341
            $relation
3342
        );
3343
3344
        return $this->contentService->loadRelations($draft->getVersionInfo());
3345
    }
3346
3347
    /**
3348
     * Test for the addRelation() method.
3349
     *
3350
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3351
     *
3352
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3353
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3354
     */
3355
    public function testAddRelationAddsRelationToContent($relations)
3356
    {
3357
        $this->assertEquals(
3358
            1,
3359
            count($relations)
3360
        );
3361
    }
3362
3363
    /**
3364
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3365
     */
3366
    protected function assertExpectedRelations($relations)
3367
    {
3368
        $this->assertEquals(
3369
            [
3370
                'type' => Relation::COMMON,
3371
                'sourceFieldDefinitionIdentifier' => null,
3372
                'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3373
                'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3374
            ],
3375
            [
3376
                'type' => $relations[0]->type,
3377
                'sourceFieldDefinitionIdentifier' => $relations[0]->sourceFieldDefinitionIdentifier,
3378
                'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3379
                'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3380
            ]
3381
        );
3382
    }
3383
3384
    /**
3385
     * Test for the addRelation() method.
3386
     *
3387
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3388
     *
3389
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3390
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3391
     */
3392
    public function testAddRelationSetsExpectedRelations($relations)
3393
    {
3394
        $this->assertExpectedRelations($relations);
3395
    }
3396
3397
    /**
3398
     * Test for the createContentDraft() method.
3399
     *
3400
     * @return \eZ\Publish\API\Repository\Values\Content\Relation[]
3401
     *
3402
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
3403
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelationSetsExpectedRelations
3404
     */
3405
    public function testCreateContentDraftWithRelations()
3406
    {
3407
        $draft = $this->createContentDraftVersion1();
3408
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3409
3410
        // Create relation between new content object and "Media" page
3411
        $this->contentService->addRelation(
3412
            $draft->getVersionInfo(),
3413
            $media
3414
        );
3415
3416
        $content = $this->contentService->publishVersion($draft->versionInfo);
3417
        $newDraft = $this->contentService->createContentDraft($content->contentInfo);
3418
3419
        return $this->contentService->loadRelations($newDraft->getVersionInfo());
3420
    }
3421
3422
    /**
3423
     * Test for the createContentDraft() method.
3424
     *
3425
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3426
     *
3427
     * @return \eZ\Publish\API\Repository\Values\Content\Relation[]
3428
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraftWithRelations
3429
     */
3430
    public function testCreateContentDraftWithRelationsCreatesRelations($relations)
3431
    {
3432
        $this->assertEquals(
3433
            1,
3434
            count($relations)
3435
        );
3436
3437
        return $relations;
3438
    }
3439
3440
    /**
3441
     * Test for the createContentDraft() method.
3442
     *
3443
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3444
     *
3445
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraftWithRelationsCreatesRelations
3446
     */
3447
    public function testCreateContentDraftWithRelationsCreatesExpectedRelations($relations)
3448
    {
3449
        $this->assertExpectedRelations($relations);
3450
    }
3451
3452
    /**
3453
     * Test for the addRelation() method.
3454
     *
3455
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3456
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3457
     */
3458
    public function testAddRelationThrowsBadStateException()
3459
    {
3460
        $content = $this->createContentVersion1();
3461
3462
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3463
3464
        $this->expectException(BadStateException::class);
3465
3466
        // This call will fail with a "BadStateException", because content is published and not a draft.
3467
        $this->contentService->addRelation(
3468
            $content->getVersionInfo(),
3469
            $media
3470
        );
3471
    }
3472
3473
    /**
3474
     * Test for the loadRelations() method.
3475
     *
3476
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3477
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3478
     */
3479
    public function testLoadRelations()
3480
    {
3481
        $draft = $this->createContentDraftVersion1();
3482
3483
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3484
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
3485
3486
        // Create relation between new content object and "Media" page
3487
        $this->contentService->addRelation(
3488
            $draft->getVersionInfo(),
3489
            $media
3490
        );
3491
3492
        // Create another relation with the "Demo Design" page
3493
        $this->contentService->addRelation(
3494
            $draft->getVersionInfo(),
3495
            $demoDesign
3496
        );
3497
3498
        $relations = $this->contentService->loadRelations($draft->getVersionInfo());
3499
3500
        usort(
3501
            $relations,
3502
            function ($rel1, $rel2) {
3503
                return strcasecmp(
3504
                    $rel2->getDestinationContentInfo()->remoteId,
3505
                    $rel1->getDestinationContentInfo()->remoteId
3506
                );
3507
            }
3508
        );
3509
3510
        $this->assertEquals(
3511
            [
3512
                [
3513
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3514
                    'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3515
                ],
3516
                [
3517
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3518
                    'destinationContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3519
                ],
3520
            ],
3521
            [
3522
                [
3523
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3524
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3525
                ],
3526
                [
3527
                    'sourceContentInfo' => $relations[1]->sourceContentInfo->remoteId,
3528
                    'destinationContentInfo' => $relations[1]->destinationContentInfo->remoteId,
3529
                ],
3530
            ]
3531
        );
3532
    }
3533
3534
    /**
3535
     * Test for the loadRelations() method.
3536
     *
3537
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3538
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3539
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
3540
     */
3541
    public function testLoadRelationsSkipsArchivedContent()
3542
    {
3543
        $trashService = $this->getRepository()->getTrashService();
3544
3545
        $draft = $this->createContentDraftVersion1();
3546
3547
        // Load other content objects
3548
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
3549
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
3550
3551
        // Create relation between new content object and "Media" page
3552
        $this->contentService->addRelation(
3553
            $draft->getVersionInfo(),
3554
            $media
3555
        );
3556
3557
        // Create another relation with the "Demo Design" page
3558
        $this->contentService->addRelation(
3559
            $draft->getVersionInfo(),
3560
            $demoDesign
3561
        );
3562
3563
        $demoDesignLocation = $this->locationService->loadLocation($demoDesign->mainLocationId);
3564
3565
        // Trashing Content's last Location will change its status to archived,
3566
        // in this case relation towards it will not be loaded.
3567
        $trashService->trash($demoDesignLocation);
3568
3569
        // Load all relations
3570
        $relations = $this->contentService->loadRelations($draft->getVersionInfo());
3571
3572
        $this->assertCount(1, $relations);
3573
        $this->assertEquals(
3574
            [
3575
                [
3576
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3577
                    'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3578
                ],
3579
            ],
3580
            [
3581
                [
3582
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3583
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3584
                ],
3585
            ]
3586
        );
3587
    }
3588
3589
    /**
3590
     * Test for the loadRelations() method.
3591
     *
3592
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3593
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3594
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
3595
     */
3596
    public function testLoadRelationsSkipsDraftContent()
3597
    {
3598
        $draft = $this->createContentDraftVersion1();
3599
3600
        // Load other content objects
3601
        $media = $this->contentService->loadContentByRemoteId(self::MEDIA_REMOTE_ID);
3602
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
3603
3604
        // Create draft of "Media" page
3605
        $mediaDraft = $this->contentService->createContentDraft($media->contentInfo);
3606
3607
        // Create relation between "Media" page and new content object draft.
3608
        // This relation will not be loaded before the draft is published.
3609
        $this->contentService->addRelation(
3610
            $mediaDraft->getVersionInfo(),
3611
            $draft->getVersionInfo()->getContentInfo()
3612
        );
3613
3614
        // Create another relation with the "Demo Design" page
3615
        $this->contentService->addRelation(
3616
            $mediaDraft->getVersionInfo(),
3617
            $demoDesign
3618
        );
3619
3620
        $relations = $this->contentService->loadRelations($mediaDraft->getVersionInfo());
3621
3622
        $this->assertCount(1, $relations);
3623
        $this->assertEquals(
3624
            [
3625
                [
3626
                    'sourceContentInfo' => self::MEDIA_REMOTE_ID,
3627
                    'destinationContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3628
                ],
3629
            ],
3630
            [
3631
                [
3632
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3633
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3634
                ],
3635
            ]
3636
        );
3637
    }
3638
3639
    /**
3640
     * Test for the countReverseRelations() method.
3641
     *
3642
     * @covers \eZ\Publish\API\Repository\ContentService::countReverseRelations
3643
     */
3644
    public function testCountReverseRelations(): void
3645
    {
3646
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3647
            $this->contentService->createContentDraft(
3648
                $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3649
            ),
3650
            $this->contentService->createContentDraft(
3651
                $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3652
            ),
3653
        ]);
3654
3655
        $contentInfo = $contentWithReverseRelations->content->getVersionInfo()->getContentInfo();
3656
3657
        $this->assertEquals(2, $this->contentService->countReverseRelations($contentInfo));
3658
    }
3659
3660
    /**
3661
     * Test for the countReverseRelations() method.
3662
     *
3663
     * @covers \eZ\Publish\API\Repository\ContentService::countReverseRelations
3664
     */
3665
    public function testCountReverseRelationsReturnsZeroByDefault(): void
3666
    {
3667
        $draft = $this->createContentDraftVersion1();
3668
3669
        $this->assertSame(0, $this->contentService->countReverseRelations($draft->getVersionInfo()->getContentInfo()));
3670
    }
3671
3672
    /**
3673
     * Test for the countReverseRelations() method.
3674
     *
3675
     * @covers \eZ\Publish\API\Repository\ContentService::countReverseRelations
3676
     */
3677
    public function testCountReverseRelationsForUnauthorizedUser(): void
3678
    {
3679
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3680
            $this->contentService->createContentDraft(
3681
                $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3682
            ),
3683
        ]);
3684
        $mediaUser = $this->createMediaUserVersion1();
3685
        $this->permissionResolver->setCurrentUserReference($mediaUser);
3686
3687
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
3688
3689
        $this->assertSame(0, $this->contentService->countReverseRelations($contentInfo));
3690
    }
3691
3692
    /**
3693
     * Test for the loadReverseRelations() method.
3694
     *
3695
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3696
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3697
     */
3698
    public function testLoadReverseRelations()
3699
    {
3700
        $versionInfo = $this->createContentVersion1()->getVersionInfo();
3701
        $contentInfo = $versionInfo->getContentInfo();
3702
3703
        // Create some drafts
3704
        $mediaDraft = $this->contentService->createContentDraft(
3705
            $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID)
3706
        );
3707
        $demoDesignDraft = $this->contentService->createContentDraft(
3708
            $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID)
3709
        );
3710
3711
        // Create relation between new content object and "Media" page
3712
        $relation1 = $this->contentService->addRelation(
3713
            $mediaDraft->getVersionInfo(),
3714
            $contentInfo
3715
        );
3716
3717
        // Create another relation with the "Demo Design" page
3718
        $relation2 = $this->contentService->addRelation(
3719
            $demoDesignDraft->getVersionInfo(),
3720
            $contentInfo
3721
        );
3722
3723
        // Publish drafts, so relations become active
3724
        $this->contentService->publishVersion($mediaDraft->getVersionInfo());
3725
        $this->contentService->publishVersion($demoDesignDraft->getVersionInfo());
3726
3727
        $relations = $this->contentService->loadRelations($versionInfo);
3728
        $reverseRelations = $this->contentService->loadReverseRelations($contentInfo);
3729
3730
        $this->assertEquals($contentInfo->id, $relation1->getDestinationContentInfo()->id);
3731
        $this->assertEquals($mediaDraft->id, $relation1->getSourceContentInfo()->id);
3732
3733
        $this->assertEquals($contentInfo->id, $relation2->getDestinationContentInfo()->id);
3734
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3735
3736
        $this->assertEquals(0, count($relations));
3737
        $this->assertEquals(2, count($reverseRelations));
3738
3739
        usort(
3740
            $reverseRelations,
3741
            function ($rel1, $rel2) {
3742
                return strcasecmp(
3743
                    $rel2->getSourceContentInfo()->remoteId,
3744
                    $rel1->getSourceContentInfo()->remoteId
3745
                );
3746
            }
3747
        );
3748
3749
        $this->assertEquals(
3750
            [
3751
                [
3752
                    'sourceContentInfo' => self::MEDIA_REMOTE_ID,
3753
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3754
                ],
3755
                [
3756
                    'sourceContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3757
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3758
                ],
3759
            ],
3760
            [
3761
                [
3762
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3763
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3764
                ],
3765
                [
3766
                    'sourceContentInfo' => $reverseRelations[1]->sourceContentInfo->remoteId,
3767
                    'destinationContentInfo' => $reverseRelations[1]->destinationContentInfo->remoteId,
3768
                ],
3769
            ]
3770
        );
3771
    }
3772
3773
    /**
3774
     * Test for the loadReverseRelations() method.
3775
     *
3776
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3777
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3778
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadReverseRelations
3779
     */
3780
    public function testLoadReverseRelationsSkipsArchivedContent()
3781
    {
3782
        $trashService = $this->getRepository()->getTrashService();
3783
3784
        $versionInfo = $this->createContentVersion1()->getVersionInfo();
3785
        $contentInfo = $versionInfo->getContentInfo();
3786
3787
        // Create some drafts
3788
        $mediaDraft = $this->contentService->createContentDraft(
3789
            $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID)
3790
        );
3791
        $demoDesignDraft = $this->contentService->createContentDraft(
3792
            $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID)
3793
        );
3794
3795
        // Create relation between new content object and "Media" page
3796
        $relation1 = $this->contentService->addRelation(
3797
            $mediaDraft->getVersionInfo(),
3798
            $contentInfo
3799
        );
3800
3801
        // Create another relation with the "Demo Design" page
3802
        $relation2 = $this->contentService->addRelation(
3803
            $demoDesignDraft->getVersionInfo(),
3804
            $contentInfo
3805
        );
3806
3807
        // Publish drafts, so relations become active
3808
        $this->contentService->publishVersion($mediaDraft->getVersionInfo());
3809
        $this->contentService->publishVersion($demoDesignDraft->getVersionInfo());
3810
3811
        $demoDesignLocation = $this->locationService->loadLocation($demoDesignDraft->contentInfo->mainLocationId);
3812
3813
        // Trashing Content's last Location will change its status to archived,
3814
        // in this case relation from it will not be loaded.
3815
        $trashService->trash($demoDesignLocation);
3816
3817
        // Load all relations
3818
        $relations = $this->contentService->loadRelations($versionInfo);
3819
        $reverseRelations = $this->contentService->loadReverseRelations($contentInfo);
3820
3821
        $this->assertEquals($contentInfo->id, $relation1->getDestinationContentInfo()->id);
3822
        $this->assertEquals($mediaDraft->id, $relation1->getSourceContentInfo()->id);
3823
3824
        $this->assertEquals($contentInfo->id, $relation2->getDestinationContentInfo()->id);
3825
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3826
3827
        $this->assertEquals(0, count($relations));
3828
        $this->assertEquals(1, count($reverseRelations));
3829
3830
        $this->assertEquals(
3831
            [
3832
                [
3833
                    'sourceContentInfo' => self::MEDIA_REMOTE_ID,
3834
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3835
                ],
3836
            ],
3837
            [
3838
                [
3839
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3840
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3841
                ],
3842
            ]
3843
        );
3844
    }
3845
3846
    /**
3847
     * Test for the loadReverseRelations() method.
3848
     *
3849
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3850
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3851
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadReverseRelations
3852
     */
3853
    public function testLoadReverseRelationsSkipsDraftContent()
3854
    {
3855
        // Load "Media" page Content
3856
        $media = $this->contentService->loadContentByRemoteId(self::MEDIA_REMOTE_ID);
3857
3858
        // Create some drafts
3859
        $newDraftVersionInfo = $this->createContentDraftVersion1()->getVersionInfo();
3860
        $demoDesignDraft = $this->contentService->createContentDraft(
3861
            $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID)
3862
        );
3863
3864
        // Create relation between "Media" page and new content object
3865
        $relation1 = $this->contentService->addRelation(
3866
            $newDraftVersionInfo,
3867
            $media->contentInfo
3868
        );
3869
3870
        // Create another relation with the "Demo Design" page
3871
        $relation2 = $this->contentService->addRelation(
3872
            $demoDesignDraft->getVersionInfo(),
3873
            $media->contentInfo
3874
        );
3875
3876
        // Publish drafts, so relations become active
3877
        $this->contentService->publishVersion($demoDesignDraft->getVersionInfo());
3878
        // We will not publish new Content draft, therefore relation from it
3879
        // will not be loaded as reverse relation for "Media" page
3880
3881
        $relations = $this->contentService->loadRelations($media->versionInfo);
3882
        $reverseRelations = $this->contentService->loadReverseRelations($media->contentInfo);
3883
3884
        $this->assertEquals($media->contentInfo->id, $relation1->getDestinationContentInfo()->id);
3885
        $this->assertEquals($newDraftVersionInfo->contentInfo->id, $relation1->getSourceContentInfo()->id);
3886
3887
        $this->assertEquals($media->contentInfo->id, $relation2->getDestinationContentInfo()->id);
3888
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3889
3890
        $this->assertEquals(0, count($relations));
3891
        $this->assertEquals(1, count($reverseRelations));
3892
3893
        $this->assertEquals(
3894
            [
3895
                [
3896
                    'sourceContentInfo' => self::DEMO_DESIGN_REMOTE_ID,
3897
                    'destinationContentInfo' => self::MEDIA_REMOTE_ID,
3898
                ],
3899
            ],
3900
            [
3901
                [
3902
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3903
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3904
                ],
3905
            ]
3906
        );
3907
    }
3908
3909
    /**
3910
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
3911
     */
3912
    public function testLoadReverseRelationList(): void
3913
    {
3914
        $draft1 = $this->contentService->createContentDraft(
3915
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3916
        );
3917
        $draft2 = $this->contentService->createContentDraft(
3918
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3919
        );
3920
        $draft3 = $this->contentService->createContentDraft(
3921
            $this->createFolder([self::ENG_GB => 'Baz'], 2)->contentInfo
3922
        );
3923
3924
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3925
            $draft1,
3926
            $draft2,
3927
            $draft3,
3928
        ]);
3929
3930
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
3931
3932
        $reverseRelationList = $this->contentService->loadReverseRelationList($contentInfo);
3933
3934
        $this->assertSame(3, $reverseRelationList->totalCount);
3935
        $this->assertEquals(
3936
            $contentWithReverseRelations->reverseRelations[2]->contentInfo,
3937
            $reverseRelationList->items[0]->getRelation()->sourceContentInfo
3938
        );
3939
        $this->assertEquals(
3940
            $contentWithReverseRelations->reverseRelations[1]->contentInfo,
3941
            $reverseRelationList->items[1]->getRelation()->sourceContentInfo
3942
        );
3943
        $this->assertEquals(
3944
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
3945
            $reverseRelationList->items[2]->getRelation()->sourceContentInfo
3946
        );
3947
    }
3948
3949
    /**
3950
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
3951
     */
3952
    public function testLoadReverseRelationListWithPagination(): void
3953
    {
3954
        $draft1 = $this->contentService->createContentDraft(
3955
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3956
        );
3957
        $draft2 = $this->contentService->createContentDraft(
3958
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
3959
        );
3960
        $draft3 = $this->contentService->createContentDraft(
3961
            $this->createFolder([self::ENG_GB => 'Baz'], 2)->contentInfo
3962
        );
3963
3964
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
3965
            $draft1,
3966
            $draft2,
3967
            $draft3,
3968
        ]);
3969
3970
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
3971
3972
        $reverseRelationPage1 = $this->contentService->loadReverseRelationList($contentInfo, 0, 2);
3973
        $reverseRelationPage2 = $this->contentService->loadReverseRelationList($contentInfo, 2, 2);
3974
        $this->assertSame(3, $reverseRelationPage1->totalCount);
3975
        $this->assertSame(3, $reverseRelationPage2->totalCount);
3976
        $this->assertEquals(
3977
            $contentWithReverseRelations->reverseRelations[2]->contentInfo,
3978
            $reverseRelationPage1->items[0]->getRelation()->sourceContentInfo
3979
        );
3980
        $this->assertEquals(
3981
            $contentWithReverseRelations->reverseRelations[1]->contentInfo,
3982
            $reverseRelationPage1->items[1]->getRelation()->sourceContentInfo
3983
        );
3984
        $this->assertEquals(
3985
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
3986
            $reverseRelationPage2->items[0]->getRelation()->sourceContentInfo
3987
        );
3988
    }
3989
3990
    /**
3991
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
3992
     */
3993
    public function testLoadReverseRelationListSkipsArchivedContent(): void
3994
    {
3995
        $trashService = $this->getRepository()->getTrashService();
3996
3997
        $draft1 = $this->contentService->createContentDraft(
3998
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
3999
        );
4000
        $draft2 = $this->contentService->createContentDraft(
4001
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
4002
        );
4003
        $draft3 = $this->contentService->createContentDraft(
4004
            $this->createFolder([self::ENG_GB => 'Baz'], 2)->contentInfo
4005
        );
4006
4007
        $contentWithReverseRelations = $this->createContentWithReverseRelations([
4008
            $draft1,
4009
            $draft2,
4010
            $draft3,
4011
        ]);
4012
4013
        $locationToTrash = $this->locationService->loadLocation($draft3->contentInfo->mainLocationId);
4014
4015
        // Trashing Content's last Location will change its status to archived, in this case relation from it will not be loaded.
4016
        $trashService->trash($locationToTrash);
4017
4018
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
4019
        $reverseRelationList = $this->contentService->loadReverseRelationList($contentInfo);
4020
4021
        $this->assertSame(2, $reverseRelationList->totalCount);
4022
        $this->assertEquals(
4023
            $contentWithReverseRelations->reverseRelations[1]->contentInfo,
4024
            $reverseRelationList->items[0]->getRelation()->sourceContentInfo
4025
        );
4026
        $this->assertEquals(
4027
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
4028
            $reverseRelationList->items[1]->getRelation()->sourceContentInfo
4029
        );
4030
    }
4031
4032
    /**
4033
     * @covers \eZ\Publish\API\Repository\ContentService::loadReverseRelationList
4034
     */
4035
    public function testLoadReverseRelationListSkipsDraftContent()
4036
    {
4037
        $draft1 = $this->contentService->createContentDraft(
4038
            $this->createFolder([self::ENG_GB => 'Foo'], 2)->contentInfo
4039
        );
4040
4041
        $contentWithReverseRelations = $this->createContentWithReverseRelations([$draft1]);
4042
4043
        $contentInfo = $contentWithReverseRelations->content->contentInfo;
4044
4045
        // create a relation, but without publishing it
4046
        $draft2 = $this->contentService->createContentDraft(
4047
            $this->createFolder([self::ENG_GB => 'Bar'], 2)->contentInfo
4048
        );
4049
        $this->contentService->addRelation(
4050
            $draft2->getVersionInfo(),
4051
            $contentInfo
4052
        );
4053
4054
        $reverseRelationList = $this->contentService->loadReverseRelationList($contentInfo);
4055
4056
        $this->assertSame(1, $reverseRelationList->totalCount);
4057
        $this->assertEquals(
4058
            $contentWithReverseRelations->reverseRelations[0]->contentInfo,
4059
            $reverseRelationList->items[0]->getRelation()->sourceContentInfo
4060
        );
4061
    }
4062
4063
    /**
4064
     * Test for the deleteRelation() method.
4065
     *
4066
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4067
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
4068
     */
4069
    public function testDeleteRelation()
4070
    {
4071
        $draft = $this->createContentDraftVersion1();
4072
4073
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
4074
        $demoDesign = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
4075
4076
        // Establish some relations
4077
        $this->contentService->addRelation($draft->getVersionInfo(), $media);
4078
        $this->contentService->addRelation($draft->getVersionInfo(), $demoDesign);
4079
4080
        // Delete one of the currently created relations
4081
        $this->contentService->deleteRelation($draft->getVersionInfo(), $media);
4082
4083
        // The relations array now contains only one element
4084
        $relations = $this->contentService->loadRelations($draft->getVersionInfo());
4085
4086
        $this->assertEquals(1, count($relations));
4087
    }
4088
4089
    /**
4090
     * Test for the deleteRelation() method.
4091
     *
4092
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4093
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteRelation
4094
     */
4095
    public function testDeleteRelationThrowsBadStateException()
4096
    {
4097
        $content = $this->createContentVersion1();
4098
4099
        // Load the destination object
4100
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
4101
4102
        // Create a new draft
4103
        $draftVersion2 = $this->contentService->createContentDraft($content->contentInfo);
4104
4105
        // Add a relation
4106
        $this->contentService->addRelation($draftVersion2->getVersionInfo(), $media);
4107
4108
        // Publish new version
4109
        $contentVersion2 = $this->contentService->publishVersion(
4110
            $draftVersion2->getVersionInfo()
4111
        );
4112
4113
        $this->expectException(BadStateException::class);
4114
4115
        // This call will fail with a "BadStateException", because content is published and not a draft.
4116
        $this->contentService->deleteRelation(
4117
            $contentVersion2->getVersionInfo(),
4118
            $media
4119
        );
4120
    }
4121
4122
    /**
4123
     * Test for the deleteRelation() method.
4124
     *
4125
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4126
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteRelation
4127
     */
4128
    public function testDeleteRelationThrowsInvalidArgumentException()
4129
    {
4130
        $draft = $this->createContentDraftVersion1();
4131
4132
        // Load the destination object
4133
        $media = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
4134
4135
        // This call will fail with a "InvalidArgumentException", because no relation exists between $draft and $media.
4136
        $this->expectException(APIInvalidArgumentException::class);
4137
        $this->contentService->deleteRelation(
4138
            $draft->getVersionInfo(),
4139
            $media
4140
        );
4141
    }
4142
4143
    /**
4144
     * Test for the createContent() method.
4145
     *
4146
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
4147
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4148
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4149
     */
4150
    public function testCreateContentInTransactionWithRollback()
4151
    {
4152
        if ($this->isVersion4()) {
4153
            $this->markTestSkipped('This test requires eZ Publish 5');
4154
        }
4155
4156
        $repository = $this->getRepository();
4157
4158
        $contentTypeService = $this->getRepository()->getContentTypeService();
4159
4160
        // Start a transaction
4161
        $repository->beginTransaction();
4162
4163
        try {
4164
            $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
4165
4166
            // Get a content create struct and set mandatory properties
4167
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
4168
            $contentCreate->setField('name', 'Sindelfingen forum');
4169
4170
            $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
4171
            $contentCreate->alwaysAvailable = true;
4172
4173
            // Create a new content object
4174
            $contentId = $this->contentService->createContent($contentCreate)->id;
4175
        } catch (Exception $e) {
4176
            // Cleanup hanging transaction on error
4177
            $repository->rollback();
4178
            throw $e;
4179
        }
4180
4181
        // Rollback all changes
4182
        $repository->rollback();
4183
4184
        try {
4185
            // This call will fail with a "NotFoundException"
4186
            $this->contentService->loadContent($contentId);
4187
        } catch (NotFoundException $e) {
4188
            // This is expected
4189
            return;
4190
        }
4191
4192
        $this->fail('Content object still exists after rollback.');
4193
    }
4194
4195
    /**
4196
     * Test for the createContent() method.
4197
     *
4198
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
4199
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4200
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4201
     */
4202
    public function testCreateContentInTransactionWithCommit()
4203
    {
4204
        if ($this->isVersion4()) {
4205
            $this->markTestSkipped('This test requires eZ Publish 5');
4206
        }
4207
4208
        $repository = $this->getRepository();
4209
4210
        $contentTypeService = $repository->getContentTypeService();
4211
4212
        // Start a transaction
4213
        $repository->beginTransaction();
4214
4215
        try {
4216
            $contentType = $contentTypeService->loadContentTypeByIdentifier(self::FORUM_IDENTIFIER);
4217
4218
            // Get a content create struct and set mandatory properties
4219
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
4220
            $contentCreate->setField('name', 'Sindelfingen forum');
4221
4222
            $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
4223
            $contentCreate->alwaysAvailable = true;
4224
4225
            // Create a new content object
4226
            $contentId = $this->contentService->createContent($contentCreate)->id;
4227
4228
            // Commit changes
4229
            $repository->commit();
4230
        } catch (Exception $e) {
4231
            // Cleanup hanging transaction on error
4232
            $repository->rollback();
4233
            throw $e;
4234
        }
4235
4236
        // Load the new content object
4237
        $content = $this->contentService->loadContent($contentId);
4238
4239
        $this->assertEquals($contentId, $content->id);
4240
    }
4241
4242
    /**
4243
     * Test for the createContent() method.
4244
     *
4245
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
4246
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
4247
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentThrowsNotFoundException
4248
     */
4249
    public function testCreateContentWithLocationCreateParameterInTransactionWithRollback()
4250
    {
4251
        $repository = $this->getRepository();
4252
4253
        // Start a transaction
4254
        $repository->beginTransaction();
4255
4256
        try {
4257
            $draft = $this->createContentDraftVersion1();
4258
        } catch (Exception $e) {
4259
            // Cleanup hanging transaction on error
4260
            $repository->rollback();
4261
            throw $e;
4262
        }
4263
4264
        $contentId = $draft->id;
4265
4266
        // Roleback the transaction
4267
        $repository->rollback();
4268
4269
        try {
4270
            // This call will fail with a "NotFoundException"
4271
            $this->contentService->loadContent($contentId);
4272
        } catch (NotFoundException $e) {
4273
            return;
4274
        }
4275
4276
        $this->fail('Can still load content object after rollback.');
4277
    }
4278
4279
    /**
4280
     * Test for the createContent() method.
4281
     *
4282
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
4283
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
4284
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentThrowsNotFoundException
4285
     */
4286
    public function testCreateContentWithLocationCreateParameterInTransactionWithCommit()
4287
    {
4288
        $repository = $this->getRepository();
4289
4290
        // Start a transaction
4291
        $repository->beginTransaction();
4292
4293
        try {
4294
            $draft = $this->createContentDraftVersion1();
4295
4296
            $contentId = $draft->id;
4297
4298
            // Roleback the transaction
4299
            $repository->commit();
4300
        } catch (Exception $e) {
4301
            // Cleanup hanging transaction on error
4302
            $repository->rollback();
4303
            throw $e;
4304
        }
4305
4306
        // Load the new content object
4307
        $content = $this->contentService->loadContent($contentId);
4308
4309
        $this->assertEquals($contentId, $content->id);
4310
    }
4311
4312
    /**
4313
     * Test for the createContentDraft() method.
4314
     *
4315
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
4316
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
4317
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4318
     */
4319
    public function testCreateContentDraftInTransactionWithRollback()
4320
    {
4321
        $repository = $this->getRepository();
4322
4323
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4324
4325
        // Load the user group content object
4326
        $content = $this->contentService->loadContent($contentId);
4327
4328
        // Start a new transaction
4329
        $repository->beginTransaction();
4330
4331
        try {
4332
            // Create a new draft
4333
            $drafted = $this->contentService->createContentDraft($content->contentInfo);
4334
4335
            // Store version number for later reuse
4336
            $versionNo = $drafted->versionInfo->versionNo;
4337
        } catch (Exception $e) {
4338
            // Cleanup hanging transaction on error
4339
            $repository->rollback();
4340
            throw $e;
4341
        }
4342
4343
        // Rollback
4344
        $repository->rollback();
4345
4346
        try {
4347
            // This call will fail with a "NotFoundException"
4348
            $this->contentService->loadContent($contentId, null, $versionNo);
4349
        } catch (NotFoundException $e) {
4350
            return;
4351
        }
4352
4353
        $this->fail('Can still load content draft after rollback');
4354
    }
4355
4356
    /**
4357
     * Test for the createContentDraft() method.
4358
     *
4359
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
4360
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
4361
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4362
     */
4363
    public function testCreateContentDraftInTransactionWithCommit()
4364
    {
4365
        $repository = $this->getRepository();
4366
4367
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4368
4369
        // Load the user group content object
4370
        $content = $this->contentService->loadContent($contentId);
4371
4372
        // Start a new transaction
4373
        $repository->beginTransaction();
4374
4375
        try {
4376
            // Create a new draft
4377
            $drafted = $this->contentService->createContentDraft($content->contentInfo);
4378
4379
            // Store version number for later reuse
4380
            $versionNo = $drafted->versionInfo->versionNo;
4381
4382
            // Commit all changes
4383
            $repository->commit();
4384
        } catch (Exception $e) {
4385
            // Cleanup hanging transaction on error
4386
            $repository->rollback();
4387
            throw $e;
4388
        }
4389
4390
        $content = $this->contentService->loadContent($contentId, null, $versionNo);
4391
4392
        $this->assertEquals(
4393
            $versionNo,
4394
            $content->getVersionInfo()->versionNo
4395
        );
4396
    }
4397
4398
    /**
4399
     * Test for the publishVersion() method.
4400
     *
4401
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
4402
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
4403
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4404
     */
4405
    public function testPublishVersionInTransactionWithRollback()
4406
    {
4407
        $repository = $this->getRepository();
4408
4409
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4410
4411
        // Load the user group content object
4412
        $content = $this->contentService->loadContent($contentId);
4413
4414
        // Start a new transaction
4415
        $repository->beginTransaction();
4416
4417
        try {
4418
            $draftVersion = $this->contentService->createContentDraft($content->contentInfo)->getVersionInfo();
4419
4420
            // Publish a new version
4421
            $content = $this->contentService->publishVersion($draftVersion);
4422
4423
            // Store version number for later reuse
4424
            $versionNo = $content->versionInfo->versionNo;
4425
        } catch (Exception $e) {
4426
            // Cleanup hanging transaction on error
4427
            $repository->rollback();
4428
            throw $e;
4429
        }
4430
4431
        // Rollback
4432
        $repository->rollback();
4433
4434
        try {
4435
            // This call will fail with a "NotFoundException"
4436
            $this->contentService->loadContent($contentId, null, $versionNo);
4437
        } catch (NotFoundException $e) {
4438
            return;
4439
        }
4440
4441
        $this->fail('Can still load content draft after rollback');
4442
    }
4443
4444
    /**
4445
     * Test for the publishVersion() method.
4446
     *
4447
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
4448
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
4449
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
4450
     */
4451
    public function testPublishVersionInTransactionWithCommit()
4452
    {
4453
        $repository = $this->getRepository();
4454
4455
        // Load the user group content object
4456
        $template = $this->contentService->loadContent(self::ADMINISTRATORS_USER_GROUP_ID);
4457
4458
        // Start a new transaction
4459
        $repository->beginTransaction();
4460
4461
        try {
4462
            // Publish a new version
4463
            $content = $this->contentService->publishVersion(
4464
                $this->contentService->createContentDraft($template->contentInfo)->getVersionInfo()
4465
            );
4466
4467
            // Store version number for later reuse
4468
            $versionNo = $content->versionInfo->versionNo;
4469
4470
            // Commit all changes
4471
            $repository->commit();
4472
        } catch (Exception $e) {
4473
            // Cleanup hanging transaction on error
4474
            $repository->rollback();
4475
            throw $e;
4476
        }
4477
4478
        // Load current version info
4479
        $versionInfo = $this->contentService->loadVersionInfo($content->contentInfo);
4480
4481
        $this->assertEquals($versionNo, $versionInfo->versionNo);
4482
    }
4483
4484
    /**
4485
     * Test for the updateContent() method.
4486
     *
4487
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
4488
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
4489
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4490
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4491
     */
4492
    public function testUpdateContentInTransactionWithRollback()
4493
    {
4494
        $repository = $this->getRepository();
4495
4496
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4497
4498
        // Create a new user group draft
4499
        $draft = $this->contentService->createContentDraft(
4500
            $this->contentService->loadContentInfo($contentId)
4501
        );
4502
4503
        // Get an update struct and change the group name
4504
        $contentUpdate = $this->contentService->newContentUpdateStruct();
4505
        $contentUpdate->setField('name', self::ADMINISTRATORS_USER_GROUP_NAME, self::ENG_US);
4506
4507
        // Start a transaction
4508
        $repository->beginTransaction();
4509
4510
        try {
4511
            // Update the group name
4512
            $draft = $this->contentService->updateContent(
4513
                $draft->getVersionInfo(),
4514
                $contentUpdate
4515
            );
4516
4517
            // Publish updated version
4518
            $this->contentService->publishVersion($draft->getVersionInfo());
4519
        } catch (Exception $e) {
4520
            // Cleanup hanging transaction on error
4521
            $repository->rollback();
4522
            throw $e;
4523
        }
4524
4525
        // Rollback all changes.
4526
        $repository->rollback();
4527
4528
        // Name will still be "Administrator users"
4529
        $name = $this->contentService->loadContent($contentId)->getFieldValue('name');
4530
4531
        $this->assertEquals('Administrator users', $name);
4532
    }
4533
4534
    /**
4535
     * Test for the updateContent() method.
4536
     *
4537
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
4538
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
4539
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4540
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4541
     */
4542
    public function testUpdateContentInTransactionWithCommit()
4543
    {
4544
        $repository = $this->getRepository();
4545
4546
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4547
4548
        // Create a new user group draft
4549
        $draft = $this->contentService->createContentDraft(
4550
            $this->contentService->loadContentInfo($contentId)
4551
        );
4552
4553
        // Get an update struct and change the group name
4554
        $contentUpdate = $this->contentService->newContentUpdateStruct();
4555
        $contentUpdate->setField('name', self::ADMINISTRATORS_USER_GROUP_NAME, self::ENG_US);
4556
4557
        // Start a transaction
4558
        $repository->beginTransaction();
4559
4560
        try {
4561
            // Update the group name
4562
            $draft = $this->contentService->updateContent(
4563
                $draft->getVersionInfo(),
4564
                $contentUpdate
4565
            );
4566
4567
            // Publish updated version
4568
            $this->contentService->publishVersion($draft->getVersionInfo());
4569
4570
            // Commit all changes.
4571
            $repository->commit();
4572
        } catch (Exception $e) {
4573
            // Cleanup hanging transaction on error
4574
            $repository->rollback();
4575
            throw $e;
4576
        }
4577
4578
        // Name is now "Administrators"
4579
        $name = $this->contentService->loadContent($contentId)->getFieldValue('name', self::ENG_US);
4580
4581
        $this->assertEquals(self::ADMINISTRATORS_USER_GROUP_NAME, $name);
4582
    }
4583
4584
    /**
4585
     * Test for the updateContentMetadata() method.
4586
     *
4587
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4588
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
4589
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4590
     */
4591
    public function testUpdateContentMetadataInTransactionWithRollback()
4592
    {
4593
        $repository = $this->getRepository();
4594
4595
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4596
4597
        // Load a ContentInfo object
4598
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4599
4600
        // Store remoteId for later testing
4601
        $remoteId = $contentInfo->remoteId;
4602
4603
        // Start a transaction
4604
        $repository->beginTransaction();
4605
4606
        try {
4607
            // Get metadata update struct and change remoteId
4608
            $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
4609
            $metadataUpdate->remoteId = md5(microtime(true));
4610
4611
            // Update the metadata of the published content object
4612
            $this->contentService->updateContentMetadata(
4613
                $contentInfo,
4614
                $metadataUpdate
4615
            );
4616
        } catch (Exception $e) {
4617
            // Cleanup hanging transaction on error
4618
            $repository->rollback();
4619
            throw $e;
4620
        }
4621
4622
        // Rollback all changes.
4623
        $repository->rollback();
4624
4625
        // Load current remoteId
4626
        $remoteIdReloaded = $this->contentService->loadContentInfo($contentId)->remoteId;
4627
4628
        $this->assertEquals($remoteId, $remoteIdReloaded);
4629
    }
4630
4631
    /**
4632
     * Test for the updateContentMetadata() method.
4633
     *
4634
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4635
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
4636
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4637
     */
4638
    public function testUpdateContentMetadataInTransactionWithCommit()
4639
    {
4640
        $repository = $this->getRepository();
4641
4642
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4643
4644
        // Load a ContentInfo object
4645
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4646
4647
        // Store remoteId for later testing
4648
        $remoteId = $contentInfo->remoteId;
4649
4650
        // Start a transaction
4651
        $repository->beginTransaction();
4652
4653
        try {
4654
            // Get metadata update struct and change remoteId
4655
            $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
4656
            $metadataUpdate->remoteId = md5(microtime(true));
4657
4658
            // Update the metadata of the published content object
4659
            $this->contentService->updateContentMetadata(
4660
                $contentInfo,
4661
                $metadataUpdate
4662
            );
4663
4664
            // Commit all changes.
4665
            $repository->commit();
4666
        } catch (Exception $e) {
4667
            // Cleanup hanging transaction on error
4668
            $repository->rollback();
4669
            throw $e;
4670
        }
4671
4672
        // Load current remoteId
4673
        $remoteIdReloaded = $this->contentService->loadContentInfo($contentId)->remoteId;
4674
4675
        $this->assertNotEquals($remoteId, $remoteIdReloaded);
4676
    }
4677
4678
    /**
4679
     * Test for the updateContentMetadata() method, and how cache + transactions play together.
4680
     *
4681
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4682
     * @depends testUpdateContentMetadata
4683
     * @depends testLoadContentInfo
4684
     */
4685
    public function testUpdateContentMetadataCheckWithinTransaction()
4686
    {
4687
        $repository = $this->getRepository();
4688
        $contentService = $repository->getContentService();
4689
        $contentId = $this->generateId('object', 12);
4690
4691
        // Load a ContentInfo object, and warmup cache
4692
        $contentInfo = $contentService->loadContentInfo($contentId);
4693
4694
        // Store remoteId for later testing
4695
        $remoteId = $contentInfo->remoteId;
4696
4697
        // Start a transaction
4698
        $repository->beginTransaction();
4699
4700
        try {
4701
            // Get metadata update struct and change remoteId
4702
            $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
4703
            $metadataUpdate->remoteId = md5(microtime(true));
4704
4705
            // Update the metadata of the published content object
4706
            $contentService->updateContentMetadata(
4707
                $contentInfo,
4708
                $metadataUpdate
4709
            );
4710
4711
            // Check that it's been updated
4712
            $remoteIdReloaded = $contentService->loadContentInfo($contentId)->remoteId;
4713
            $this->assertNotEquals($remoteId, $remoteIdReloaded);
4714
4715
            // Commit all changes.
4716
            $repository->commit();
4717
        } catch (Exception $e) {
4718
            // Cleanup hanging transaction on error
4719
            $repository->rollback();
4720
            throw $e;
4721
        }
4722
    }
4723
4724
    /**
4725
     * Test for the deleteVersion() method.
4726
     *
4727
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4728
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4729
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4730
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4731
     */
4732
    public function testDeleteVersionInTransactionWithRollback()
4733
    {
4734
        $repository = $this->getRepository();
4735
4736
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4737
4738
        // Start a new transaction
4739
        $repository->beginTransaction();
4740
4741
        try {
4742
            // Create a new draft
4743
            $draft = $this->contentService->createContentDraft(
4744
                $this->contentService->loadContentInfo($contentId)
4745
            );
4746
4747
            $this->contentService->deleteVersion($draft->getVersionInfo());
4748
        } catch (Exception $e) {
4749
            // Cleanup hanging transaction on error
4750
            $repository->rollback();
4751
            throw $e;
4752
        }
4753
4754
        // Rollback all changes.
4755
        $repository->rollback();
4756
4757
        // This array will be empty
4758
        $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...
4759
4760
        $this->assertSame([], $drafts);
4761
    }
4762
4763
    /**
4764
     * Test for the deleteVersion() method.
4765
     *
4766
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4767
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4768
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4769
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4770
     */
4771
    public function testDeleteVersionInTransactionWithCommit()
4772
    {
4773
        $repository = $this->getRepository();
4774
4775
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4776
4777
        // Start a new transaction
4778
        $repository->beginTransaction();
4779
4780
        try {
4781
            // Create a new draft
4782
            $draft = $this->contentService->createContentDraft(
4783
                $this->contentService->loadContentInfo($contentId)
4784
            );
4785
4786
            $this->contentService->deleteVersion($draft->getVersionInfo());
4787
4788
            // Commit all changes.
4789
            $repository->commit();
4790
        } catch (Exception $e) {
4791
            // Cleanup hanging transaction on error
4792
            $repository->rollback();
4793
            throw $e;
4794
        }
4795
4796
        // This array will contain no element
4797
        $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...
4798
4799
        $this->assertSame([], $drafts);
4800
    }
4801
4802
    /**
4803
     * Test for the deleteContent() method.
4804
     *
4805
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
4806
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteContent
4807
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4808
     */
4809
    public function testDeleteContentInTransactionWithRollback()
4810
    {
4811
        $repository = $this->getRepository();
4812
4813
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4814
4815
        // Load a ContentInfo instance
4816
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4817
4818
        // Start a new transaction
4819
        $repository->beginTransaction();
4820
4821
        try {
4822
            // Delete content object
4823
            $this->contentService->deleteContent($contentInfo);
4824
        } catch (Exception $e) {
4825
            // Cleanup hanging transaction on error
4826
            $repository->rollback();
4827
            throw $e;
4828
        }
4829
4830
        // Rollback all changes
4831
        $repository->rollback();
4832
4833
        // This call will return the original content object
4834
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4835
4836
        $this->assertEquals($contentId, $contentInfo->id);
4837
    }
4838
4839
    /**
4840
     * Test for the deleteContent() method.
4841
     *
4842
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
4843
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteContent
4844
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4845
     */
4846
    public function testDeleteContentInTransactionWithCommit()
4847
    {
4848
        $repository = $this->getRepository();
4849
4850
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4851
4852
        // Load a ContentInfo instance
4853
        $contentInfo = $this->contentService->loadContentInfo($contentId);
4854
4855
        // Start a new transaction
4856
        $repository->beginTransaction();
4857
4858
        try {
4859
            // Delete content object
4860
            $this->contentService->deleteContent($contentInfo);
4861
4862
            // Commit all changes
4863
            $repository->commit();
4864
        } catch (Exception $e) {
4865
            // Cleanup hanging transaction on error
4866
            $repository->rollback();
4867
            throw $e;
4868
        }
4869
4870
        // Deleted content info is not found anymore
4871
        try {
4872
            $this->contentService->loadContentInfo($contentId);
4873
        } catch (NotFoundException $e) {
4874
            return;
4875
        }
4876
4877
        $this->fail('Can still load ContentInfo after commit.');
4878
    }
4879
4880
    /**
4881
     * Test for the copyContent() method.
4882
     *
4883
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
4884
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
4885
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
4886
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
4887
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
4888
     */
4889
    public function testCopyContentInTransactionWithRollback()
4890
    {
4891
        $repository = $this->getRepository();
4892
4893
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4894
        $locationId = $this->generateId('location', self::ADMINISTRATORS_USER_GROUP_LOCATION_ID);
4895
4896
        // Load content object to copy
4897
        $content = $this->contentService->loadContent($contentId);
4898
4899
        // Create new target location
4900
        $locationCreate = $this->locationService->newLocationCreateStruct($locationId);
4901
4902
        // Start a new transaction
4903
        $repository->beginTransaction();
4904
4905
        try {
4906
            // Copy content with all versions and drafts
4907
            $this->contentService->copyContent(
4908
                $content->contentInfo,
4909
                $locationCreate
4910
            );
4911
        } catch (Exception $e) {
4912
            // Cleanup hanging transaction on error
4913
            $repository->rollback();
4914
            throw $e;
4915
        }
4916
4917
        // Rollback all changes
4918
        $repository->rollback();
4919
4920
        $this->refreshSearch($repository);
4921
4922
        // This array will only contain a single admin user object
4923
        $locations = $this->locationService->loadLocationChildren(
4924
            $this->locationService->loadLocation($locationId)
4925
        )->locations;
4926
4927
        $this->assertEquals(1, count($locations));
4928
    }
4929
4930
    /**
4931
     * Test for the copyContent() method.
4932
     *
4933
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
4934
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
4935
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
4936
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
4937
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
4938
     */
4939
    public function testCopyContentInTransactionWithCommit()
4940
    {
4941
        $repository = $this->getRepository();
4942
4943
        $contentId = $this->generateId('object', self::MEMBERS_USER_GROUP_ID);
4944
        $locationId = $this->generateId('location', self::ADMINISTRATORS_USER_GROUP_LOCATION_ID);
4945
4946
        // Load content object to copy
4947
        $content = $this->contentService->loadContent($contentId);
4948
4949
        // Create new target location
4950
        $locationCreate = $this->locationService->newLocationCreateStruct($locationId);
4951
4952
        // Start a new transaction
4953
        $repository->beginTransaction();
4954
4955
        try {
4956
            // Copy content with all versions and drafts
4957
            $this->contentService->copyContent(
4958
                $content->contentInfo,
4959
                $locationCreate
4960
            );
4961
4962
            // Commit all changes
4963
            $repository->commit();
4964
        } catch (Exception $e) {
4965
            // Cleanup hanging transaction on error
4966
            $repository->rollback();
4967
            throw $e;
4968
        }
4969
4970
        $this->refreshSearch($repository);
4971
4972
        // This will contain the admin user and the new child location
4973
        $locations = $this->locationService->loadLocationChildren(
4974
            $this->locationService->loadLocation($locationId)
4975
        )->locations;
4976
4977
        $this->assertEquals(2, count($locations));
4978
    }
4979
4980
    public function testURLAliasesCreatedForNewContent()
4981
    {
4982
        $urlAliasService = $this->getRepository()->getURLAliasService();
4983
4984
        $draft = $this->createContentDraftVersion1();
4985
4986
        // Automatically creates a new URLAlias for the content
4987
        $liveContent = $this->contentService->publishVersion($draft->getVersionInfo());
4988
4989
        $location = $this->locationService->loadLocation(
4990
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
4991
        );
4992
4993
        $aliases = $urlAliasService->listLocationAliases($location, false);
4994
4995
        $this->assertAliasesCorrect(
4996
            [
4997
                '/Design/Plain-site/An-awesome-forum' => [
4998
                    'type' => URLAlias::LOCATION,
4999
                    'destination' => $location->id,
5000
                    'path' => '/Design/Plain-site/An-awesome-forum',
5001
                    'languageCodes' => [self::ENG_US],
5002
                    'isHistory' => false,
5003
                    'isCustom' => false,
5004
                    'forward' => false,
5005
                ],
5006
            ],
5007
            $aliases
5008
        );
5009
    }
5010
5011
    public function testURLAliasesCreatedForUpdatedContent()
5012
    {
5013
        $urlAliasService = $this->getRepository()->getURLAliasService();
5014
5015
        $draft = $this->createUpdatedDraftVersion2();
5016
5017
        $location = $this->locationService->loadLocation(
5018
            $draft->getVersionInfo()->getContentInfo()->mainLocationId
5019
        );
5020
5021
        // Load and assert URL aliases before publishing updated Content, so that
5022
        // SPI cache is warmed up and cache invalidation is also tested.
5023
        $aliases = $urlAliasService->listLocationAliases($location, false);
5024
5025
        $this->assertAliasesCorrect(
5026
            [
5027
                '/Design/Plain-site/An-awesome-forum' => [
5028
                    'type' => URLAlias::LOCATION,
5029
                    'destination' => $location->id,
5030
                    'path' => '/Design/Plain-site/An-awesome-forum',
5031
                    'languageCodes' => [self::ENG_US],
5032
                    'alwaysAvailable' => true,
5033
                    'isHistory' => false,
5034
                    'isCustom' => false,
5035
                    'forward' => false,
5036
                ],
5037
            ],
5038
            $aliases
5039
        );
5040
5041
        // Automatically marks old aliases for the content as history
5042
        // and creates new aliases, based on the changes
5043
        $liveContent = $this->contentService->publishVersion($draft->getVersionInfo());
5044
5045
        $location = $this->locationService->loadLocation(
5046
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5047
        );
5048
5049
        $aliases = $urlAliasService->listLocationAliases($location, false);
5050
5051
        $this->assertAliasesCorrect(
5052
            [
5053
                '/Design/Plain-site/An-awesome-forum2' => [
5054
                    'type' => URLAlias::LOCATION,
5055
                    'destination' => $location->id,
5056
                    'path' => '/Design/Plain-site/An-awesome-forum2',
5057
                    'languageCodes' => [self::ENG_US],
5058
                    'alwaysAvailable' => true,
5059
                    'isHistory' => false,
5060
                    'isCustom' => false,
5061
                    'forward' => false,
5062
                ],
5063
                '/Design/Plain-site/An-awesome-forum23' => [
5064
                    'type' => URLAlias::LOCATION,
5065
                    'destination' => $location->id,
5066
                    'path' => '/Design/Plain-site/An-awesome-forum23',
5067
                    'languageCodes' => [self::ENG_GB],
5068
                    'alwaysAvailable' => true,
5069
                    'isHistory' => false,
5070
                    'isCustom' => false,
5071
                    'forward' => false,
5072
                ],
5073
            ],
5074
            $aliases
5075
        );
5076
    }
5077
5078
    public function testCustomURLAliasesNotHistorizedOnUpdatedContent()
5079
    {
5080
        $urlAliasService = $this->getRepository()->getURLAliasService();
5081
5082
        $content = $this->createContentVersion1();
5083
5084
        // Create a custom URL alias
5085
        $urlAliasService->createUrlAlias(
5086
            $this->locationService->loadLocation(
5087
                $content->getVersionInfo()->getContentInfo()->mainLocationId
5088
            ),
5089
            '/my/fancy/story-about-ez-publish',
5090
            self::ENG_US
5091
        );
5092
5093
        $draftVersion2 = $this->contentService->createContentDraft($content->contentInfo);
5094
5095
        $contentUpdate = $this->contentService->newContentUpdateStruct();
5096
        $contentUpdate->initialLanguageCode = self::ENG_US;
5097
        $contentUpdate->setField('name', 'Amazing Bielefeld forum');
5098
5099
        $draftVersion2 = $this->contentService->updateContent(
5100
            $draftVersion2->getVersionInfo(),
5101
            $contentUpdate
5102
        );
5103
5104
        // Only marks auto-generated aliases as history
5105
        // the custom one is left untouched
5106
        $liveContent = $this->contentService->publishVersion($draftVersion2->getVersionInfo());
5107
5108
        $location = $this->locationService->loadLocation(
5109
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5110
        );
5111
5112
        $aliases = $urlAliasService->listLocationAliases($location);
5113
5114
        $this->assertAliasesCorrect(
5115
            [
5116
                '/my/fancy/story-about-ez-publish' => [
5117
                    'type' => URLAlias::LOCATION,
5118
                    'destination' => $location->id,
5119
                    'path' => '/my/fancy/story-about-ez-publish',
5120
                    'languageCodes' => [self::ENG_US],
5121
                    'isHistory' => false,
5122
                    'isCustom' => true,
5123
                    'forward' => false,
5124
                    'alwaysAvailable' => false,
5125
                ],
5126
            ],
5127
            $aliases
5128
        );
5129
    }
5130
5131
    /**
5132
     * Test to ensure that old versions are not affected by updates to newer
5133
     * drafts.
5134
     */
5135
    public function testUpdatingDraftDoesNotUpdateOldVersions()
5136
    {
5137
        $contentVersion2 = $this->createContentVersion2();
5138
5139
        $loadedContent1 = $this->contentService->loadContent($contentVersion2->id, null, 1);
5140
        $loadedContent2 = $this->contentService->loadContent($contentVersion2->id, null, 2);
5141
5142
        $this->assertNotEquals(
5143
            $loadedContent1->getFieldValue('name', self::ENG_US),
5144
            $loadedContent2->getFieldValue('name', self::ENG_US)
5145
        );
5146
    }
5147
5148
    /**
5149
     * Test scenario with writer and publisher users.
5150
     * Writer can only create content. Publisher can publish this content.
5151
     */
5152
    public function testPublishWorkflow()
5153
    {
5154
        $this->createRoleWithPolicies('Publisher', [
5155
            ['module' => 'content', 'function' => 'read'],
5156
            ['module' => 'content', 'function' => 'create'],
5157
            ['module' => 'content', 'function' => 'publish'],
5158
        ]);
5159
5160
        $this->createRoleWithPolicies('Writer', [
5161
            ['module' => 'content', 'function' => 'read'],
5162
            ['module' => 'content', 'function' => 'create'],
5163
        ]);
5164
5165
        $writerUser = $this->createCustomUserWithLogin(
5166
            'writer',
5167
            '[email protected]',
5168
            self::WRITERS_USER_GROUP_NAME,
5169
            'Writer'
5170
        );
5171
5172
        $publisherUser = $this->createCustomUserWithLogin(
5173
            'publisher',
5174
            '[email protected]',
5175
            'Publishers',
5176
            'Publisher'
5177
        );
5178
5179
        $this->permissionResolver->setCurrentUserReference($writerUser);
5180
        $draft = $this->createContentDraftVersion1();
5181
5182
        $this->permissionResolver->setCurrentUserReference($publisherUser);
5183
        $content = $this->contentService->publishVersion($draft->versionInfo);
5184
5185
        $this->contentService->loadContent($content->id);
5186
    }
5187
5188
    /**
5189
     * Test publish / content policy is required to be able to publish content.
5190
     */
5191
    public function testPublishContentWithoutPublishPolicyThrowsException()
5192
    {
5193
        $this->createRoleWithPolicies('Writer', [
5194
            ['module' => 'content', 'function' => 'read'],
5195
            ['module' => 'content', 'function' => 'create'],
5196
            ['module' => 'content', 'function' => 'edit'],
5197
        ]);
5198
        $writerUser = $this->createCustomUserWithLogin(
5199
            'writer',
5200
            '[email protected]',
5201
            self::WRITERS_USER_GROUP_NAME,
5202
            'Writer'
5203
        );
5204
        $this->permissionResolver->setCurrentUserReference($writerUser);
5205
5206
        $this->expectException(CoreUnauthorizedException::class);
5207
        $this->expectExceptionMessageRegExp('/User does not have access to \'publish\' \'content\'/');
5208
5209
        $this->createContentVersion1();
5210
    }
5211
5212
    /**
5213
     * Test removal of the specific translation from all the Versions of a Content Object.
5214
     *
5215
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5216
     */
5217
    public function testDeleteTranslation()
5218
    {
5219
        $content = $this->createContentVersion2();
5220
5221
        // create multiple versions to exceed archive limit
5222
        for ($i = 0; $i < 5; ++$i) {
5223
            $contentDraft = $this->contentService->createContentDraft($content->contentInfo);
5224
            $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
5225
            $contentDraft = $this->contentService->updateContent(
5226
                $contentDraft->versionInfo,
5227
                $contentUpdateStruct
5228
            );
5229
            $this->contentService->publishVersion($contentDraft->versionInfo);
5230
        }
5231
5232
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_GB);
5233
5234
        $this->assertTranslationDoesNotExist(self::ENG_GB, $content->id);
5235
    }
5236
5237
    /**
5238
     * Test deleting a Translation which is initial for some Version, updates initialLanguageCode
5239
     * with mainLanguageCode (assuming they are different).
5240
     */
5241
    public function testDeleteTranslationUpdatesInitialLanguageCodeVersion()
5242
    {
5243
        $content = $this->createContentVersion2();
5244
        // create another, copied, version
5245
        $contentDraft = $this->contentService->updateContent(
5246
            $this->contentService->createContentDraft($content->contentInfo)->versionInfo,
5247
            $this->contentService->newContentUpdateStruct()
5248
        );
5249
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
5250
5251
        // remove first version with only one translation as it is not the subject of this test
5252
        $this->contentService->deleteVersion(
5253
            $this->contentService->loadVersionInfo($publishedContent->contentInfo, 1)
5254
        );
5255
5256
        // sanity check
5257
        self::assertEquals(self::ENG_US, $content->contentInfo->mainLanguageCode);
5258
        self::assertEquals(self::ENG_US, $content->versionInfo->initialLanguageCode);
5259
5260
        // update mainLanguageCode so it is different than initialLanguageCode for Version
5261
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
5262
        $contentMetadataUpdateStruct->mainLanguageCode = self::ENG_GB;
5263
        $content = $this->contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
5264
5265
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_US);
5266
5267
        $this->assertTranslationDoesNotExist(self::ENG_US, $content->id);
5268
    }
5269
5270
    /**
5271
     * Test removal of the specific translation properly updates languages of the URL alias.
5272
     *
5273
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5274
     */
5275
    public function testDeleteTranslationUpdatesUrlAlias()
5276
    {
5277
        $urlAliasService = $this->getRepository()->getURLAliasService();
5278
5279
        $content = $this->createContentVersion2();
5280
        $mainLocation = $this->locationService->loadLocation($content->contentInfo->mainLocationId);
5281
5282
        // create custom URL alias for Content main Location
5283
        $urlAliasService->createUrlAlias($mainLocation, '/my-custom-url', self::ENG_GB);
5284
5285
        // create secondary Location for Content
5286
        $secondaryLocation = $this->locationService->createLocation(
5287
            $content->contentInfo,
5288
            $this->locationService->newLocationCreateStruct(2)
5289
        );
5290
5291
        // create custom URL alias for Content secondary Location
5292
        $urlAliasService->createUrlAlias($secondaryLocation, '/my-secondary-url', self::ENG_GB);
5293
5294
        // delete Translation
5295
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_GB);
5296
5297
        foreach ([$mainLocation, $secondaryLocation] as $location) {
5298
            // check auto-generated URL aliases
5299
            foreach ($urlAliasService->listLocationAliases($location, false) as $alias) {
5300
                self::assertNotContains(self::ENG_GB, $alias->languageCodes);
5301
            }
5302
5303
            // check custom URL aliases
5304
            foreach ($urlAliasService->listLocationAliases($location) as $alias) {
5305
                self::assertNotContains(self::ENG_GB, $alias->languageCodes);
5306
            }
5307
        }
5308
    }
5309
5310
    /**
5311
     * Test removal of a main translation throws BadStateException.
5312
     *
5313
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5314
     */
5315
    public function testDeleteTranslationMainLanguageThrowsBadStateException()
5316
    {
5317
        $content = $this->createContentVersion2();
5318
5319
        // delete first version which has only one translation
5320
        $this->contentService->deleteVersion($this->contentService->loadVersionInfo($content->contentInfo, 1));
5321
5322
        // try to delete main translation
5323
        $this->expectException(BadStateException::class);
5324
        $this->expectExceptionMessage('Specified translation is the main translation of the Content Object');
5325
5326
        $this->contentService->deleteTranslation($content->contentInfo, $content->contentInfo->mainLanguageCode);
5327
    }
5328
5329
    /**
5330
     * Test removal of a Translation is possible when some archived Versions have only this Translation.
5331
     *
5332
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5333
     */
5334
    public function testDeleteTranslationDeletesSingleTranslationVersions()
5335
    {
5336
        // content created by the createContentVersion1 method has eng-US translation only.
5337
        $content = $this->createContentVersion1();
5338
5339
        // create new version and add eng-GB translation
5340
        $contentDraft = $this->contentService->createContentDraft($content->contentInfo);
5341
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
5342
        $contentUpdateStruct->setField('name', 'Awesome Board', self::ENG_GB);
5343
        $contentDraft = $this->contentService->updateContent($contentDraft->versionInfo, $contentUpdateStruct);
5344
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
5345
5346
        // update mainLanguageCode to avoid exception related to that
5347
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
5348
        $contentMetadataUpdateStruct->mainLanguageCode = self::ENG_GB;
5349
5350
        $content = $this->contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
5351
5352
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_US);
5353
5354
        $this->assertTranslationDoesNotExist(self::ENG_US, $content->id);
5355
    }
5356
5357
    /**
5358
     * Test removal of the translation by the user who is not allowed to delete a content
5359
     * throws UnauthorizedException.
5360
     *
5361
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5362
     */
5363
    public function testDeleteTranslationThrowsUnauthorizedException()
5364
    {
5365
        $content = $this->createContentVersion2();
5366
5367
        // create user that can read/create/edit but cannot delete content
5368
        $this->createRoleWithPolicies('Writer', [
5369
            ['module' => 'content', 'function' => 'read'],
5370
            ['module' => 'content', 'function' => 'versionread'],
5371
            ['module' => 'content', 'function' => 'create'],
5372
            ['module' => 'content', 'function' => 'edit'],
5373
        ]);
5374
        $writerUser = $this->createCustomUserWithLogin(
5375
            'writer',
5376
            '[email protected]',
5377
            self::WRITERS_USER_GROUP_NAME,
5378
            'Writer'
5379
        );
5380
        $this->permissionResolver->setCurrentUserReference($writerUser);
5381
5382
        $this->expectException(UnauthorizedException::class);
5383
        $this->expectExceptionMessage('User does not have access to \'remove\' \'content\'');
5384
5385
        $this->contentService->deleteTranslation($content->contentInfo, self::ENG_GB);
5386
    }
5387
5388
    /**
5389
     * Test removal of a non-existent translation throws InvalidArgumentException.
5390
     *
5391
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5392
     */
5393
    public function testDeleteTranslationThrowsInvalidArgumentException()
5394
    {
5395
        // content created by the createContentVersion1 method has eng-US translation only.
5396
        $content = $this->createContentVersion1();
5397
5398
        $this->expectException(APIInvalidArgumentException::class);
5399
        $this->expectExceptionMessage('Argument \'$languageCode\' is invalid: ger-DE does not exist in the Content item');
5400
5401
        $this->contentService->deleteTranslation($content->contentInfo, self::GER_DE);
5402
    }
5403
5404
    /**
5405
     * Test deleting a Translation from Draft.
5406
     *
5407
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5408
     */
5409
    public function testDeleteTranslationFromDraft()
5410
    {
5411
        $languageCode = self::ENG_GB;
5412
        $content = $this->createMultipleLanguageContentVersion2();
5413
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5414
        $draft = $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5415
        $content = $this->contentService->publishVersion($draft->versionInfo);
5416
5417
        $loadedContent = $this->contentService->loadContent($content->id);
5418
        self::assertNotContains($languageCode, $loadedContent->versionInfo->languageCodes);
5419
        self::assertEmpty($loadedContent->getFieldsByLanguage($languageCode));
5420
    }
5421
5422
    /**
5423
     * Get values for multilingual field.
5424
     *
5425
     * @return array
5426
     */
5427
    public function providerForDeleteTranslationFromDraftRemovesUrlAliasOnPublishing()
5428
    {
5429
        return [
5430
            [
5431
                [self::ENG_US => 'US Name', self::ENG_GB => 'GB Name'],
5432
            ],
5433
            [
5434
                [self::ENG_US => 'Same Name', self::ENG_GB => 'Same Name'],
5435
            ],
5436
        ];
5437
    }
5438
5439
    /**
5440
     * Test deleting a Translation from Draft removes previously stored URL aliases for published Content.
5441
     *
5442
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5443
     *
5444
     * @dataProvider providerForDeleteTranslationFromDraftRemovesUrlAliasOnPublishing
5445
     *
5446
     * @param string[] $fieldValues translated field values
5447
     *
5448
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
5449
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
5450
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
5451
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
5452
     */
5453
    public function testDeleteTranslationFromDraftRemovesUrlAliasOnPublishing(array $fieldValues)
5454
    {
5455
        $urlAliasService = $this->getRepository()->getURLAliasService();
5456
5457
        // set language code to be removed
5458
        $languageCode = self::ENG_GB;
5459
        $draft = $this->createMultilingualContentDraft(
5460
            'folder',
5461
            2,
5462
            self::ENG_US,
5463
            [
5464
                'name' => [
5465
                    self::ENG_GB => $fieldValues[self::ENG_GB],
5466
                    self::ENG_US => $fieldValues[self::ENG_US],
5467
                ],
5468
            ]
5469
        );
5470
        $content = $this->contentService->publishVersion($draft->versionInfo);
5471
5472
        // create secondary location
5473
        $this->locationService->createLocation(
5474
            $content->contentInfo,
5475
            $this->locationService->newLocationCreateStruct(5)
5476
        );
5477
5478
        // sanity check
5479
        $locations = $this->locationService->loadLocations($content->contentInfo);
5480
        self::assertCount(2, $locations, 'Sanity check: Expected to find 2 Locations');
5481
        foreach ($locations as $location) {
5482
            $urlAliasService->createUrlAlias($location, '/us-custom_' . $location->id, self::ENG_US);
5483
            $urlAliasService->createUrlAlias($location, '/gb-custom_' . $location->id, self::ENG_GB);
5484
5485
            // check default URL aliases
5486
            $aliases = $urlAliasService->listLocationAliases($location, false, $languageCode);
5487
            self::assertNotEmpty($aliases, 'Sanity check: URL alias for the translation does not exist');
5488
5489
            // check custom URL aliases
5490
            $aliases = $urlAliasService->listLocationAliases($location, true, $languageCode);
5491
            self::assertNotEmpty($aliases, 'Sanity check: Custom URL alias for the translation does not exist');
5492
        }
5493
5494
        // delete translation and publish new version
5495
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5496
        $draft = $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5497
        $this->contentService->publishVersion($draft->versionInfo);
5498
5499
        // check that aliases does not exist
5500
        foreach ($locations as $location) {
5501
            // check default URL aliases
5502
            $aliases = $urlAliasService->listLocationAliases($location, false, $languageCode);
5503
            self::assertEmpty($aliases, 'URL alias for the deleted translation still exists');
5504
5505
            // check custom URL aliases
5506
            $aliases = $urlAliasService->listLocationAliases($location, true, $languageCode);
5507
            self::assertEmpty($aliases, 'Custom URL alias for the deleted translation still exists');
5508
        }
5509
    }
5510
5511
    /**
5512
     * Test that URL aliases for deleted Translations are properly archived.
5513
     */
5514
    public function testDeleteTranslationFromDraftArchivesUrlAliasOnPublishing()
5515
    {
5516
        $urlAliasService = $this->getRepository()->getURLAliasService();
5517
5518
        $content = $this->contentService->publishVersion(
5519
            $this->createMultilingualContentDraft(
5520
                'folder',
5521
                2,
5522
                self::ENG_US,
5523
                [
5524
                    'name' => [
5525
                        self::ENG_GB => 'BritishEnglishContent',
5526
                        self::ENG_US => 'AmericanEnglishContent',
5527
                    ],
5528
                ]
5529
            )->versionInfo
5530
        );
5531
5532
        $unrelatedContent = $this->contentService->publishVersion(
5533
            $this->createMultilingualContentDraft(
5534
                'folder',
5535
                2,
5536
                self::ENG_US,
5537
                [
5538
                    'name' => [
5539
                        self::ENG_GB => 'AnotherBritishContent',
5540
                        self::ENG_US => 'AnotherAmericanContent',
5541
                    ],
5542
                ]
5543
            )->versionInfo
5544
        );
5545
5546
        $urlAlias = $urlAliasService->lookup('/BritishEnglishContent');
5547
        self::assertFalse($urlAlias->isHistory);
5548
        self::assertEquals($urlAlias->path, '/BritishEnglishContent');
5549
        self::assertEquals($urlAlias->destination, $content->contentInfo->mainLocationId);
5550
5551
        $draft = $this->contentService->deleteTranslationFromDraft(
5552
            $this->contentService->createContentDraft($content->contentInfo)->versionInfo,
5553
            self::ENG_GB
5554
        );
5555
        $content = $this->contentService->publishVersion($draft->versionInfo);
5556
5557
        $urlAlias = $urlAliasService->lookup('/BritishEnglishContent');
5558
        self::assertTrue($urlAlias->isHistory);
5559
        self::assertEquals($urlAlias->path, '/BritishEnglishContent');
5560
        self::assertEquals($urlAlias->destination, $content->contentInfo->mainLocationId);
5561
5562
        $unrelatedUrlAlias = $urlAliasService->lookup('/AnotherBritishContent');
5563
        self::assertFalse($unrelatedUrlAlias->isHistory);
5564
        self::assertEquals($unrelatedUrlAlias->path, '/AnotherBritishContent');
5565
        self::assertEquals($unrelatedUrlAlias->destination, $unrelatedContent->contentInfo->mainLocationId);
5566
    }
5567
5568
    /**
5569
     * Test deleting a Translation from Draft which has single Translation throws BadStateException.
5570
     *
5571
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5572
     */
5573
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnSingleTranslation()
5574
    {
5575
        // create Content with single Translation
5576
        $publishedContent = $this->contentService->publishVersion(
5577
            $this->createContentDraft(
5578
                self::FORUM_IDENTIFIER,
5579
                2,
5580
                ['name' => 'Eng-US Version name']
5581
            )->versionInfo
5582
        );
5583
5584
        // update mainLanguageCode to avoid exception related to trying to delete main Translation
5585
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
5586
        $contentMetadataUpdateStruct->mainLanguageCode = self::ENG_GB;
5587
        $publishedContent = $this->contentService->updateContentMetadata(
5588
            $publishedContent->contentInfo,
5589
            $contentMetadataUpdateStruct
5590
        );
5591
5592
        // create single Translation Version from the first one
5593
        $draft = $this->contentService->createContentDraft(
5594
            $publishedContent->contentInfo,
5595
            $publishedContent->versionInfo
5596
        );
5597
5598
        $this->expectException(BadStateException::class);
5599
        $this->expectExceptionMessage('Specified Translation is the only one Content Object Version has');
5600
5601
        // attempt to delete Translation
5602
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, self::ENG_US);
5603
    }
5604
5605
    /**
5606
     * Test deleting the Main Translation from Draft throws BadStateException.
5607
     *
5608
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5609
     */
5610
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnMainTranslation()
5611
    {
5612
        $mainLanguageCode = self::ENG_US;
5613
        $draft = $this->createMultilingualContentDraft(
5614
            self::FORUM_IDENTIFIER,
5615
            2,
5616
            $mainLanguageCode,
5617
            [
5618
                'name' => [
5619
                    self::ENG_US => 'An awesome eng-US forum',
5620
                    self::ENG_GB => 'An awesome eng-GB forum',
5621
                ],
5622
            ]
5623
        );
5624
5625
        $this->expectException(BadStateException::class);
5626
        $this->expectExceptionMessage('Specified Translation is the main Translation of the Content Object');
5627
5628
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $mainLanguageCode);
5629
    }
5630
5631
    /**
5632
     * Test deleting the Translation from Published Version throws BadStateException.
5633
     *
5634
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5635
     */
5636
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnPublishedVersion()
5637
    {
5638
        $languageCode = self::ENG_US;
5639
        $content = $this->createMultipleLanguageContentVersion2();
5640
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5641
        $publishedContent = $this->contentService->publishVersion($draft->versionInfo);
5642
5643
        $this->expectException(BadStateException::class);
5644
        $this->expectExceptionMessage('Version is not a draft');
5645
5646
        $this->contentService->deleteTranslationFromDraft($publishedContent->versionInfo, $languageCode);
5647
    }
5648
5649
    /**
5650
     * Test deleting a Translation from Draft throws UnauthorizedException if user cannot edit Content.
5651
     *
5652
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5653
     */
5654
    public function testDeleteTranslationFromDraftThrowsUnauthorizedException()
5655
    {
5656
        $languageCode = self::ENG_GB;
5657
        $content = $this->createMultipleLanguageContentVersion2();
5658
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5659
5660
        // create user that can read/create/delete but cannot edit or content
5661
        $this->createRoleWithPolicies('Writer', [
5662
            ['module' => 'content', 'function' => 'read'],
5663
            ['module' => 'content', 'function' => 'versionread'],
5664
            ['module' => 'content', 'function' => 'create'],
5665
            ['module' => 'content', 'function' => 'delete'],
5666
        ]);
5667
        $writerUser = $this->createCustomUserWithLogin(
5668
            'user',
5669
            '[email protected]',
5670
            self::WRITERS_USER_GROUP_NAME,
5671
            'Writer'
5672
        );
5673
        $this->permissionResolver->setCurrentUserReference($writerUser);
5674
5675
        $this->expectException(UnauthorizedException::class);
5676
        $this->expectExceptionMessage('User does not have access to \'edit\' \'content\'');
5677
5678
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5679
    }
5680
5681
    /**
5682
     * Test deleting a non-existent Translation from Draft throws InvalidArgumentException.
5683
     *
5684
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5685
     */
5686
    public function testDeleteTranslationFromDraftThrowsInvalidArgumentException()
5687
    {
5688
        $languageCode = self::GER_DE;
5689
        $content = $this->createMultipleLanguageContentVersion2();
5690
        $draft = $this->contentService->createContentDraft($content->contentInfo);
5691
        $this->expectException(APIInvalidArgumentException::class);
5692
        $this->expectExceptionMessageRegExp('/The Version \(ContentId=\d+, VersionNo=\d+\) is not translated into ger-DE/');
5693
        $this->contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5694
    }
5695
5696
    /**
5697
     * Test loading list of Content items.
5698
     */
5699
    public function testLoadContentListByContentInfo()
5700
    {
5701
        $allLocationsCount = $this->locationService->getAllLocationsCount();
5702
        $contentInfoList = array_map(
5703
            function (Location $location) {
5704
                return $location->contentInfo;
5705
            },
5706
            $this->locationService->loadAllLocations(0, $allLocationsCount)
5707
        );
5708
5709
        $contentList = $this->contentService->loadContentListByContentInfo($contentInfoList);
5710
        self::assertCount(count($contentInfoList), $contentList);
5711
        foreach ($contentList as $content) {
5712
            try {
5713
                $loadedContent = $this->contentService->loadContent($content->id);
5714
                self::assertEquals($loadedContent, $content, "Failed to properly bulk-load Content {$content->id}");
5715
            } catch (NotFoundException $e) {
5716
                self::fail("Failed to load Content {$content->id}: {$e->getMessage()}");
5717
            } catch (UnauthorizedException $e) {
5718
                self::fail("Failed to load Content {$content->id}: {$e->getMessage()}");
5719
            }
5720
        }
5721
    }
5722
5723
    /**
5724
     * Test loading content versions after removing exactly two drafts.
5725
     *
5726
     * @see https://jira.ez.no/browse/EZP-30271
5727
     *
5728
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
5729
     */
5730
    public function testLoadVersionsAfterDeletingTwoDrafts()
5731
    {
5732
        $content = $this->createFolder([self::ENG_GB => 'Foo'], 2);
5733
5734
        // First update and publish
5735
        $modifiedContent = $this->updateFolder($content, [self::ENG_GB => 'Foo1']);
5736
        $content = $this->contentService->publishVersion($modifiedContent->versionInfo);
5737
5738
        // Second update and publish
5739
        $modifiedContent = $this->updateFolder($content, [self::ENG_GB => 'Foo2']);
5740
        $content = $this->contentService->publishVersion($modifiedContent->versionInfo);
5741
5742
        // Create drafts
5743
        $this->updateFolder($content, [self::ENG_GB => 'Foo3']);
5744
        $this->updateFolder($content, [self::ENG_GB => 'Foo4']);
5745
5746
        $versions = $this->contentService->loadVersions($content->contentInfo);
5747
5748
        foreach ($versions as $key => $version) {
5749
            if ($version->isDraft()) {
5750
                $this->contentService->deleteVersion($version);
5751
                unset($versions[$key]);
5752
            }
5753
        }
5754
5755
        $this->assertEquals($versions, $this->contentService->loadVersions($content->contentInfo));
5756
    }
5757
5758
    /**
5759
     * Tests loading list of content versions of status draft.
5760
     */
5761
    public function testLoadVersionsOfStatusDraft()
5762
    {
5763
        $content = $this->createContentVersion1();
5764
5765
        $this->contentService->createContentDraft($content->contentInfo);
5766
        $this->contentService->createContentDraft($content->contentInfo);
5767
        $this->contentService->createContentDraft($content->contentInfo);
5768
5769
        $versions = $this->contentService->loadVersions($content->contentInfo, VersionInfo::STATUS_DRAFT);
5770
5771
        $this->assertSame(\count($versions), 3);
5772
    }
5773
5774
    /**
5775
     * Tests loading list of content versions of status archived.
5776
     */
5777
    public function testLoadVersionsOfStatusArchived()
5778
    {
5779
        $content = $this->createContentVersion1();
5780
5781
        $draft1 = $this->contentService->createContentDraft($content->contentInfo);
5782
        $this->contentService->publishVersion($draft1->versionInfo);
5783
5784
        $draft2 = $this->contentService->createContentDraft($content->contentInfo);
5785
        $this->contentService->publishVersion($draft2->versionInfo);
5786
5787
        $versions = $this->contentService->loadVersions($content->contentInfo, VersionInfo::STATUS_ARCHIVED);
5788
5789
        $this->assertSame(\count($versions), 2);
5790
    }
5791
5792
    /**
5793
     * Asserts that all aliases defined in $expectedAliasProperties with the
5794
     * given properties are available in $actualAliases and not more.
5795
     *
5796
     * @param array $expectedAliasProperties
5797
     * @param array $actualAliases
5798
     */
5799
    private function assertAliasesCorrect(array $expectedAliasProperties, array $actualAliases)
5800
    {
5801
        foreach ($actualAliases as $actualAlias) {
5802
            if (!isset($expectedAliasProperties[$actualAlias->path])) {
5803
                $this->fail(
5804
                    sprintf(
5805
                        'Alias with path "%s" in languages "%s" not expected.',
5806
                        $actualAlias->path,
5807
                        implode(', ', $actualAlias->languageCodes)
5808
                    )
5809
                );
5810
            }
5811
5812
            foreach ($expectedAliasProperties[$actualAlias->path] as $propertyName => $propertyValue) {
5813
                $this->assertEquals(
5814
                    $propertyValue,
5815
                    $actualAlias->$propertyName,
5816
                    sprintf(
5817
                        'Property $%s incorrect on alias with path "%s" in languages "%s".',
5818
                        $propertyName,
5819
                        $actualAlias->path,
5820
                        implode(', ', $actualAlias->languageCodes)
5821
                    )
5822
                );
5823
            }
5824
5825
            unset($expectedAliasProperties[$actualAlias->path]);
5826
        }
5827
5828
        if (!empty($expectedAliasProperties)) {
5829
            $this->fail(
5830
                sprintf(
5831
                    'Missing expected aliases with paths "%s".',
5832
                    implode('", "', array_keys($expectedAliasProperties))
5833
                )
5834
            );
5835
        }
5836
    }
5837
5838
    /**
5839
     * Asserts that the given fields are equal to the default fields fixture.
5840
     *
5841
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
5842
     */
5843
    private function assertAllFieldsEquals(array $fields)
5844
    {
5845
        $actual = $this->normalizeFields($fields);
5846
        $expected = $this->normalizeFields($this->createFieldsFixture());
5847
5848
        $this->assertEquals($expected, $actual);
5849
    }
5850
5851
    /**
5852
     * Asserts that the given fields are equal to a language filtered set of the
5853
     * default fields fixture.
5854
     *
5855
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
5856
     * @param string $languageCode
5857
     */
5858
    private function assertLocaleFieldsEquals(array $fields, $languageCode)
5859
    {
5860
        $actual = $this->normalizeFields($fields);
5861
5862
        $expected = [];
5863
        foreach ($this->normalizeFields($this->createFieldsFixture()) as $field) {
5864
            if ($field->languageCode !== $languageCode) {
5865
                continue;
5866
            }
5867
            $expected[] = $field;
5868
        }
5869
5870
        $this->assertEquals($expected, $actual);
5871
    }
5872
5873
    /**
5874
     * This method normalizes a set of fields and returns a normalized set.
5875
     *
5876
     * Normalization means it resets the storage specific field id to zero and
5877
     * it sorts the field by their identifier and their language code. In
5878
     * addition, the field value is removed, since this one depends on the
5879
     * specific FieldType, which is tested in a dedicated integration test.
5880
     *
5881
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
5882
     *
5883
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
5884
     */
5885
    private function normalizeFields(array $fields)
5886
    {
5887
        $normalized = [];
5888
        foreach ($fields as $field) {
5889
            $normalized[] = new Field(
5890
                [
5891
                    'id' => 0,
5892
                    'value' => $field->value !== null,
5893
                    'languageCode' => $field->languageCode,
5894
                    'fieldDefIdentifier' => $field->fieldDefIdentifier,
5895
                    'fieldTypeIdentifier' => $field->fieldTypeIdentifier,
5896
                ]
5897
            );
5898
        }
5899
        usort(
5900
            $normalized,
5901
            function ($field1, $field2) {
5902
                if (0 === ($return = strcasecmp($field1->fieldDefIdentifier, $field2->fieldDefIdentifier))) {
5903
                    return strcasecmp($field1->languageCode, $field2->languageCode);
5904
                }
5905
5906
                return $return;
5907
            }
5908
        );
5909
5910
        return $normalized;
5911
    }
5912
5913
    /**
5914
     * Asserts that given Content has default ContentStates.
5915
     *
5916
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
5917
     */
5918
    private function assertDefaultContentStates(ContentInfo $contentInfo)
5919
    {
5920
        $objectStateService = $this->getRepository()->getObjectStateService();
5921
5922
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
5923
5924
        foreach ($objectStateGroups as $objectStateGroup) {
5925
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
5926
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
5927
                // Only check the first object state which is the default one.
5928
                $this->assertEquals(
5929
                    $objectState,
5930
                    $contentState
5931
                );
5932
                break;
5933
            }
5934
        }
5935
    }
5936
5937
    /**
5938
     * Assert that given Content has no references to a translation specified by the $languageCode.
5939
     *
5940
     * @param string $languageCode
5941
     * @param int $contentId
5942
     */
5943
    private function assertTranslationDoesNotExist($languageCode, $contentId)
5944
    {
5945
        $content = $this->contentService->loadContent($contentId);
5946
5947
        foreach ($content->fields as $field) {
5948
            /** @var array $field */
5949
            self::assertArrayNotHasKey($languageCode, $field);
5950
            self::assertNotEquals($languageCode, $content->contentInfo->mainLanguageCode);
5951
            self::assertArrayNotHasKey($languageCode, $content->versionInfo->getNames());
5952
            self::assertNotEquals($languageCode, $content->versionInfo->initialLanguageCode);
5953
            self::assertNotContains($languageCode, $content->versionInfo->languageCodes);
5954
        }
5955
        foreach ($this->contentService->loadVersions($content->contentInfo) as $versionInfo) {
5956
            self::assertArrayNotHasKey($languageCode, $versionInfo->getNames());
5957
            self::assertNotEquals($languageCode, $versionInfo->contentInfo->mainLanguageCode);
5958
            self::assertNotEquals($languageCode, $versionInfo->initialLanguageCode);
5959
            self::assertNotContains($languageCode, $versionInfo->languageCodes);
5960
        }
5961
    }
5962
5963
    /**
5964
     * Returns the default fixture of fields used in most tests.
5965
     *
5966
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
5967
     */
5968
    private function createFieldsFixture()
5969
    {
5970
        return [
5971
            new Field(
5972
                [
5973
                    'id' => 0,
5974
                    'value' => 'Foo',
5975
                    'languageCode' => self::ENG_US,
5976
                    'fieldDefIdentifier' => 'description',
5977
                    'fieldTypeIdentifier' => 'ezrichtext',
5978
                ]
5979
            ),
5980
            new Field(
5981
                [
5982
                    'id' => 0,
5983
                    'value' => 'Bar',
5984
                    'languageCode' => self::ENG_GB,
5985
                    'fieldDefIdentifier' => 'description',
5986
                    'fieldTypeIdentifier' => 'ezrichtext',
5987
                ]
5988
            ),
5989
            new Field(
5990
                [
5991
                    'id' => 0,
5992
                    'value' => 'An awesome multi-lang forum²',
5993
                    'languageCode' => self::ENG_US,
5994
                    'fieldDefIdentifier' => 'name',
5995
                    'fieldTypeIdentifier' => 'ezstring',
5996
                ]
5997
            ),
5998
            new Field(
5999
                [
6000
                    'id' => 0,
6001
                    'value' => 'An awesome multi-lang forum²³',
6002
                    'languageCode' => self::ENG_GB,
6003
                    'fieldDefIdentifier' => 'name',
6004
                    'fieldTypeIdentifier' => 'ezstring',
6005
                ]
6006
            ),
6007
        ];
6008
    }
6009
6010
    /**
6011
     * Gets expected property values for the "Media" ContentInfo ValueObject.
6012
     *
6013
     * @return array
6014
     */
6015
    private function getExpectedMediaContentInfoProperties()
6016
    {
6017
        return [
6018
            'id' => self::MEDIA_CONTENT_ID,
6019
            'contentTypeId' => 1,
6020
            'name' => 'Media',
6021
            'sectionId' => 3,
6022
            'currentVersionNo' => 1,
6023
            'published' => true,
6024
            'ownerId' => 14,
6025
            'modificationDate' => $this->createDateTime(1060695457),
6026
            'publishedDate' => $this->createDateTime(1060695457),
6027
            'alwaysAvailable' => 1,
6028
            'remoteId' => self::MEDIA_REMOTE_ID,
6029
            'mainLanguageCode' => self::ENG_US,
6030
            'mainLocationId' => 43,
6031
            'status' => ContentInfo::STATUS_PUBLISHED,
6032
        ];
6033
    }
6034
6035
    /**
6036
     * @covers \eZ\Publish\API\Repository\ContentService::hideContent
6037
     *
6038
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
6039
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
6040
     * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException
6041
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6042
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
6043
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6044
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6045
     */
6046
    public function testHideContent(): void
6047
    {
6048
        $contentTypeService = $this->getRepository()->getContentTypeService();
6049
6050
        $locationCreateStructs = array_map(
6051
            function (Location $parentLocation) {
6052
                return $this->locationService->newLocationCreateStruct($parentLocation->id);
6053
            },
6054
            $this->createParentLocationsForHideReveal(2)
6055
        );
6056
6057
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6058
6059
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6060
        $contentCreate->setField('name', 'Folder to hide');
6061
6062
        $content = $this->contentService->createContent(
6063
            $contentCreate,
6064
            $locationCreateStructs
6065
        );
6066
6067
        $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6068
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6069
6070
        // Sanity check
6071
        $this->assertCount(3, $locations);
6072
        $this->assertCount(0, $this->filterHiddenLocations($locations));
6073
6074
        $this->contentService->hideContent($publishedContent->contentInfo);
6075
6076
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6077
        $this->assertCount(3, $locations);
6078
        $this->assertCount(3, $this->filterHiddenLocations($locations));
6079
    }
6080
6081
    /**
6082
     * @covers \eZ\Publish\API\Repository\ContentService::revealContent
6083
     *
6084
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6085
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6086
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6087
     */
6088
    public function testRevealContent()
6089
    {
6090
        $contentTypeService = $this->getRepository()->getContentTypeService();
6091
6092
        $locationCreateStructs = array_map(
6093
            function (Location $parentLocation) {
6094
                return $this->locationService->newLocationCreateStruct($parentLocation->id);
6095
            },
6096
            $this->createParentLocationsForHideReveal(2)
6097
        );
6098
6099
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6100
6101
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6102
        $contentCreate->setField('name', 'Folder to hide');
6103
6104
        $locationCreateStructs[0]->hidden = true;
6105
6106
        $content = $this->contentService->createContent(
6107
            $contentCreate,
6108
            $locationCreateStructs
6109
        );
6110
6111
        $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6112
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6113
6114
        // Sanity check
6115
        $hiddenLocations = $this->filterHiddenLocations($locations);
6116
        $this->assertCount(3, $locations);
6117
        $this->assertCount(1, $hiddenLocations);
6118
6119
        $this->contentService->hideContent($publishedContent->contentInfo);
6120
        $this->assertCount(
6121
            3,
6122
            $this->filterHiddenLocations(
6123
                $this->locationService->loadLocations($publishedContent->contentInfo)
6124
            )
6125
        );
6126
6127
        $this->contentService->revealContent($publishedContent->contentInfo);
6128
6129
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6130
        $hiddenLocationsAfterReveal = $this->filterHiddenLocations($locations);
6131
        $this->assertCount(3, $locations);
6132
        $this->assertCount(1, $hiddenLocationsAfterReveal);
6133
        $this->assertEquals($hiddenLocations, $hiddenLocationsAfterReveal);
6134
    }
6135
6136
    /**
6137
     * @depends testRevealContent
6138
     */
6139
    public function testRevealContentWithHiddenParent()
6140
    {
6141
        $contentTypeService = $this->getRepository()->getContentTypeService();
6142
6143
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6144
6145
        $contentNames = [
6146
            'Parent Content',
6147
            'Child (Nesting 1)',
6148
            'Child (Nesting 2)',
6149
            'Child (Nesting 3)',
6150
            'Child (Nesting 4)',
6151
        ];
6152
6153
        $parentLocation = $this->locationService->newLocationCreateStruct(
6154
            $this->generateId('location', 2)
6155
        );
6156
6157
        /** @var Content[] $contents */
6158
        $contents = [];
6159
6160
        foreach ($contentNames as $contentName) {
6161
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6162
            $contentCreate->setField('name', $contentName);
6163
6164
            $content = $this->contentService->createContent($contentCreate, [$parentLocation]);
6165
            $contents[] = $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6166
6167
            $parentLocation = $this->locationService->newLocationCreateStruct(
6168
                $this->generateId('location', $publishedContent->contentInfo->mainLocationId)
6169
            );
6170
        }
6171
6172
        $this->contentService->hideContent($contents[0]->contentInfo);
6173
        $this->contentService->hideContent($contents[2]->contentInfo);
6174
        $this->contentService->revealContent($contents[2]->contentInfo);
6175
6176
        $parentContent = $this->contentService->loadContent($contents[0]->id);
6177
        $parentLocation = $this->locationService->loadLocation($parentContent->contentInfo->mainLocationId);
6178
        $parentSublocations = $this->locationService->loadLocationList([
6179
            $contents[1]->contentInfo->mainLocationId,
6180
            $contents[2]->contentInfo->mainLocationId,
6181
            $contents[3]->contentInfo->mainLocationId,
6182
            $contents[4]->contentInfo->mainLocationId,
6183
        ]);
6184
6185
        // Parent remains invisible
6186
        self::assertTrue($parentLocation->invisible);
6187
6188
        // All parent sublocations remain invisible as well
6189
        foreach ($parentSublocations as $parentSublocation) {
6190
            self::assertTrue($parentSublocation->invisible);
6191
        }
6192
    }
6193
6194
    /**
6195
     * @depends testRevealContent
6196
     */
6197
    public function testRevealContentWithHiddenChildren()
6198
    {
6199
        $contentTypeService = $this->getRepository()->getContentTypeService();
6200
6201
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6202
6203
        $contentNames = [
6204
            'Parent Content',
6205
            'Child (Nesting 1)',
6206
            'Child (Nesting 2)',
6207
            'Child (Nesting 3)',
6208
            'Child (Nesting 4)',
6209
        ];
6210
6211
        $parentLocation = $this->locationService->newLocationCreateStruct(
6212
            $this->generateId('location', 2)
6213
        );
6214
6215
        /** @var Content[] $contents */
6216
        $contents = [];
6217
6218
        foreach ($contentNames as $contentName) {
6219
            $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6220
            $contentCreate->setField('name', $contentName);
6221
6222
            $content = $this->contentService->createContent($contentCreate, [$parentLocation]);
6223
            $contents[] = $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6224
6225
            $parentLocation = $this->locationService->newLocationCreateStruct(
6226
                $this->generateId('location', $publishedContent->contentInfo->mainLocationId)
6227
            );
6228
        }
6229
6230
        $this->contentService->hideContent($contents[0]->contentInfo);
6231
        $this->contentService->hideContent($contents[2]->contentInfo);
6232
        $this->contentService->revealContent($contents[0]->contentInfo);
6233
6234
        $directChildContent = $this->contentService->loadContent($contents[1]->id);
6235
        $directChildLocation = $this->locationService->loadLocation($directChildContent->contentInfo->mainLocationId);
6236
6237
        $childContent = $this->contentService->loadContent($contents[2]->id);
6238
        $childLocation = $this->locationService->loadLocation($childContent->contentInfo->mainLocationId);
6239
        $childSublocations = $this->locationService->loadLocationList([
6240
            $contents[3]->contentInfo->mainLocationId,
6241
            $contents[4]->contentInfo->mainLocationId,
6242
        ]);
6243
6244
        // Direct child content is not hidden
6245
        self::assertFalse($directChildContent->contentInfo->isHidden);
6246
6247
        // Direct child content location is still invisible
6248
        self::assertFalse($directChildLocation->invisible);
6249
6250
        // Child content is still hidden
6251
        self::assertTrue($childContent->contentInfo->isHidden);
6252
6253
        // Child content location is still invisible
6254
        self::assertTrue($childLocation->invisible);
6255
6256
        // All childs sublocations remain invisible as well
6257
        foreach ($childSublocations as $childSublocation) {
6258
            self::assertTrue($childSublocation->invisible);
6259
        }
6260
    }
6261
6262
    public function testHideContentWithParentLocation()
6263
    {
6264
        $contentTypeService = $this->getRepository()->getContentTypeService();
6265
6266
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6267
6268
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6269
        $contentCreate->setField('name', 'Parent');
6270
6271
        $content = $this->contentService->createContent(
6272
            $contentCreate,
6273
            [
6274
                $this->locationService->newLocationCreateStruct(
6275
                    $this->generateId('location', 2)
6276
                ),
6277
            ]
6278
        );
6279
6280
        $publishedContent = $this->contentService->publishVersion($content->versionInfo);
6281
6282
        $this->contentService->hideContent($publishedContent->contentInfo);
6283
6284
        $locations = $this->locationService->loadLocations($publishedContent->contentInfo);
6285
6286
        $childContentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
6287
        $childContentCreate->setField('name', 'Child');
6288
6289
        $childContent = $this->contentService->createContent(
6290
            $childContentCreate,
6291
            [
6292
                $this->locationService->newLocationCreateStruct(
6293
                    $locations[0]->id
6294
                ),
6295
            ]
6296
        );
6297
6298
        $publishedChildContent = $this->contentService->publishVersion($childContent->versionInfo);
6299
6300
        $childLocations = $this->locationService->loadLocations($publishedChildContent->contentInfo);
6301
6302
        $this->assertTrue($locations[0]->hidden);
6303
        $this->assertTrue($locations[0]->invisible);
6304
6305
        $this->assertFalse($childLocations[0]->hidden);
6306
        $this->assertTrue($childLocations[0]->invisible);
6307
    }
6308
6309
    public function testChangeContentName()
6310
    {
6311
        $contentDraft = $this->createContentDraft(
6312
            'folder',
6313
            $this->generateId('location', 2),
6314
            [
6315
                'name' => 'Marco',
6316
            ]
6317
        );
6318
6319
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
6320
        $contentMetadataUpdateStruct = new ContentMetadataUpdateStruct([
6321
            'name' => 'Polo',
6322
        ]);
6323
        $this->contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
6324
6325
        $updatedContent = $this->contentService->loadContent($publishedContent->id);
6326
6327
        $this->assertEquals('Marco', $publishedContent->contentInfo->name);
6328
        $this->assertEquals('Polo', $updatedContent->contentInfo->name);
6329
    }
6330
6331
    public function testCopyTranslationsFromPublishedToDraft()
6332
    {
6333
        $contentDraft = $this->createContentDraft(
6334
            'folder',
6335
            $this->generateId('location', 2),
6336
            [
6337
                'name' => 'Folder US',
6338
            ]
6339
        );
6340
6341
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
6342
6343
        $deDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6344
6345
        $contentUpdateStruct = new ContentUpdateStruct([
6346
            'initialLanguageCode' => self::GER_DE,
6347
            'fields' => $contentDraft->getFields(),
6348
        ]);
6349
6350
        $contentUpdateStruct->setField('name', 'Folder GER', self::GER_DE);
6351
6352
        $deContent = $this->contentService->updateContent($deDraft->versionInfo, $contentUpdateStruct);
6353
6354
        $updatedContent = $this->contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6355
        $this->assertEquals(
6356
            [
6357
                self::ENG_US => 'Folder US',
6358
                self::GER_DE => 'Folder GER',
6359
            ],
6360
            $updatedContent->fields['name']
6361
        );
6362
6363
        $gbDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6364
6365
        $contentUpdateStruct = new ContentUpdateStruct([
6366
            'initialLanguageCode' => self::ENG_GB,
6367
            'fields' => $contentDraft->getFields(),
6368
        ]);
6369
6370
        $contentUpdateStruct->setField('name', 'Folder GB', self::ENG_GB);
6371
6372
        $gbContent = $this->contentService->updateContent($gbDraft->versionInfo, $contentUpdateStruct);
6373
        $this->contentService->publishVersion($gbDraft->versionInfo);
6374
        $updatedContent = $this->contentService->loadContent($gbContent->id, null, $gbContent->versionInfo->versionNo);
6375
        $this->assertEquals(
6376
            [
6377
                self::ENG_US => 'Folder US',
6378
                self::ENG_GB => 'Folder GB',
6379
            ],
6380
            $updatedContent->fields['name']
6381
        );
6382
6383
        $dePublished = $this->contentService->publishVersion($deDraft->versionInfo);
6384
        $this->assertEquals(
6385
            [
6386
                self::ENG_US => 'Folder US',
6387
                self::GER_DE => 'Folder GER',
6388
                self::ENG_GB => 'Folder GB',
6389
            ],
6390
            $dePublished->fields['name']
6391
        );
6392
    }
6393
6394
    public function testCopyTranslationsFromInvalidPublishedContentToDraft()
6395
    {
6396
        $contentTypeService = $this->getRepository()->getContentTypeService();
6397
6398
        // Create content type for testing
6399
        $contentTypeCreateStruct = $contentTypeService->newContentTypeCreateStruct('test_copy_translation');
6400
        $contentTypeCreateStruct->mainLanguageCode = 'eng-US';
6401
        $contentTypeCreateStruct->names = ['eng-US' => 'Test Content Type for Copy Translations'];
6402
        $fieldDefinition = $contentTypeService->newFieldDefinitionCreateStruct('name', 'ezstring');
6403
        $fieldDefinition->position = 1;
6404
        $contentTypeCreateStruct->addFieldDefinition($fieldDefinition);
6405
        $contentTypeService->publishContentTypeDraft(
6406
            $contentTypeService->createContentType(
6407
                $contentTypeCreateStruct,
6408
                [$contentTypeService->loadContentTypeGroupByIdentifier('Content')]
6409
            )
6410
        );
6411
        $contentType = $contentTypeService->loadContentTypeByIdentifier('test_copy_translation');
6412
6413
        // Create entry content
6414
        $contentDraft = $this->createContentDraft(
6415
            'test_copy_translation',
6416
            $this->generateId('location', 2),
6417
            [
6418
                'name' => 'Folder US',
6419
            ]
6420
        );
6421
        $publishedContent = $this->contentService->publishVersion($contentDraft->versionInfo);
6422
6423
        // Create translation draft that would act as an OLD version
6424
        $deDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6425
        $contentUpdateStruct = new ContentUpdateStruct([
6426
            'initialLanguageCode' => self::GER_DE,
6427
            'fields' => $contentDraft->getFields(),
6428
        ]);
6429
6430
        $contentUpdateStruct->setField('name', 'Folder GER', self::GER_DE);
6431
        $deContent = $this->contentService->updateContent($deDraft->versionInfo, $contentUpdateStruct);
6432
6433
        // Update published version, as copying is only done when there is a diff between published and draft
6434
        $gbDraft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6435
        $contentUpdateStruct = new ContentUpdateStruct([
6436
            'initialLanguageCode' => self::ENG_US,
6437
        ]);
6438
        $contentUpdateStruct->setField('name', 'Folder US 2', self::ENG_US);
6439
6440
        $gbContent = $this->contentService->updateContent($gbDraft->versionInfo, $contentUpdateStruct);
6441
        $this->contentService->publishVersion($gbContent->versionInfo);
6442
6443
        // Update content type with new required field
6444
        $contentTypeDraft = $contentTypeService->createContentTypeDraft($contentType);
6445
        $fieldDefinition = $contentTypeService->newFieldDefinitionCreateStruct('req_field', 'ezstring');
6446
        $fieldDefinition->position = 2;
6447
        $fieldDefinition->isRequired = true;
6448
        $contentTypeService->addFieldDefinition($contentTypeDraft, $fieldDefinition);
6449
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
6450
6451
        // Reload previous german draft, it is now in invalid state for both ENG_US and GER_DE
6452
        $invalidContentDraft = $this->contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6453
        $contentUpdateStruct = new ContentUpdateStruct([
6454
            'initialLanguageCode' => self::GER_DE,
6455
        ]);
6456
        $contentUpdateStruct->setField('req_field', 'Required field DE', self::GER_DE);
6457
6458
        $this->contentService->updateContent($invalidContentDraft->versionInfo, $contentUpdateStruct);
6459
        $this->contentService->publishVersion($invalidContentDraft->versionInfo, [self::GER_DE]);
6460
6461
        $publishedContent = $this->contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6462
6463
        $this->assertEquals(
6464
            [
6465
                self::GER_DE => 'Folder GER',
6466
                self::ENG_US => 'Folder US 2',
6467
            ],
6468
            $publishedContent->fields['name']
6469
        );
6470
        // Missing values were copied from last updated draft
6471
        $this->assertEquals(
6472
            [
6473
                self::GER_DE => 'Required field DE',
6474
                self::ENG_US => 'Required field DE',
6475
            ],
6476
            $publishedContent->fields['req_field']
6477
        );
6478
    }
6479
6480
    /**
6481
     * Create structure of parent folders with Locations to be used for Content hide/reveal tests.
6482
     *
6483
     * @param int $parentLocationId
6484
     *
6485
     * @return \eZ\Publish\API\Repository\Values\Content\Location[] A list of Locations aimed to be parents
6486
     *
6487
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6488
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6489
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6490
     */
6491
    private function createParentLocationsForHideReveal(int $parentLocationId): array
6492
    {
6493
        $parentFoldersLocationsIds = [
6494
            $this->createFolder([self::ENG_US => 'P1'], $parentLocationId)->contentInfo->mainLocationId,
6495
            $this->createFolder([self::ENG_US => 'P2'], $parentLocationId)->contentInfo->mainLocationId,
6496
            $this->createFolder([self::ENG_US => 'P3'], $parentLocationId)->contentInfo->mainLocationId,
6497
        ];
6498
6499
        return array_values($this->locationService->loadLocationList($parentFoldersLocationsIds));
6500
    }
6501
6502
    /**
6503
     * Filter Locations list by hidden only.
6504
     *
6505
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
6506
     *
6507
     * @return array
6508
     */
6509
    private function filterHiddenLocations(array $locations): array
6510
    {
6511
        return array_values(
6512
            array_filter(
6513
                $locations,
6514
                function (Location $location) {
6515
                    return $location->hidden;
6516
                }
6517
            )
6518
        );
6519
    }
6520
6521
    public function testPublishVersionWithSelectedLanguages()
6522
    {
6523
        $publishedContent = $this->createFolder(
6524
            [
6525
                self::ENG_US => 'Published US',
6526
                self::GER_DE => 'Published DE',
6527
            ],
6528
            $this->generateId('location', 2)
6529
        );
6530
6531
        $draft = $this->contentService->createContentDraft($publishedContent->contentInfo);
6532
        $contentUpdateStruct = new ContentUpdateStruct([
6533
            'initialLanguageCode' => self::ENG_US,
6534
        ]);
6535
        $contentUpdateStruct->setField('name', 'Draft 1 US', self::ENG_US);
6536
        $contentUpdateStruct->setField('name', 'Draft 1 DE', self::GER_DE);
6537
6538
        $this->contentService->updateContent($draft->versionInfo, $contentUpdateStruct);
6539
6540
        $this->contentService->publishVersion($draft->versionInfo, [self::GER_DE]);
6541
        $content = $this->contentService->loadContent($draft->contentInfo->id);
6542
        $this->assertEquals(
6543
            [
6544
                self::ENG_US => 'Published US',
6545
                self::GER_DE => 'Draft 1 DE',
6546
            ],
6547
            $content->fields['name']
6548
        );
6549
    }
6550
6551
    public function testCreateContentWithRomanianSpecialCharsInTitle()
6552
    {
6553
        $baseName = 'ȘșțȚdfdf';
6554
        $expectedPath = '/SstTdfdf';
6555
6556
        $this->createFolder([self::ENG_US => $baseName], 2);
6557
6558
        $urlAliasService = $this->getRepository()->getURLAliasService();
6559
        $urlAlias = $urlAliasService->lookup($expectedPath);
6560
        $this->assertSame($expectedPath, $urlAlias->path);
6561
    }
6562
6563
    /**
6564
     * @param int $amountOfDrafts
6565
     *
6566
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6567
     */
6568
    private function createContentDrafts(int $amountOfDrafts): void
6569
    {
6570
        if (0 >= $amountOfDrafts) {
6571
            throw new InvalidArgumentException('$amountOfDrafts', 'Must be greater then 0');
6572
        }
6573
6574
        $publishedContent = $this->createContentVersion1();
6575
6576
        for ($i = 1; $i <= $amountOfDrafts; ++$i) {
6577
            $this->contentService->createContentDraft($publishedContent->contentInfo);
6578
        }
6579
    }
6580
6581
    /**
6582
     * @param array $limitationValues
6583
     *
6584
     * @return \eZ\Publish\API\Repository\Values\User\User
6585
     *
6586
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6587
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6588
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6589
     */
6590
    private function createUserWithVersionReadLimitations(array $limitationValues = []): User
6591
    {
6592
        $limitations = [
6593
            new LocationLimitation(['limitationValues' => $limitationValues]),
6594
        ];
6595
6596
        return $this->createUserWithPolicies(
6597
            'user',
6598
            [
6599
                ['module' => 'content', 'function' => 'versionread', 'limitations' => $limitations],
6600
                ['module' => 'content', 'function' => 'create'],
6601
                ['module' => 'content', 'function' => 'read'],
6602
                ['module' => 'content', 'function' => 'edit'],
6603
            ]
6604
        );
6605
    }
6606
6607
    /**
6608
     * @param \eZ\Publish\API\Repository\Values\Content\Content[] $drafts
6609
     *
6610
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
6611
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6612
     *
6613
     * @return object
6614
     */
6615
    private function createContentWithReverseRelations(array $drafts)
6616
    {
6617
        $contentWithReverseRelations = new class() {
6618
            /** @var \eZ\Publish\API\Repository\Values\Content\Content */
6619
            public $content;
6620
6621
            /** @var \eZ\Publish\API\Repository\Values\Content\Content[] */
6622
            public $reverseRelations;
6623
        };
6624
        $content = $this->createContentVersion1();
6625
        $versionInfo = $content->getVersionInfo();
6626
        $contentInfo = $versionInfo->getContentInfo();
6627
        $contentWithReverseRelations->content = $content;
6628
6629
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $draft */
6630
        foreach ($drafts as $draft) {
6631
            $this->contentService->addRelation(
6632
                $draft->getVersionInfo(),
6633
                $contentInfo
6634
            );
6635
6636
            $contentWithReverseRelations->reverseRelations[] = $this->contentService->publishVersion($draft->getVersionInfo());
6637
        }
6638
6639
        return $contentWithReverseRelations;
6640
    }
6641
}
6642