Completed
Push — ezp-30936-edit-content-new-req... ( e7aa44 )
by
unknown
22:52
created

ContentServiceTest   B

Complexity

Total Complexity 2

Size/Duplication

Total Lines 6411
Duplicated Lines 0 %

Importance

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

204 Methods

Rating   Name   Duplication   Size   Complexity  
A testCreateContentDraftSetsExpectedProperties() 0 13 1
A testCreateContentDraftSetsContentInfo() 0 25 1
A testCreateContentDraftSetsVersionInfo() 0 24 1
A testLoadContentInfoList() 0 12 1
A testLoadContentInfoListSkipsNotFoundItems() 0 7 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 testCreateContentDraftInOtherLanguage() 0 17 1
A testCreateContentDraftAndLoadAccess() 0 15 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 testAddRelationAddsRelationToContent() 0 7 1
A assertExpectedRelations() 0 17 1
A testAddRelationSetsExpectedRelations() 0 4 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 with given language for new draft.
1144
     *
1145
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1146
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1147
     * @group user
1148
     */
1149
    public function testCreateContentDraftInOtherLanguage()
1150
    {
1151
        $content = $this->createContentVersion1();
1152
1153
        $language = $this->getRepository()->getContentLanguageService()->loadLanguage('eng-GB');
1154
1155
        // Now we create a new draft from the published content
1156
        $draftedContent = $this->contentService->createContentDraft(
1157
            $content->contentInfo,
1158
            null,
1159
            null,
1160
            $language
1161
        );
1162
1163
        $this->assertEquals('eng-US', $content->versionInfo->initialLanguageCode);
1164
        $this->assertEquals('eng-GB', $draftedContent->versionInfo->initialLanguageCode);
1165
    }
1166
1167
    /**
1168
     * Test for the createContentDraft() method.
1169
     *
1170
     * Test that editor has access to edit own draft.
1171
     * Note: Editors have access to version_read, which is needed to load content drafts.
1172
     *
1173
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1174
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1175
     * @group user
1176
     */
1177
    public function testCreateContentDraftAndLoadAccess()
1178
    {
1179
        $user = $this->createUserVersion1();
1180
1181
        // Set new editor as user
1182
        $this->permissionResolver->setCurrentUserReference($user);
1183
1184
        // Create draft
1185
        $draft = $this->createContentDraftVersion1(2, 'folder');
1186
1187
        // Try to load the draft
1188
        $loadedDraft = $this->contentService->loadContent($draft->id);
1189
1190
        $this->assertEquals($draft->id, $loadedDraft->id);
1191
    }
1192
1193
    /**
1194
     * Test for the createContentDraft() method.
1195
     *
1196
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1197
     *
1198
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1199
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1200
     */
1201
    public function testCreateContentDraftSetsExpectedProperties($draft)
1202
    {
1203
        $this->assertEquals(
1204
            [
1205
                'fieldCount' => 2,
1206
                'relationCount' => 0,
1207
            ],
1208
            [
1209
                'fieldCount' => count($draft->getFields()),
1210
                'relationCount' => count($this->getRepository()->getContentService()->loadRelations($draft->getVersionInfo())),
1211
            ]
1212
        );
1213
    }
1214
1215
    /**
1216
     * Test for the createContentDraft() method.
1217
     *
1218
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1219
     *
1220
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1221
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1222
     */
1223
    public function testCreateContentDraftSetsContentInfo($draft)
1224
    {
1225
        $contentInfo = $draft->contentInfo;
1226
1227
        $this->assertEquals(
1228
            [
1229
                $draft->id,
1230
                true,
1231
                1,
1232
                self::ENG_US,
1233
                $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...
1234
                'abcdef0123456789abcdef0123456789',
1235
                1,
1236
            ],
1237
            [
1238
                $contentInfo->id,
1239
                $contentInfo->alwaysAvailable,
1240
                $contentInfo->currentVersionNo,
1241
                $contentInfo->mainLanguageCode,
1242
                $contentInfo->ownerId,
1243
                $contentInfo->remoteId,
1244
                $contentInfo->sectionId,
1245
            ]
1246
        );
1247
    }
1248
1249
    /**
1250
     * Test for the createContentDraft() method.
1251
     *
1252
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1253
     *
1254
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1255
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1256
     */
1257
    public function testCreateContentDraftSetsVersionInfo($draft)
1258
    {
1259
        $versionInfo = $draft->getVersionInfo();
1260
1261
        $this->assertEquals(
1262
            [
1263
                '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...
1264
                'initialLanguageCode' => self::ENG_US,
1265
                'languageCodes' => [0 => self::ENG_US],
1266
                'status' => VersionInfo::STATUS_DRAFT,
1267
                'versionNo' => 2,
1268
            ],
1269
            [
1270
                'creatorId' => $versionInfo->creatorId,
1271
                'initialLanguageCode' => $versionInfo->initialLanguageCode,
1272
                'languageCodes' => $versionInfo->languageCodes,
1273
                'status' => $versionInfo->status,
1274
                'versionNo' => $versionInfo->versionNo,
1275
            ]
1276
        );
1277
        $this->assertTrue($versionInfo->isDraft());
1278
        $this->assertFalse($versionInfo->isPublished());
1279
        $this->assertFalse($versionInfo->isArchived());
1280
    }
1281
1282
    /**
1283
     * Test for the createContentDraft() method.
1284
     *
1285
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1286
     *
1287
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1288
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1289
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
1290
     */
1291
    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...
1292
    {
1293
        $content = $this->createContentVersion1();
1294
1295
        // Now we create a new draft from the published content
1296
        $this->contentService->createContentDraft($content->contentInfo);
1297
1298
        // This call will still load the published version
1299
        $versionInfoPublished = $this->contentService->loadVersionInfo($content->contentInfo);
1300
1301
        $this->assertEquals(1, $versionInfoPublished->versionNo);
1302
    }
1303
1304
    /**
1305
     * Test for the createContentDraft() method.
1306
     *
1307
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1308
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
1309
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1310
     */
1311
    public function testCreateContentDraftLoadContentStillLoadsPublishedVersion()
1312
    {
1313
        $content = $this->createContentVersion1();
1314
1315
        // Now we create a new draft from the published content
1316
        $this->contentService->createContentDraft($content->contentInfo);
1317
1318
        // This call will still load the published content version
1319
        $contentPublished = $this->contentService->loadContent($content->id);
1320
1321
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1322
    }
1323
1324
    /**
1325
     * Test for the createContentDraft() method.
1326
     *
1327
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1328
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteId
1329
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1330
     */
1331
    public function testCreateContentDraftLoadContentByRemoteIdStillLoadsPublishedVersion()
1332
    {
1333
        $content = $this->createContentVersion1();
1334
1335
        // Now we create a new draft from the published content
1336
        $this->contentService->createContentDraft($content->contentInfo);
1337
1338
        // This call will still load the published content version
1339
        $contentPublished = $this->contentService->loadContentByRemoteId('abcdef0123456789abcdef0123456789');
1340
1341
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1342
    }
1343
1344
    /**
1345
     * Test for the createContentDraft() method.
1346
     *
1347
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1348
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
1349
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1350
     */
1351
    public function testCreateContentDraftLoadContentByContentInfoStillLoadsPublishedVersion()
1352
    {
1353
        $content = $this->createContentVersion1();
1354
1355
        // Now we create a new draft from the published content
1356
        $this->contentService->createContentDraft($content->contentInfo);
1357
1358
        // This call will still load the published content version
1359
        $contentPublished = $this->contentService->loadContentByContentInfo($content->contentInfo);
1360
1361
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1362
    }
1363
1364
    /**
1365
     * Test for the newContentUpdateStruct() method.
1366
     *
1367
     * @covers \eZ\Publish\API\Repository\ContentService::newContentUpdateStruct
1368
     * @group user
1369
     */
1370
    public function testNewContentUpdateStruct()
1371
    {
1372
        $updateStruct = $this->contentService->newContentUpdateStruct();
1373
1374
        $this->assertInstanceOf(
1375
            ContentUpdateStruct::class,
1376
            $updateStruct
1377
        );
1378
1379
        $this->assertPropertiesCorrect(
1380
            [
1381
                'initialLanguageCode' => null,
1382
                'fields' => [],
1383
            ],
1384
            $updateStruct
1385
        );
1386
    }
1387
1388
    /**
1389
     * Test for the updateContent() method.
1390
     *
1391
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1392
     *
1393
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1394
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentUpdateStruct
1395
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1396
     * @group user
1397
     * @group field-type
1398
     */
1399
    public function testUpdateContent()
1400
    {
1401
        $draftVersion2 = $this->createUpdatedDraftVersion2();
1402
1403
        $this->assertInstanceOf(
1404
            Content::class,
1405
            $draftVersion2
1406
        );
1407
1408
        $this->assertEquals(
1409
            $this->generateId('user', 10),
1410
            $draftVersion2->versionInfo->creatorId,
1411
            'creatorId is not properly set on new Version'
1412
        );
1413
1414
        return $draftVersion2;
1415
    }
1416
1417
    /**
1418
     * Test for the updateContent_WithDifferentUser() method.
1419
     *
1420
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1421
     *
1422
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1423
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentUpdateStruct
1424
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1425
     * @group user
1426
     * @group field-type
1427
     */
1428
    public function testUpdateContentWithDifferentUser()
1429
    {
1430
        $arrayWithDraftVersion2 = $this->createUpdatedDraftVersion2NotAdmin();
1431
1432
        $this->assertInstanceOf(
1433
            Content::class,
1434
            $arrayWithDraftVersion2[0]
1435
        );
1436
1437
        $this->assertEquals(
1438
            $this->generateId('user', $arrayWithDraftVersion2[1]),
1439
            $arrayWithDraftVersion2[0]->versionInfo->creatorId,
1440
            'creatorId is not properly set on new Version'
1441
        );
1442
1443
        return $arrayWithDraftVersion2[0];
1444
    }
1445
1446
    /**
1447
     * Test for the updateContent() method.
1448
     *
1449
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1450
     *
1451
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1452
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1453
     */
1454
    public function testUpdateContentSetsExpectedFields($content)
1455
    {
1456
        $actual = $this->normalizeFields($content->getFields());
1457
1458
        $expected = [
1459
            new Field(
1460
                [
1461
                    'id' => 0,
1462
                    'value' => true,
1463
                    'languageCode' => self::ENG_GB,
1464
                    'fieldDefIdentifier' => 'description',
1465
                    'fieldTypeIdentifier' => 'ezrichtext',
1466
                ]
1467
            ),
1468
            new Field(
1469
                [
1470
                    'id' => 0,
1471
                    'value' => true,
1472
                    'languageCode' => self::ENG_US,
1473
                    'fieldDefIdentifier' => 'description',
1474
                    'fieldTypeIdentifier' => 'ezrichtext',
1475
                ]
1476
            ),
1477
            new Field(
1478
                [
1479
                    'id' => 0,
1480
                    'value' => true,
1481
                    'languageCode' => self::ENG_GB,
1482
                    'fieldDefIdentifier' => 'name',
1483
                    'fieldTypeIdentifier' => 'ezstring',
1484
                ]
1485
            ),
1486
            new Field(
1487
                [
1488
                    'id' => 0,
1489
                    'value' => true,
1490
                    'languageCode' => self::ENG_US,
1491
                    'fieldDefIdentifier' => 'name',
1492
                    'fieldTypeIdentifier' => 'ezstring',
1493
                ]
1494
            ),
1495
        ];
1496
1497
        $this->assertEquals($expected, $actual);
1498
    }
1499
1500
    /**
1501
     * Test for the updateContent() method.
1502
     *
1503
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1504
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1505
     */
1506
    public function testUpdateContentThrowsBadStateException()
1507
    {
1508
        $content = $this->createContentVersion1();
1509
1510
        // Now create an update struct and modify some fields
1511
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1512
        $contentUpdateStruct->setField('title', 'An awesome² story about ezp.');
1513
        $contentUpdateStruct->setField('title', 'An awesome²³ story about ezp.', self::ENG_GB);
1514
1515
        $contentUpdateStruct->initialLanguageCode = self::ENG_US;
1516
1517
        $this->expectException(BadStateException::class);
1518
1519
        // This call will fail with a "BadStateException", because $publishedContent is not a draft.
1520
        $this->contentService->updateContent(
1521
            $content->getVersionInfo(),
1522
            $contentUpdateStruct
1523
        );
1524
    }
1525
1526
    /**
1527
     * Test for the updateContent() method.
1528
     *
1529
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1530
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1531
     */
1532
    public function testUpdateContentThrowsInvalidArgumentExceptionWhenFieldTypeDoesNotAccept()
1533
    {
1534
        $draft = $this->createContentDraftVersion1();
1535
1536
        // Now create an update struct and modify some fields
1537
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1538
        // The name field does not accept a stdClass object as its input
1539
        $contentUpdateStruct->setField('name', new \stdClass(), self::ENG_US);
1540
1541
        $this->expectException(APIInvalidArgumentException::class);
1542
        // is not accepted
1543
        $this->contentService->updateContent(
1544
            $draft->getVersionInfo(),
1545
            $contentUpdateStruct
1546
        );
1547
    }
1548
1549
    /**
1550
     * Test for the updateContent() method.
1551
     *
1552
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1553
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1554
     */
1555
    public function testUpdateContentWhenMandatoryFieldIsEmpty()
1556
    {
1557
        $draft = $this->createContentDraftVersion1();
1558
1559
        // Now create an update struct and set a mandatory field to null
1560
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1561
        $contentUpdateStruct->setField('name', null);
1562
1563
        // Don't set this, then the above call without languageCode will fail
1564
        $contentUpdateStruct->initialLanguageCode = self::ENG_US;
1565
1566
        $this->expectException(ContentFieldValidationException::class);
1567
1568
        // This call will fail with a "ContentFieldValidationException", because the mandatory "name" field is empty.
1569
        $this->contentService->updateContent(
1570
            $draft->getVersionInfo(),
1571
            $contentUpdateStruct
1572
        );
1573
    }
1574
1575
    /**
1576
     * Test for the updateContent() method.
1577
     *
1578
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1579
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1580
     */
1581
    public function testUpdateContentThrowsContentFieldValidationException()
1582
    {
1583
        $contentTypeService = $this->getRepository()->getContentTypeService();
1584
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1585
1586
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
1587
        $contentCreate->setField('name', 'An awesome Sidelfingen folder');
1588
1589
        $draft = $this->contentService->createContent($contentCreate);
1590
1591
        $contentUpdate = $this->contentService->newContentUpdateStruct();
1592
        // Violates string length constraint
1593
        $contentUpdate->setField('short_name', str_repeat('a', 200), self::ENG_US);
1594
1595
        $this->expectException(ContentFieldValidationException::class);
1596
1597
        // Throws ContentFieldValidationException because the string length validation of the field "short_name" fails
1598
        $this->contentService->updateContent($draft->getVersionInfo(), $contentUpdate);
1599
    }
1600
1601
    /**
1602
     * Test for the updateContent() method.
1603
     *
1604
     * @covers \eZ\Publish\API\Repository\ContentService::updateContent()
1605
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1606
     */
1607
    public function testUpdateContentValidatorIgnoresRequiredFieldsOfNotUpdatedLanguages()
1608
    {
1609
        $contentTypeService = $this->getRepository()->getContentTypeService();
1610
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1611
1612
        // Create multilangual content
1613
        $contentCreate = $this->contentService->newContentCreateStruct($contentType, self::ENG_US);
1614
        $contentCreate->setField('name', 'An awesome Sidelfingen folder', self::ENG_US);
1615
        $contentCreate->setField('name', 'An awesome Sidelfingen folder', self::ENG_GB);
1616
1617
        $contentDraft = $this->contentService->createContent($contentCreate);
1618
1619
        // 2. Update content type definition
1620
        $contentTypeDraft = $contentTypeService->createContentTypeDraft($contentType);
1621
1622
        $fieldDefinition = $contentType->getFieldDefinition('description');
1623
        $fieldDefinitionUpdate = $contentTypeService->newFieldDefinitionUpdateStruct();
1624
        $fieldDefinitionUpdate->identifier = 'description';
1625
        $fieldDefinitionUpdate->isRequired = true;
1626
1627
        $contentTypeService->updateFieldDefinition(
1628
            $contentTypeDraft,
1629
            $fieldDefinition,
1630
            $fieldDefinitionUpdate
1631
        );
1632
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1633
1634
        // 3. Update only eng-US translation
1635
        $description = new DOMDocument();
1636
        $description->loadXML(<<<XML
1637
<?xml version="1.0" encoding="UTF-8"?>
1638
<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">
1639
    <para>Lorem ipsum dolor</para>
1640
</section>
1641
XML
1642
        );
1643
1644
        $contentUpdate = $this->contentService->newContentUpdateStruct();
1645
        $contentUpdate->setField('name', 'An awesome Sidelfingen folder (updated)', self::ENG_US);
1646
        $contentUpdate->setField('description', $description);
1647
1648
        $this->contentService->updateContent($contentDraft->getVersionInfo(), $contentUpdate);
1649
    }
1650
1651
    /**
1652
     * Test for the updateContent() method.
1653
     *
1654
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1655
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1656
     */
1657
    public function testUpdateContentWithNotUpdatingMandatoryField()
1658
    {
1659
        $draft = $this->createContentDraftVersion1();
1660
1661
        // Now create an update struct which does not overwrite mandatory
1662
        // fields
1663
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1664
        $contentUpdateStruct->setField(
1665
            'description',
1666
            '<?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"/>'
1667
        );
1668
1669
        // Don't set this, then the above call without languageCode will fail
1670
        $contentUpdateStruct->initialLanguageCode = self::ENG_US;
1671
1672
        // This will only update the "description" field in the "eng-US" language
1673
        $updatedDraft = $this->contentService->updateContent(
1674
            $draft->getVersionInfo(),
1675
            $contentUpdateStruct
1676
        );
1677
1678
        foreach ($updatedDraft->getFields() as $field) {
1679
            if ($field->languageCode === self::ENG_US && $field->fieldDefIdentifier === 'name' && $field->value !== null) {
1680
                // Found field
1681
                return;
1682
            }
1683
        }
1684
        $this->fail(
1685
            'Field with identifier "name" in language "eng-US" could not be found or has empty value.'
1686
        );
1687
    }
1688
1689
    /**
1690
     * Test for the createContentDraft() method.
1691
     *
1692
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft($contentInfo, $versionInfo)
1693
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1694
     */
1695
    public function testCreateContentDraftWithSecondParameter()
1696
    {
1697
        $contentVersion2 = $this->createContentVersion2();
1698
1699
        // Now we create a new draft from the initial version
1700
        $draftedContentReloaded = $this->contentService->createContentDraft(
1701
            $contentVersion2->contentInfo,
1702
            $contentVersion2->getVersionInfo()
1703
        );
1704
1705
        $this->assertEquals(3, $draftedContentReloaded->getVersionInfo()->versionNo);
1706
    }
1707
1708
    /**
1709
     * Test for the createContentDraft() method with third parameter.
1710
     *
1711
     * @covers \eZ\Publish\Core\Repository\ContentService::createContentDraft
1712
     */
1713
    public function testCreateContentDraftWithThirdParameter()
1714
    {
1715
        $content = $this->contentService->loadContent(4);
1716
        $user = $this->createUserVersion1();
1717
1718
        $draftContent = $this->contentService->createContentDraft(
1719
            $content->contentInfo,
1720
            $content->getVersionInfo(),
1721
            $user
1722
        );
1723
1724
        $this->assertInstanceOf(
1725
            Content::class,
1726
            $draftContent
1727
        );
1728
    }
1729
1730
    /**
1731
     * Test for the publishVersion() method.
1732
     *
1733
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1734
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1735
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1736
     */
1737
    public function testPublishVersionFromContentDraft()
1738
    {
1739
        $contentVersion2 = $this->createContentVersion2();
1740
1741
        $versionInfo = $this->contentService->loadVersionInfo($contentVersion2->contentInfo);
1742
1743
        $this->assertEquals(
1744
            [
1745
                'status' => VersionInfo::STATUS_PUBLISHED,
1746
                'versionNo' => 2,
1747
            ],
1748
            [
1749
                'status' => $versionInfo->status,
1750
                'versionNo' => $versionInfo->versionNo,
1751
            ]
1752
        );
1753
        $this->assertTrue($versionInfo->isPublished());
1754
        $this->assertFalse($versionInfo->isDraft());
1755
        $this->assertFalse($versionInfo->isArchived());
1756
    }
1757
1758
    /**
1759
     * Test for the publishVersion() method.
1760
     *
1761
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1762
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1763
     */
1764
    public function testPublishVersionFromContentDraftArchivesOldVersion()
1765
    {
1766
        $contentVersion2 = $this->createContentVersion2();
1767
1768
        $versionInfo = $this->contentService->loadVersionInfo($contentVersion2->contentInfo, 1);
1769
1770
        $this->assertEquals(
1771
            [
1772
                'status' => VersionInfo::STATUS_ARCHIVED,
1773
                'versionNo' => 1,
1774
            ],
1775
            [
1776
                'status' => $versionInfo->status,
1777
                'versionNo' => $versionInfo->versionNo,
1778
            ]
1779
        );
1780
        $this->assertTrue($versionInfo->isArchived());
1781
        $this->assertFalse($versionInfo->isDraft());
1782
        $this->assertFalse($versionInfo->isPublished());
1783
    }
1784
1785
    /**
1786
     * Test for the publishVersion() method.
1787
     *
1788
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1789
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1790
     */
1791
    public function testPublishVersionFromContentDraftUpdatesContentInfoCurrentVersion()
1792
    {
1793
        $contentVersion2 = $this->createContentVersion2();
1794
1795
        $this->assertEquals(2, $contentVersion2->contentInfo->currentVersionNo);
1796
    }
1797
1798
    /**
1799
     * Test for the publishVersion() method.
1800
     *
1801
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1802
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1803
     */
1804
    public function testPublishVersionFromOldContentDraftArchivesNewerVersionNo()
1805
    {
1806
        $content = $this->createContentVersion1();
1807
1808
        // Create a new draft with versionNo = 2
1809
        $draftedContentVersion2 = $this->contentService->createContentDraft($content->contentInfo);
1810
1811
        // Create another new draft with versionNo = 3
1812
        $draftedContentVersion3 = $this->contentService->createContentDraft($content->contentInfo);
1813
1814
        // Publish draft with versionNo = 3
1815
        $this->contentService->publishVersion($draftedContentVersion3->getVersionInfo());
1816
1817
        // Publish the first draft with versionNo = 2
1818
        // currentVersionNo is now 2, versionNo 3 will be archived
1819
        $publishedDraft = $this->contentService->publishVersion($draftedContentVersion2->getVersionInfo());
1820
1821
        $this->assertEquals(2, $publishedDraft->contentInfo->currentVersionNo);
1822
    }
1823
1824
    /**
1825
     * Test for the publishVersion() method, and that it creates limited archives.
1826
     *
1827
     * @todo Adapt this when per content type archive limited is added on repository Content Type model.
1828
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1829
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1830
     */
1831
    public function testPublishVersionNotCreatingUnlimitedArchives()
1832
    {
1833
        $content = $this->createContentVersion1();
1834
1835
        // load first to make sure list gets updated also (cache)
1836
        $versionInfoList = $this->contentService->loadVersions($content->contentInfo);
1837
        $this->assertEquals(1, count($versionInfoList));
1838
        $this->assertEquals(1, $versionInfoList[0]->versionNo);
1839
1840
        // Create a new draft with versionNo = 2
1841
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1842
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1843
1844
        // Create a new draft with versionNo = 3
1845
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1846
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1847
1848
        // Create a new draft with versionNo = 4
1849
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1850
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1851
1852
        // Create a new draft with versionNo = 5
1853
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1854
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1855
1856
        // Create a new draft with versionNo = 6
1857
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1858
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1859
1860
        // Create a new draft with versionNo = 7
1861
        $draftedContentVersion = $this->contentService->createContentDraft($content->contentInfo);
1862
        $this->contentService->publishVersion($draftedContentVersion->getVersionInfo());
1863
1864
        $versionInfoList = $this->contentService->loadVersions($content->contentInfo);
1865
1866
        $this->assertEquals(6, count($versionInfoList));
1867
        $this->assertEquals(2, $versionInfoList[0]->versionNo);
1868
        $this->assertEquals(7, $versionInfoList[5]->versionNo);
1869
1870
        $this->assertEquals(
1871
            [
1872
                VersionInfo::STATUS_ARCHIVED,
1873
                VersionInfo::STATUS_ARCHIVED,
1874
                VersionInfo::STATUS_ARCHIVED,
1875
                VersionInfo::STATUS_ARCHIVED,
1876
                VersionInfo::STATUS_ARCHIVED,
1877
                VersionInfo::STATUS_PUBLISHED,
1878
            ],
1879
            [
1880
                $versionInfoList[0]->status,
1881
                $versionInfoList[1]->status,
1882
                $versionInfoList[2]->status,
1883
                $versionInfoList[3]->status,
1884
                $versionInfoList[4]->status,
1885
                $versionInfoList[5]->status,
1886
            ]
1887
        );
1888
    }
1889
1890
    /**
1891
     * Test for the newContentMetadataUpdateStruct() method.
1892
     *
1893
     * @covers \eZ\Publish\API\Repository\ContentService::newContentMetadataUpdateStruct
1894
     * @group user
1895
     */
1896
    public function testNewContentMetadataUpdateStruct()
1897
    {
1898
        // Creates a new metadata update struct
1899
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
1900
1901
        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...
1902
            $this->assertNull($propertyValue, "Property '{$propertyName}' initial value should be null'");
1903
        }
1904
1905
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
1906
        $metadataUpdate->mainLanguageCode = self::ENG_GB;
1907
        $metadataUpdate->alwaysAvailable = false;
1908
1909
        $this->assertInstanceOf(
1910
            ContentMetadataUpdateStruct::class,
1911
            $metadataUpdate
1912
        );
1913
    }
1914
1915
    /**
1916
     * Test for the updateContentMetadata() method.
1917
     *
1918
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1919
     *
1920
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1921
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1922
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentMetadataUpdateStruct
1923
     * @group user
1924
     */
1925
    public function testUpdateContentMetadata()
1926
    {
1927
        $content = $this->createContentVersion1();
1928
1929
        // Creates a metadata update struct
1930
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
1931
1932
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
1933
        $metadataUpdate->mainLanguageCode = self::ENG_GB;
1934
        $metadataUpdate->alwaysAvailable = false;
1935
        $metadataUpdate->publishedDate = $this->createDateTime(441759600); // 1984/01/01
1936
        $metadataUpdate->modificationDate = $this->createDateTime(441759600); // 1984/01/01
1937
1938
        // Update the metadata of the published content object
1939
        $content = $this->contentService->updateContentMetadata(
1940
            $content->contentInfo,
1941
            $metadataUpdate
1942
        );
1943
1944
        $this->assertInstanceOf(
1945
            Content::class,
1946
            $content
1947
        );
1948
1949
        return $content;
1950
    }
1951
1952
    /**
1953
     * Test for the updateContentMetadata() method.
1954
     *
1955
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1956
     *
1957
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1958
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1959
     */
1960
    public function testUpdateContentMetadataSetsExpectedProperties($content)
1961
    {
1962
        $contentInfo = $content->contentInfo;
1963
1964
        $this->assertEquals(
1965
            [
1966
                'remoteId' => 'aaaabbbbccccddddeeeeffff11112222',
1967
                'sectionId' => $this->generateId('section', 1),
1968
                'alwaysAvailable' => false,
1969
                'currentVersionNo' => 1,
1970
                'mainLanguageCode' => self::ENG_GB,
1971
                'modificationDate' => $this->createDateTime(441759600),
1972
                '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...
1973
                'published' => true,
1974
                'publishedDate' => $this->createDateTime(441759600),
1975
            ],
1976
            [
1977
                'remoteId' => $contentInfo->remoteId,
1978
                'sectionId' => $contentInfo->sectionId,
1979
                'alwaysAvailable' => $contentInfo->alwaysAvailable,
1980
                'currentVersionNo' => $contentInfo->currentVersionNo,
1981
                'mainLanguageCode' => $contentInfo->mainLanguageCode,
1982
                'modificationDate' => $contentInfo->modificationDate,
1983
                'ownerId' => $contentInfo->ownerId,
1984
                'published' => $contentInfo->published,
1985
                'publishedDate' => $contentInfo->publishedDate,
1986
            ]
1987
        );
1988
    }
1989
1990
    /**
1991
     * Test for the updateContentMetadata() method.
1992
     *
1993
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1994
     *
1995
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
1996
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1997
     */
1998
    public function testUpdateContentMetadataNotUpdatesContentVersion($content)
1999
    {
2000
        $this->assertEquals(1, $content->getVersionInfo()->versionNo);
2001
    }
2002
2003
    /**
2004
     * Test for the updateContentMetadata() method.
2005
     *
2006
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2007
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
2008
     */
2009
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnDuplicateRemoteId()
2010
    {
2011
        $content = $this->createContentVersion1();
2012
2013
        // Creates a metadata update struct
2014
        $metadataUpdate = $this->contentService->newContentMetadataUpdateStruct();
2015
        $metadataUpdate->remoteId = self::MEDIA_REMOTE_ID;
2016
2017
        $this->expectException(APIInvalidArgumentException::class);
2018
        // specified remoteId is already used by the "Media" page.
2019
        $this->contentService->updateContentMetadata(
2020
            $content->contentInfo,
2021
            $metadataUpdate
2022
        );
2023
    }
2024
2025
    /**
2026
     * Test for the updateContentMetadata() method.
2027
     *
2028
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContentMetadata
2029
     */
2030
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnNoMetadataPropertiesSet()
2031
    {
2032
        $contentInfo = $this->contentService->loadContentInfo(4);
2033
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
2034
2035
        $this->expectException(APIInvalidArgumentException::class);
2036
        $this->contentService->updateContentMetadata($contentInfo, $contentMetadataUpdateStruct);
2037
    }
2038
2039
    /**
2040
     * Test for the deleteContent() method.
2041
     *
2042
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2043
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2044
     */
2045
    public function testDeleteContent()
2046
    {
2047
        $contentVersion2 = $this->createContentVersion2();
2048
2049
        // Load the locations for this content object
2050
        $locations = $this->locationService->loadLocations($contentVersion2->contentInfo);
2051
2052
        // This will delete the content, all versions and the associated locations
2053
        $this->contentService->deleteContent($contentVersion2->contentInfo);
2054
2055
        $this->expectException(NotFoundException::class);
2056
2057
        foreach ($locations as $location) {
2058
            $this->locationService->loadLocation($location->id);
2059
        }
2060
    }
2061
2062
    /**
2063
     * Test for the deleteContent() method.
2064
     *
2065
     * Test for issue EZP-21057:
2066
     * "contentService: Unable to delete a content with an empty file attribute"
2067
     *
2068
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2069
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2070
     */
2071
    public function testDeleteContentWithEmptyBinaryField()
2072
    {
2073
        $contentVersion = $this->createContentVersion1EmptyBinaryField();
2074
2075
        // Load the locations for this content object
2076
        $locations = $this->locationService->loadLocations($contentVersion->contentInfo);
2077
2078
        // This will delete the content, all versions and the associated locations
2079
        $this->contentService->deleteContent($contentVersion->contentInfo);
2080
2081
        $this->expectException(NotFoundException::class);
2082
2083
        foreach ($locations as $location) {
2084
            $this->locationService->loadLocation($location->id);
2085
        }
2086
    }
2087
2088
    public function testCountContentDraftsReturnsZeroByDefault(): void
2089
    {
2090
        $this->assertSame(0, $this->contentService->countContentDrafts());
2091
    }
2092
2093
    public function testCountContentDrafts(): void
2094
    {
2095
        // Create 5 drafts
2096
        $this->createContentDrafts(5);
2097
2098
        $this->assertSame(5, $this->contentService->countContentDrafts());
2099
    }
2100
2101
    public function testCountContentDraftsForUsers(): void
2102
    {
2103
        $newUser = $this->createUserWithPolicies(
2104
            'new_user',
2105
            [
2106
                ['module' => 'content', 'function' => 'create'],
2107
                ['module' => 'content', 'function' => 'read'],
2108
                ['module' => 'content', 'function' => 'publish'],
2109
                ['module' => 'content', 'function' => 'edit'],
2110
            ]
2111
        );
2112
2113
        $previousUser = $this->permissionResolver->getCurrentUserReference();
2114
2115
        // Set new editor as user
2116
        $this->permissionResolver->setCurrentUserReference($newUser);
2117
2118
        // Create a content draft as newUser
2119
        $publishedContent = $this->createContentVersion1();
2120
        $this->contentService->createContentDraft($publishedContent->contentInfo);
2121
2122
        // Reset to previous current user
2123
        $this->permissionResolver->setCurrentUserReference($previousUser);
2124
2125
        // Now $contentDrafts for the previous current user and the new user
2126
        $newUserDrafts = $this->contentService->countContentDrafts($newUser);
2127
        $previousUserDrafts = $this->contentService->countContentDrafts();
2128
2129
        $this->assertSame(1, $newUserDrafts);
2130
        $this->assertSame(0, $previousUserDrafts);
2131
    }
2132
2133
    /**
2134
     * Test for the loadContentDrafts() method.
2135
     *
2136
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2137
     */
2138
    public function testLoadContentDraftsReturnsEmptyArrayByDefault()
2139
    {
2140
        $contentDrafts = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2141
2142
        $this->assertSame([], $contentDrafts);
2143
    }
2144
2145
    /**
2146
     * Test for the loadContentDrafts() method.
2147
     *
2148
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2149
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
2150
     */
2151
    public function testLoadContentDrafts()
2152
    {
2153
        // "Media" content object
2154
        $mediaContentInfo = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
2155
2156
        // "eZ Publish Demo Design ..." content object
2157
        $demoDesignContentInfo = $this->contentService->loadContentInfoByRemoteId(self::DEMO_DESIGN_REMOTE_ID);
2158
2159
        // Create some drafts
2160
        $this->contentService->createContentDraft($mediaContentInfo);
2161
        $this->contentService->createContentDraft($demoDesignContentInfo);
2162
2163
        // Now $contentDrafts should contain two drafted versions
2164
        $draftedVersions = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2165
2166
        $actual = [
2167
            $draftedVersions[0]->status,
2168
            $draftedVersions[0]->getContentInfo()->remoteId,
2169
            $draftedVersions[1]->status,
2170
            $draftedVersions[1]->getContentInfo()->remoteId,
2171
        ];
2172
        sort($actual, SORT_STRING);
2173
2174
        $this->assertEquals(
2175
            [
2176
                VersionInfo::STATUS_DRAFT,
2177
                VersionInfo::STATUS_DRAFT,
2178
                self::DEMO_DESIGN_REMOTE_ID,
2179
                self::MEDIA_REMOTE_ID,
2180
            ],
2181
            $actual
2182
        );
2183
    }
2184
2185
    /**
2186
     * Test for the loadContentDrafts() method.
2187
     *
2188
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts($user)
2189
     */
2190
    public function testLoadContentDraftsWithFirstParameter()
2191
    {
2192
        $user = $this->createUserVersion1();
2193
2194
        // Get current user
2195
        $oldCurrentUser = $this->permissionResolver->getCurrentUserReference();
2196
2197
        // Set new editor as user
2198
        $this->permissionResolver->setCurrentUserReference($user);
2199
2200
        // "Media" content object
2201
        $mediaContentInfo = $this->contentService->loadContentInfoByRemoteId(self::MEDIA_REMOTE_ID);
2202
2203
        // Create a content draft
2204
        $this->contentService->createContentDraft($mediaContentInfo);
2205
2206
        // Reset to previous current user
2207
        $this->permissionResolver->setCurrentUserReference($oldCurrentUser);
2208
2209
        // Now $contentDrafts for the previous current user and the new user
2210
        $newCurrentUserDrafts = $this->contentService->loadContentDrafts($user);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
4656
4657
        $this->assertSame([], $drafts);
4658
    }
4659
4660
    /**
4661
     * Test for the deleteVersion() method.
4662
     *
4663
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4664
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4665
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4666
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4667
     */
4668
    public function testDeleteVersionInTransactionWithCommit()
4669
    {
4670
        $repository = $this->getRepository();
4671
4672
        $contentId = $this->generateId('object', self::ADMINISTRATORS_USER_GROUP_ID);
4673
4674
        // Start a new transaction
4675
        $repository->beginTransaction();
4676
4677
        try {
4678
            // Create a new draft
4679
            $draft = $this->contentService->createContentDraft(
4680
                $this->contentService->loadContentInfo($contentId)
4681
            );
4682
4683
            $this->contentService->deleteVersion($draft->getVersionInfo());
4684
4685
            // Commit all changes.
4686
            $repository->commit();
4687
        } catch (Exception $e) {
4688
            // Cleanup hanging transaction on error
4689
            $repository->rollback();
4690
            throw $e;
4691
        }
4692
4693
        // This array will contain no element
4694
        $drafts = $this->contentService->loadContentDrafts();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...ce::loadContentDrafts() has been deprecated with message: Please use {@see loadContentDraftList()} instead to avoid risking loading too much data.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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