Completed
Push — 7.5 ( eb35b7...ffc5d4 )
by
unknown
19:26
created

ContentServiceTest   B

Complexity

Total Complexity 2

Size/Duplication

Total Lines 6386
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6386
rs 8.8
c 0
b 0
f 0
wmc 2

203 Methods

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