Completed
Push — ezp_30797 ( b39740...a92ef0 )
by
unknown
17:49
created

ContentTest   F

Complexity

Total Complexity 158

Size/Duplication

Total Lines 6053
Duplicated Lines 8.01 %

Coupling/Cohesion

Components 1
Dependencies 36

Importance

Changes 0
Metric Value
dl 485
loc 6053
rs 0.8
c 0
b 0
f 0
wmc 158
lcom 1
cbo 36

102 Methods

Rating   Name   Duplication   Size   Complexity  
B testConstructor() 0 63 1
A testLoadVersionInfoById() 0 42 1
A testLoadVersionInfoByIdAndVersionNumber() 0 41 1
A testLoadVersionInfoByIdThrowsNotFoundException() 0 25 1
A testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion() 0 37 1
A testLoadVersionInfoByIdPublishedVersion() 39 39 1
A testLoadVersionInfoByIdNonPublishedVersion() 39 39 1
A testLoadVersionInfo() 0 23 1
A testLoadContent() 0 29 1
A testLoadContentNonPublished() 33 33 1
A testLoadContentUnauthorized() 0 20 1
A testLoadContentNotPublishedStatusUnauthorized() 33 33 1
B testInternalLoadContent() 0 42 5
A internalLoadContentProvider() 0 20 1
A testInternalLoadContentNotFound() 0 20 1
A testLoadContentByContentInfo() 0 26 1
A testLoadContentByVersionInfo() 0 30 1
A testDeleteContentThrowsUnauthorizedException() 0 24 1
B testDeleteContent() 0 55 2
A testDeleteContentWithRollback() 0 37 1
A testDeleteVersionThrowsBadStateExceptionLastVersion() 0 49 1
A testCreateContentThrowsInvalidArgumentExceptionMainLanguageCodeNotSet() 0 5 1
A testCreateContentThrowsInvalidArgumentExceptionContentTypeNotSet() 0 8 1
A testCreateContentThrowsUnauthorizedException() 0 52 1
B testCreateContentThrowsInvalidArgumentExceptionDuplicateRemoteId() 0 59 1
A mapStructFieldsForCreate() 0 20 4
B determineValuesForCreate() 12 37 6
A determineLanguageCodesForCreate() 0 16 4
B assertForTestCreateContentNonRedundantFieldSet() 0 221 3
A providerForTestCreateContentNonRedundantFieldSet1() 0 44 1
A testCreateContentNonRedundantFieldSet1() 22 22 1
B providerForTestCreateContentNonRedundantFieldSet2() 0 66 1
A testCreateContentNonRedundantFieldSet2() 0 32 1
B providerForTestCreateContentNonRedundantFieldSetComplex() 0 120 1
A fixturesForTestCreateContentNonRedundantFieldSetComplex() 0 45 1
A testCreateContentNonRedundantFieldSetComplex() 0 11 1
A providerForTestCreateContentWithInvalidLanguage() 29 29 1
B testCreateContentWithInvalidLanguage() 7 82 2
A assertForCreateContentContentValidationException() 0 52 1
A providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition() 17 17 1
A testCreateContentThrowsContentValidationExceptionFieldDefinition() 0 8 1
A providerForTestCreateContentThrowsContentValidationExceptionTranslation() 17 17 1
A testCreateContentThrowsContentValidationExceptionTranslation() 21 21 1
B assertForTestCreateContentRequiredField() 0 112 1
A providerForTestCreateContentThrowsContentValidationExceptionRequiredField() 19 19 1
A testCreateContentRequiredField() 0 37 2
B assertForTestCreateContentThrowsContentFieldValidationException() 0 146 4
A providerForTestCreateContentThrowsContentFieldValidationException() 0 4 1
A testCreateContentThrowsContentFieldValidationException() 0 19 2
B testCreateContentWithLocations() 0 127 1
B testCreateContentWithLocationsDuplicateUnderParent() 0 119 1
B testCreateContentObjectStates() 0 96 1
A testCreateContentWithRollback() 0 41 1
A providerForTestUpdateContentThrowsBadStateException() 0 7 1
A testUpdateContentThrowsBadStateException() 0 30 1
A testUpdateContentThrowsUnauthorizedException() 0 40 1
A determineLanguageCodesForUpdate() 0 17 5
B mapStructFieldsForUpdate() 0 26 6
B determineValuesForUpdate() 12 46 7
A stubValues() 0 10 3
B assertForTestUpdateContentNonRedundantFieldSet() 0 239 2
A providerForTestUpdateContentNonRedundantFieldSet1() 0 52 1
A testUpdateContentNonRedundantFieldSet1() 34 34 1
B providerForTestUpdateContentNonRedundantFieldSet2() 0 167 1
A testUpdateContentNonRedundantFieldSet2() 34 34 1
B providerForTestUpdateContentNonRedundantFieldSet3() 0 216 1
A testUpdateContentNonRedundantFieldSet3() 0 52 1
B providerForTestUpdateContentNonRedundantFieldSet4() 0 241 1
A testUpdateContentNonRedundantFieldSet4() 0 52 1
B providerForTestUpdateContentNonRedundantFieldSetComplex() 0 228 1
B fixturesForTestUpdateContentNonRedundantFieldSetComplex() 0 82 1
A testUpdateContentNonRedundantFieldSetComplex() 0 12 1
A providerForTestUpdateContentWithInvalidLanguage() 29 29 1
B testUpdateContentWithInvalidLanguage() 7 71 2
B assertForUpdateContentContentValidationException() 7 85 2
A providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition() 17 17 1
A testUpdateContentThrowsContentValidationExceptionFieldDefinition() 0 8 1
A providerForTestUpdateContentThrowsContentValidationExceptionTranslation() 17 17 1
A testUpdateContentThrowsContentValidationExceptionTranslation() 21 21 1
B assertForTestUpdateContentRequiredField() 0 122 1
A providerForTestUpdateContentRequiredField() 19 19 1
A testUpdateContentRequiredField() 0 47 2
B assertForTestUpdateContentThrowsContentFieldValidationException() 0 133 1
B providerForTestUpdateContentThrowsContentFieldValidationException() 0 121 2
A testUpdateContentThrowsContentFieldValidationException() 0 18 2
A testUpdateContentTransactionRollback() 0 54 1
A testCopyContentThrowsUnauthorizedException() 0 40 1
B testCopyContent() 0 117 1
B testCopyContentWithVersionInfo() 0 115 1
B testCopyContentWithRollback() 0 59 1
A mockBuildContentDomainObject() 0 30 1
A mockGetDefaultObjectStates() 0 39 1
A mockSetDefaultObjectStates() 0 19 2
B mockPublishVersion() 0 75 3
A mockPublishUrlAliasesForContent() 0 46 1
A getDomainMapperMock() 0 8 2
A getRelationProcessorMock() 0 8 2
A getNameSchemaServiceMock() 0 8 2
A getContentTypeServiceMock() 0 8 2
A getLocationServiceMock() 0 8 2
A getPartlyMockedContentService() 0 21 2
A getRepositoryMock() 0 10 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

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

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

1
<?php
2
3
/**
4
 * File contains: eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest 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\Core\Repository\Tests\Service\Mock;
10
11
use eZ\Publish\API\Repository\Repository;
12
use eZ\Publish\API\Repository\Values\Content\Language;
13
use eZ\Publish\API\Repository\Values\Content\Content as APIContent;
14
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
15
use eZ\Publish\API\Repository\ContentTypeService as APIContentTypeService;
16
use eZ\Publish\API\Repository\LocationService as APILocationService;
17
use eZ\Publish\API\Repository\Exceptions\NotFoundException as APINotFoundException;
18
use eZ\Publish\API\Repository\Values\Content\ContentInfo as APIContentInfo;
19
use eZ\Publish\API\Repository\Values\ContentType\ContentType as APIContentType;
20
use eZ\Publish\API\Repository\Values\Content\Location as APILocation;
21
use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition as APIFieldDefinition;
22
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct as APIContentCreateStruct;
23
use eZ\Publish\Core\Base\Exceptions\ContentFieldValidationException;
24
use eZ\Publish\Core\Base\Exceptions\ContentValidationException;
25
use eZ\Publish\Core\Repository\Tests\Service\Mock\Base as BaseServiceMockTest;
26
use eZ\Publish\Core\Repository\ContentService;
27
use eZ\Publish\Core\Repository\Values\Content\Location;
28
use eZ\Publish\Core\Repository\Values\Content\Content;
29
use eZ\Publish\Core\Repository\Values\Content\ContentCreateStruct;
30
use eZ\Publish\Core\Repository\Values\Content\ContentUpdateStruct;
31
use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
32
use eZ\Publish\Core\Repository\Helper\DomainMapper;
33
use eZ\Publish\Core\Repository\Helper\RelationProcessor;
34
use eZ\Publish\Core\Repository\Helper\NameSchemaService;
35
use eZ\Publish\API\Repository\Values\Content\Field;
36
use eZ\Publish\Core\FieldType\Value;
37
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
38
use eZ\Publish\API\Repository\Values\Content\VersionInfo as APIVersionInfo;
39
use eZ\Publish\Core\Repository\Values\ContentType\ContentType;
40
use eZ\Publish\Core\Repository\Values\ContentType\FieldDefinition;
41
use eZ\Publish\SPI\Persistence\Content\Location as SPILocation;
42
use eZ\Publish\SPI\FieldType\FieldType as SPIFieldType;
43
use eZ\Publish\SPI\Persistence\Content as SPIContent;
44
use eZ\Publish\SPI\Persistence\Content\UpdateStruct as SPIContentUpdateStruct;
45
use eZ\Publish\SPI\Persistence\Content\CreateStruct as SPIContentCreateStruct;
46
use eZ\Publish\SPI\Persistence\Content\Field as SPIField;
47
use eZ\Publish\SPI\Persistence\Content\ObjectState\Group as SPIObjectStateGroup;
48
use eZ\Publish\SPI\Persistence\Content\ObjectState as SPIObjectState;
49
use eZ\Publish\SPI\Persistence\Content\VersionInfo as SPIVersionInfo;
50
use eZ\Publish\SPI\Persistence\Content\ContentInfo as SPIContentInfo;
51
use eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct as SPIMetadataUpdateStruct;
52
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
53
use eZ\Publish\Core\Repository\Values\User\UserReference;
54
use Exception;
55
56
/**
57
 * Mock test case for Content service.
58
 */
59
class ContentTest extends BaseServiceMockTest
60
{
61
    /**
62
     * Represents empty Field Value.
63
     */
64
    const EMPTY_FIELD_VALUE = 'empty';
65
66
    /**
67
     * Test for the __construct() method.
68
     *
69
     * @covers \eZ\Publish\Core\Repository\ContentService::__construct
70
     */
71
    public function testConstructor()
72
    {
73
        $repositoryMock = $this->getRepositoryMock();
74
        /** @var \eZ\Publish\SPI\Persistence\Handler $persistenceHandlerMock */
75
        $persistenceHandlerMock = $this->getPersistenceMockHandler('Handler');
76
        $domainMapperMock = $this->getDomainMapperMock();
77
        $relationProcessorMock = $this->getRelationProcessorMock();
78
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
79
        $fieldTypeRegistryMock = $this->getFieldTypeRegistryMock();
80
        $settings = ['default_version_archive_limit' => 10];
81
82
        $service = new ContentService(
83
            $repositoryMock,
0 ignored issues
show
Bug introduced by
It seems like $repositoryMock defined by $this->getRepositoryMock() on line 73 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\API\Repository\Repository>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
84
            $persistenceHandlerMock,
85
            $domainMapperMock,
0 ignored issues
show
Bug introduced by
It seems like $domainMapperMock defined by $this->getDomainMapperMock() on line 76 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\Core\R...ry\Helper\DomainMapper>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
86
            $relationProcessorMock,
0 ignored issues
show
Bug introduced by
It seems like $relationProcessorMock defined by $this->getRelationProcessorMock() on line 77 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\Core\R...lper\RelationProcessor>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
87
            $nameSchemaServiceMock,
0 ignored issues
show
Bug introduced by
It seems like $nameSchemaServiceMock defined by $this->getNameSchemaServiceMock() on line 78 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\Core\R...lper\NameSchemaService>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
88
            $fieldTypeRegistryMock,
0 ignored issues
show
Bug introduced by
It seems like $fieldTypeRegistryMock defined by $this->getFieldTypeRegistryMock() on line 79 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\Core\R...lper\FieldTypeRegistry>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
89
            $settings
90
        );
91
92
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
93
            $repositoryMock,
94
            'repository',
95
            $service
96
        );
97
98
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
99
            $persistenceHandlerMock,
100
            'persistenceHandler',
101
            $service
102
        );
103
104
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
105
            $domainMapperMock,
106
            'domainMapper',
107
            $service
108
        );
109
110
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
111
            $relationProcessorMock,
112
            'relationProcessor',
113
            $service
114
        );
115
116
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
117
            $nameSchemaServiceMock,
118
            'nameSchemaService',
119
            $service
120
        );
121
122
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
123
            $fieldTypeRegistryMock,
124
            'fieldTypeRegistry',
125
            $service
126
        );
127
128
        $this->assertAttributeSame(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertAttributeSame() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3338

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...
129
            $settings,
130
            'settings',
131
            $service
132
        );
133
    }
134
135
    /**
136
     * Test for the loadVersionInfo() method, of published version.
137
     *
138
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
139
     */
140
    public function testLoadVersionInfoById()
141
    {
142
        $repository = $this->getRepositoryMock();
143
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
144
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
145
        $contentHandler = $this->getPersistenceMock()->contentHandler();
146
        $domainMapperMock = $this->getDomainMapperMock();
147
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
148
149
        $versionInfoMock->expects($this->once())
150
            ->method('isPublished')
151
            ->willReturn(true);
152
153
        $contentServiceMock->expects($this->never())
154
            ->method('loadContentInfo');
155
156
        $contentHandler->expects($this->once())
157
            ->method('loadVersionInfo')
158
            ->with(
159
                $this->equalTo(42),
160
                $this->equalTo(null)
161
            )->will(
162
                $this->returnValue(new SPIVersionInfo())
163
            );
164
165
        $domainMapperMock->expects($this->once())
166
            ->method('buildVersionInfoDomainObject')
167
            ->with(new SPIVersionInfo())
168
            ->will($this->returnValue($versionInfoMock));
169
170
        $repository->expects($this->once())
171
            ->method('canUser')
172
            ->with(
173
                $this->equalTo('content'),
174
                $this->equalTo('read'),
175
                $this->equalTo($versionInfoMock)
176
            )->will($this->returnValue(true));
177
178
        $result = $contentServiceMock->loadVersionInfoById(42);
179
180
        $this->assertEquals($versionInfoMock, $result);
181
    }
182
183
    /**
184
     * Test for the loadVersionInfo() method, of a draft.
185
     *
186
     * @depends testLoadVersionInfoById
187
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
188
     */
189
    public function testLoadVersionInfoByIdAndVersionNumber()
190
    {
191
        $repository = $this->getRepositoryMock();
192
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
193
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
194
        $contentHandler = $this->getPersistenceMock()->contentHandler();
195
        $domainMapperMock = $this->getDomainMapperMock();
196
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
197
198
        $versionInfoMock->expects($this->any())
199
            ->method('__get')
200
            ->with('status')
201
            ->willReturn(APIVersionInfo::STATUS_DRAFT);
202
203
        $contentServiceMock->expects($this->never())
204
            ->method('loadContentInfo');
205
206
        $contentHandler->expects($this->once())
207
            ->method('loadVersionInfo')
208
            ->with(
209
                $this->equalTo(42),
210
                $this->equalTo(2)
211
            )->willReturn(new SPIVersionInfo());
212
213
        $domainMapperMock->expects($this->once())
214
            ->method('buildVersionInfoDomainObject')
215
            ->with(new SPIVersionInfo())
216
            ->willReturn($versionInfoMock);
217
218
        $repository->expects($this->once())
219
            ->method('canUser')
220
            ->with(
221
                $this->equalTo('content'),
222
                $this->equalTo('versionread'),
223
                $this->equalTo($versionInfoMock)
224
            )->willReturn(true);
225
226
        $result = $contentServiceMock->loadVersionInfoById(42, 2);
227
228
        $this->assertEquals($versionInfoMock, $result);
229
    }
230
231
    /**
232
     * Test for the loadVersionInfo() method.
233
     *
234
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
235
     * @expectedException \eZ\Publish\Core\Base\Exceptions\NotFoundException
236
     */
237
    public function testLoadVersionInfoByIdThrowsNotFoundException()
238
    {
239
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
240
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
241
        $contentHandler = $this->getPersistenceMock()->contentHandler();
242
243
        $contentHandler->expects($this->once())
244
            ->method('loadVersionInfo')
245
            ->with(
246
                $this->equalTo(42),
247
                $this->equalTo(24)
248
            )->will(
249
                $this->throwException(
250
                    new NotFoundException(
251
                        'Content',
252
                        [
253
                            'contentId' => 42,
254
                            'versionNo' => 24,
255
                        ]
256
                    )
257
                )
258
            );
259
260
        $contentServiceMock->loadVersionInfoById(42, 24);
261
    }
262
263
    /**
264
     * Test for the loadVersionInfo() method.
265
     *
266
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
267
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
268
     */
269
    public function testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion()
270
    {
271
        $repository = $this->getRepositoryMock();
272
        $contentServiceMock = $this->getPartlyMockedContentService();
273
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
274
        $contentHandler = $this->getPersistenceMock()->contentHandler();
275
        $domainMapperMock = $this->getDomainMapperMock();
276
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
277
278
        $versionInfoMock->expects($this->any())
279
            ->method('isPublished')
280
            ->willReturn(false);
281
282
        $contentHandler->expects($this->once())
283
            ->method('loadVersionInfo')
284
            ->with(
285
                $this->equalTo(42),
286
                $this->equalTo(24)
287
            )->will(
288
                $this->returnValue(new SPIVersionInfo())
289
            );
290
291
        $domainMapperMock->expects($this->once())
292
            ->method('buildVersionInfoDomainObject')
293
            ->with(new SPIVersionInfo())
294
            ->will($this->returnValue($versionInfoMock));
295
296
        $repository->expects($this->once())
297
            ->method('canUser')
298
            ->with(
299
                $this->equalTo('content'),
300
                $this->equalTo('versionread'),
301
                $this->equalTo($versionInfoMock)
302
            )->will($this->returnValue(false));
303
304
        $contentServiceMock->loadVersionInfoById(42, 24);
305
    }
306
307
    /**
308
     * Test for the loadVersionInfo() method.
309
     *
310
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
311
     */
312 View Code Duplication
    public function testLoadVersionInfoByIdPublishedVersion()
313
    {
314
        $repository = $this->getRepositoryMock();
315
        $contentServiceMock = $this->getPartlyMockedContentService();
316
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
317
        $contentHandler = $this->getPersistenceMock()->contentHandler();
318
        $domainMapperMock = $this->getDomainMapperMock();
319
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
320
321
        $versionInfoMock->expects($this->once())
322
            ->method('isPublished')
323
            ->willReturn(true);
324
325
        $contentHandler->expects($this->once())
326
            ->method('loadVersionInfo')
327
            ->with(
328
                $this->equalTo(42),
329
                $this->equalTo(24)
330
            )->will(
331
                $this->returnValue(new SPIVersionInfo())
332
            );
333
334
        $domainMapperMock->expects($this->once())
335
            ->method('buildVersionInfoDomainObject')
336
            ->with(new SPIVersionInfo())
337
            ->will($this->returnValue($versionInfoMock));
338
339
        $repository->expects($this->once())
340
            ->method('canUser')
341
            ->with(
342
                $this->equalTo('content'),
343
                $this->equalTo('read'),
344
                $this->equalTo($versionInfoMock)
345
            )->will($this->returnValue(true));
346
347
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
348
349
        $this->assertEquals($versionInfoMock, $result);
350
    }
351
352
    /**
353
     * Test for the loadVersionInfo() method.
354
     *
355
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
356
     */
357 View Code Duplication
    public function testLoadVersionInfoByIdNonPublishedVersion()
358
    {
359
        $repository = $this->getRepositoryMock();
360
        $contentServiceMock = $this->getPartlyMockedContentService();
361
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
362
        $contentHandler = $this->getPersistenceMock()->contentHandler();
363
        $domainMapperMock = $this->getDomainMapperMock();
364
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
365
366
        $versionInfoMock->expects($this->once())
367
            ->method('isPublished')
368
            ->willReturn(false);
369
370
        $contentHandler->expects($this->once())
371
            ->method('loadVersionInfo')
372
            ->with(
373
                $this->equalTo(42),
374
                $this->equalTo(24)
375
            )->will(
376
                $this->returnValue(new SPIVersionInfo())
377
            );
378
379
        $domainMapperMock->expects($this->once())
380
            ->method('buildVersionInfoDomainObject')
381
            ->with(new SPIVersionInfo())
382
            ->will($this->returnValue($versionInfoMock));
383
384
        $repository->expects($this->once())
385
            ->method('canUser')
386
            ->with(
387
                $this->equalTo('content'),
388
                $this->equalTo('versionread'),
389
                $this->equalTo($versionInfoMock)
390
            )->will($this->returnValue(true));
391
392
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
393
394
        $this->assertEquals($versionInfoMock, $result);
395
    }
396
397
    /**
398
     * Test for the loadVersionInfo() method.
399
     *
400
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfo
401
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoById
402
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsNotFoundException
403
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion
404
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdPublishedVersion
405
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdNonPublishedVersion
406
     */
407
    public function testLoadVersionInfo()
408
    {
409
        $contentServiceMock = $this->getPartlyMockedContentService(
410
            ['loadVersionInfoById']
411
        );
412
        $contentServiceMock->expects(
413
            $this->once()
414
        )->method(
415
            'loadVersionInfoById'
416
        )->with(
417
            $this->equalTo(42),
418
            $this->equalTo(7)
419
        )->will(
420
            $this->returnValue('result')
421
        );
422
423
        $result = $contentServiceMock->loadVersionInfo(
424
            new ContentInfo(['id' => 42]),
425
            7
426
        );
427
428
        $this->assertEquals('result', $result);
429
    }
430
431
    public function testLoadContent()
432
    {
433
        $repository = $this->getRepositoryMock();
434
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
435
        $content = $this->createMock(APIContent::class);
436
        $versionInfo = $this->createMock(APIVersionInfo::class);
437
        $content
438
            ->expects($this->once())
439
            ->method('getVersionInfo')
440
            ->will($this->returnValue($versionInfo));
441
        $versionInfo
442
            ->expects($this->once())
443
            ->method('isPublished')
444
            ->willReturn(true);
445
        $contentId = 123;
446
        $contentService
447
            ->expects($this->once())
448
            ->method('internalLoadContent')
449
            ->with($contentId)
450
            ->will($this->returnValue($content));
451
452
        $repository
453
            ->expects($this->once())
454
            ->method('canUser')
455
            ->with('content', 'read', $content)
456
            ->will($this->returnValue(true));
457
458
        $this->assertSame($content, $contentService->loadContent($contentId));
459
    }
460
461 View Code Duplication
    public function testLoadContentNonPublished()
462
    {
463
        $repository = $this->getRepositoryMock();
464
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
465
        $content = $this->createMock(APIContent::class);
466
        $versionInfo = $this
467
            ->getMockBuilder(APIVersionInfo::class)
468
            ->getMockForAbstractClass();
469
        $content
470
            ->expects($this->once())
471
            ->method('getVersionInfo')
472
            ->will($this->returnValue($versionInfo));
473
        $contentId = 123;
474
        $contentService
475
            ->expects($this->once())
476
            ->method('internalLoadContent')
477
            ->with($contentId)
478
            ->will($this->returnValue($content));
479
480
        $repository
481
            ->expects($this->exactly(2))
482
            ->method('canUser')
483
            ->will(
484
                $this->returnValueMap(
485
                    [
486
                        ['content', 'read', $content, null, true],
487
                        ['content', 'versionread', $content, null, true],
488
                    ]
489
                )
490
            );
491
492
        $this->assertSame($content, $contentService->loadContent($contentId));
493
    }
494
495
    /**
496
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
497
     */
498
    public function testLoadContentUnauthorized()
499
    {
500
        $repository = $this->getRepositoryMock();
501
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
502
        $content = $this->createMock(APIContent::class);
503
        $contentId = 123;
504
        $contentService
505
            ->expects($this->once())
506
            ->method('internalLoadContent')
507
            ->with($contentId)
508
            ->will($this->returnValue($content));
509
510
        $repository
511
            ->expects($this->once())
512
            ->method('canUser')
513
            ->with('content', 'read', $content)
514
            ->will($this->returnValue(false));
515
516
        $contentService->loadContent($contentId);
517
    }
518
519
    /**
520
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
521
     */
522 View Code Duplication
    public function testLoadContentNotPublishedStatusUnauthorized()
523
    {
524
        $repository = $this->getRepositoryMock();
525
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
526
        $content = $this->createMock(APIContent::class);
527
        $versionInfo = $this
528
            ->getMockBuilder(APIVersionInfo::class)
529
            ->getMockForAbstractClass();
530
        $content
531
            ->expects($this->once())
532
            ->method('getVersionInfo')
533
            ->will($this->returnValue($versionInfo));
534
        $contentId = 123;
535
        $contentService
536
            ->expects($this->once())
537
            ->method('internalLoadContent')
538
            ->with($contentId)
539
            ->will($this->returnValue($content));
540
541
        $repository
542
            ->expects($this->exactly(2))
543
            ->method('canUser')
544
            ->will(
545
                $this->returnValueMap(
546
                    [
547
                        ['content', 'read', $content, null, true],
548
                        ['content', 'versionread', $content, null, false],
549
                    ]
550
                )
551
            );
552
553
        $contentService->loadContent($contentId);
554
    }
555
556
    /**
557
     * @dataProvider internalLoadContentProvider
558
     */
559
    public function testInternalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
560
    {
561
        $contentService = $this->getPartlyMockedContentService();
562
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
563
        $contentHandler = $this->getPersistenceMock()->contentHandler();
564
        $realId = $id;
565
566
        if ($isRemoteId) {
567
            $realId = 123;
568
            $spiContentInfo = new SPIContentInfo(['currentVersionNo' => $versionNo ?: 7, 'id' => $realId]);
569
            $contentHandler
570
                ->expects($this->once())
571
                ->method('loadContentInfoByRemoteId')
572
                ->with($id)
573
                ->will($this->returnValue($spiContentInfo));
574
        } elseif (!empty($languages) && $useAlwaysAvailable) {
575
            $spiContentInfo = new SPIContentInfo(['alwaysAvailable' => false]);
576
            $contentHandler
577
                ->expects($this->once())
578
                ->method('loadContentInfo')
579
                ->with($id)
580
                ->will($this->returnValue($spiContentInfo));
581
        }
582
583
        $spiContent = new SPIContent([
584
            'versionInfo' => new VersionInfo([
585
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
586
            ]),
587
        ]);
588
        $contentHandler
589
            ->expects($this->once())
590
            ->method('load')
591
            ->with($realId, $versionNo, $languages)
592
            ->willReturn($spiContent);
593
594
        $content = $this->mockBuildContentDomainObject($spiContent, $languages);
595
596
        $this->assertSame(
597
            $content,
598
            $contentService->internalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
599
        );
600
    }
601
602
    public function internalLoadContentProvider()
603
    {
604
        return [
605
            [123, null, null, false, false],
606
            [123, null, 456, false, false],
607
            [456, null, 123, false, true],
608
            [456, null, 2, false, false],
609
            [456, ['eng-GB'], 2, false, true],
610
            [456, ['eng-GB', 'fre-FR'], null, false, false],
611
            [456, ['eng-GB', 'fre-FR', 'nor-NO'], 2, false, false],
612
            // With remoteId
613
            [123, null, null, true, false],
614
            ['someRemoteId', null, 456, true, false],
615
            [456, null, 123, true, false],
616
            ['someRemoteId', null, 2, true, false],
617
            ['someRemoteId', ['eng-GB'], 2, true, false],
618
            [456, ['eng-GB', 'fre-FR'], null, true, false],
619
            ['someRemoteId', ['eng-GB', 'fre-FR', 'nor-NO'], 2, true, false],
620
        ];
621
    }
622
623
    /**
624
     * @expectedException \eZ\Publish\Core\Base\Exceptions\NotFoundException
625
     */
626
    public function testInternalLoadContentNotFound()
627
    {
628
        $contentService = $this->getPartlyMockedContentService();
629
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
630
        $contentHandler = $this->getPersistenceMock()->contentHandler();
631
        $id = 123;
632
        $versionNo = 7;
633
        $languages = null;
634
        $contentHandler
635
            ->expects($this->once())
636
            ->method('load')
637
            ->with($id, $versionNo, $languages)
638
            ->will(
639
                $this->throwException(
640
                    $this->createMock(APINotFoundException::class)
641
                )
642
            );
643
644
        $contentService->internalLoadContent($id, $languages, $versionNo);
645
    }
646
647
    /**
648
     * Test for the loadContentByContentInfo() method.
649
     *
650
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByContentInfo
651
     */
652
    public function testLoadContentByContentInfo()
653
    {
654
        $contentServiceMock = $this->getPartlyMockedContentService(
655
            ['loadContent']
656
        );
657
        $contentServiceMock->expects(
658
            $this->once()
659
        )->method(
660
            'loadContent'
661
        )->with(
662
            $this->equalTo(42),
663
            $this->equalTo(['cro-HR']),
664
            $this->equalTo(7),
665
            $this->equalTo(false)
666
        )->will(
667
            $this->returnValue('result')
668
        );
669
670
        $result = $contentServiceMock->loadContentByContentInfo(
671
            new ContentInfo(['id' => 42]),
672
            ['cro-HR'],
673
            7
674
        );
675
676
        $this->assertEquals('result', $result);
677
    }
678
679
    /**
680
     * Test for the loadContentByVersionInfo() method.
681
     *
682
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByVersionInfo
683
     */
684
    public function testLoadContentByVersionInfo()
685
    {
686
        $contentServiceMock = $this->getPartlyMockedContentService(
687
            ['loadContent']
688
        );
689
        $contentServiceMock->expects(
690
            $this->once()
691
        )->method(
692
            'loadContent'
693
        )->with(
694
            $this->equalTo(42),
695
            $this->equalTo(['cro-HR']),
696
            $this->equalTo(7),
697
            $this->equalTo(false)
698
        )->will(
699
            $this->returnValue('result')
700
        );
701
702
        $result = $contentServiceMock->loadContentByVersionInfo(
703
            new VersionInfo(
704
                [
705
                    'contentInfo' => new ContentInfo(['id' => 42]),
706
                    'versionNo' => 7,
707
                ]
708
            ),
709
            ['cro-HR']
710
        );
711
712
        $this->assertEquals('result', $result);
713
    }
714
715
    /**
716
     * Test for the deleteContent() method.
717
     *
718
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
719
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
720
     */
721
    public function testDeleteContentThrowsUnauthorizedException()
722
    {
723
        $repository = $this->getRepositoryMock();
724
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
725
        $contentInfo = $this->createMock(APIContentInfo::class);
726
727
        $contentInfo->expects($this->any())
728
            ->method('__get')
729
            ->with('id')
730
            ->will($this->returnValue(42));
731
732
        $contentService->expects($this->once())
733
            ->method('internalLoadContentInfo')
734
            ->with(42)
735
            ->will($this->returnValue($contentInfo));
736
737
        $repository->expects($this->once())
738
            ->method('canUser')
739
            ->with('content', 'remove')
740
            ->will($this->returnValue(false));
741
742
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
743
        $contentService->deleteContent($contentInfo);
744
    }
745
746
    /**
747
     * Test for the deleteContent() method.
748
     *
749
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
750
     */
751
    public function testDeleteContent()
752
    {
753
        $repository = $this->getRepositoryMock();
754
755
        $repository->expects($this->once())
756
            ->method('canUser')
757
            ->with('content', 'remove')
758
            ->will($this->returnValue(true));
759
760
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
761
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandler */
762
        $urlAliasHandler = $this->getPersistenceMock()->urlAliasHandler();
763
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
764
        $locationHandler = $this->getPersistenceMock()->locationHandler();
765
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
766
        $contentHandler = $this->getPersistenceMock()->contentHandler();
767
768
        $contentInfo = $this->createMock(APIContentInfo::class);
769
770
        $contentService->expects($this->once())
771
            ->method('internalLoadContentInfo')
772
            ->with(42)
773
            ->will($this->returnValue($contentInfo));
774
775
        $contentInfo->expects($this->any())
776
            ->method('__get')
777
            ->with('id')
778
            ->will($this->returnValue(42));
779
780
        $repository->expects($this->once())->method('beginTransaction');
781
782
        $spiLocations = [
783
            new SPILocation(['id' => 1]),
784
            new SPILocation(['id' => 2]),
785
        ];
786
        $locationHandler->expects($this->once())
787
            ->method('loadLocationsByContent')
788
            ->with(42)
789
            ->will($this->returnValue($spiLocations));
790
791
        $contentHandler->expects($this->once())
792
            ->method('deleteContent')
793
            ->with(42);
794
795
        foreach ($spiLocations as $index => $spiLocation) {
796
            $urlAliasHandler->expects($this->at($index))
797
                ->method('locationDeleted')
798
                ->with($spiLocation->id);
799
        }
800
801
        $repository->expects($this->once())->method('commit');
802
803
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
804
        $contentService->deleteContent($contentInfo);
805
    }
806
807
    /**
808
     * Test for the deleteContent() method.
809
     *
810
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
811
     * @expectedException \Exception
812
     */
813
    public function testDeleteContentWithRollback()
814
    {
815
        $repository = $this->getRepositoryMock();
816
817
        $repository->expects($this->once())
818
            ->method('canUser')
819
            ->with('content', 'remove')
820
            ->will($this->returnValue(true));
821
822
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
823
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
824
        $locationHandler = $this->getPersistenceMock()->locationHandler();
825
826
        $contentInfo = $this->createMock(APIContentInfo::class);
827
828
        $contentService->expects($this->once())
829
            ->method('internalLoadContentInfo')
830
            ->with(42)
831
            ->will($this->returnValue($contentInfo));
832
833
        $contentInfo->expects($this->any())
834
            ->method('__get')
835
            ->with('id')
836
            ->will($this->returnValue(42));
837
838
        $repository->expects($this->once())->method('beginTransaction');
839
840
        $locationHandler->expects($this->once())
841
            ->method('loadLocationsByContent')
842
            ->with(42)
843
            ->will($this->throwException(new \Exception()));
844
845
        $repository->expects($this->once())->method('rollback');
846
847
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
848
        $contentService->deleteContent($contentInfo);
849
    }
850
851
    /**
852
     * Test for the deleteVersion() method.
853
     *
854
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
855
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
856
     */
857
    public function testDeleteVersionThrowsBadStateExceptionLastVersion()
858
    {
859
        $repository = $this->getRepositoryMock();
860
        $repository
861
            ->expects($this->once())
862
            ->method('canUser')
863
            ->with('content', 'versionremove')
864
            ->will($this->returnValue(true));
865
        $repository
866
            ->expects($this->never())
867
            ->method('beginTransaction');
868
869
        $contentService = $this->getPartlyMockedContentService();
870
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
871
        $contentHandler = $this->getPersistenceMock()->contentHandler();
872
        $contentInfo = $this->createMock(APIContentInfo::class);
873
        $versionInfo = $this->createMock(APIVersionInfo::class);
874
875
        $contentInfo
876
            ->expects($this->any())
877
            ->method('__get')
878
            ->with('id')
879
            ->will($this->returnValue(42));
880
881
        $versionInfo
882
            ->expects($this->any())
883
            ->method('__get')
884
            ->will(
885
                $this->returnValueMap(
886
                    [
887
                        ['versionNo', 123],
888
                        ['contentInfo', $contentInfo],
889
                    ]
890
                )
891
            );
892
        $versionInfo
893
            ->expects($this->once())
894
            ->method('isPublished')
895
            ->willReturn(false);
896
897
        $contentHandler
898
            ->expects($this->once())
899
            ->method('listVersions')
900
            ->with(42)
901
            ->will($this->returnValue(['version']));
902
903
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo */
904
        $contentService->deleteVersion($versionInfo);
905
    }
906
907
    /**
908
     * Test for the createContent() method.
909
     *
910
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
911
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
912
     * @expectedExceptionMessage Argument '$contentCreateStruct' is invalid: 'mainLanguageCode' property must be set
913
     */
914
    public function testCreateContentThrowsInvalidArgumentExceptionMainLanguageCodeNotSet()
915
    {
916
        $mockedService = $this->getPartlyMockedContentService();
917
        $mockedService->createContent(new ContentCreateStruct(), []);
918
    }
919
920
    /**
921
     * Test for the createContent() method.
922
     *
923
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
924
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
925
     * @expectedExceptionMessage Argument '$contentCreateStruct' is invalid: 'contentType' property must be set
926
     */
927
    public function testCreateContentThrowsInvalidArgumentExceptionContentTypeNotSet()
928
    {
929
        $mockedService = $this->getPartlyMockedContentService();
930
        $mockedService->createContent(
931
            new ContentCreateStruct(['mainLanguageCode' => 'eng-US']),
932
            []
933
        );
934
    }
935
936
    /**
937
     * Test for the createContent() method.
938
     *
939
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
940
     * @expectedException \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
941
     */
942
    public function testCreateContentThrowsUnauthorizedException()
943
    {
944
        $repositoryMock = $this->getRepositoryMock();
945
        $mockedService = $this->getPartlyMockedContentService();
946
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
947
        $contentType = new ContentType(
948
            [
949
                'id' => 123,
950
                'fieldDefinitions' => [],
951
            ]
952
        );
953
        $contentCreateStruct = new ContentCreateStruct(
954
            [
955
                'ownerId' => 169,
956
                'alwaysAvailable' => false,
957
                'mainLanguageCode' => 'eng-US',
958
                'contentType' => $contentType,
959
            ]
960
        );
961
962
        $repositoryMock->expects($this->once())
963
            ->method('getCurrentUserReference')
964
            ->will($this->returnValue(new UserReference(169)));
965
966
        $contentTypeServiceMock->expects($this->once())
967
            ->method('loadContentType')
968
            ->with($this->equalTo(123))
969
            ->will($this->returnValue($contentType));
970
971
        $repositoryMock->expects($this->once())
972
            ->method('getContentTypeService')
973
            ->will($this->returnValue($contentTypeServiceMock));
974
975
        $repositoryMock->expects($this->once())
976
            ->method('canUser')
977
            ->with(
978
                $this->equalTo('content'),
979
                $this->equalTo('create'),
980
                $this->isInstanceOf(get_class($contentCreateStruct)),
981
                $this->equalTo([])
982
            )->will($this->returnValue(false));
983
984
        $mockedService->createContent(
985
            new ContentCreateStruct(
986
                [
987
                    'mainLanguageCode' => 'eng-US',
988
                    'contentType' => $contentType,
989
                ]
990
            ),
991
            []
992
        );
993
    }
994
995
    /**
996
     * Test for the createContent() method.
997
     *
998
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
999
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1000
     * @exceptionMessage Argument '$contentCreateStruct' is invalid: Another content with remoteId 'faraday' exists
1001
     */
1002
    public function testCreateContentThrowsInvalidArgumentExceptionDuplicateRemoteId()
1003
    {
1004
        $repositoryMock = $this->getRepositoryMock();
1005
        $mockedService = $this->getPartlyMockedContentService(['loadContentByRemoteId']);
1006
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1007
        $contentType = new ContentType(
1008
            [
1009
                'id' => 123,
1010
                'fieldDefinitions' => [],
1011
            ]
1012
        );
1013
        $contentCreateStruct = new ContentCreateStruct(
1014
            [
1015
                'ownerId' => 169,
1016
                'alwaysAvailable' => false,
1017
                'remoteId' => 'faraday',
1018
                'mainLanguageCode' => 'eng-US',
1019
                'contentType' => $contentType,
1020
            ]
1021
        );
1022
1023
        $repositoryMock->expects($this->once())
1024
            ->method('getCurrentUserReference')
1025
            ->will($this->returnValue(new UserReference(169)));
1026
1027
        $contentTypeServiceMock->expects($this->once())
1028
            ->method('loadContentType')
1029
            ->with($this->equalTo(123))
1030
            ->will($this->returnValue($contentType));
1031
1032
        $repositoryMock->expects($this->once())
1033
            ->method('getContentTypeService')
1034
            ->will($this->returnValue($contentTypeServiceMock));
1035
1036
        $repositoryMock->expects($this->once())
1037
            ->method('canUser')
1038
            ->with(
1039
                $this->equalTo('content'),
1040
                $this->equalTo('create'),
1041
                $this->isInstanceOf(get_class($contentCreateStruct)),
1042
                $this->equalTo([])
1043
            )->will($this->returnValue(true));
1044
1045
        $mockedService->expects($this->once())
1046
            ->method('loadContentByRemoteId')
1047
            ->with($contentCreateStruct->remoteId)
1048
            ->will($this->returnValue('Hello...'));
1049
1050
        $mockedService->createContent(
1051
            new ContentCreateStruct(
1052
                [
1053
                    'remoteId' => 'faraday',
1054
                    'mainLanguageCode' => 'eng-US',
1055
                    'contentType' => $contentType,
1056
                ]
1057
            ),
1058
            []
1059
        );
1060
    }
1061
1062
    /**
1063
     * @param string $mainLanguageCode
1064
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1065
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1066
     *
1067
     * @return array
1068
     */
1069
    protected function mapStructFieldsForCreate($mainLanguageCode, $structFields, $fieldDefinitions)
1070
    {
1071
        $mappedFieldDefinitions = [];
1072
        foreach ($fieldDefinitions as $fieldDefinition) {
1073
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
1074
        }
1075
1076
        $mappedStructFields = [];
1077
        foreach ($structFields as $structField) {
1078
            if ($structField->languageCode === null) {
1079
                $languageCode = $mainLanguageCode;
1080
            } else {
1081
                $languageCode = $structField->languageCode;
1082
            }
1083
1084
            $mappedStructFields[$structField->fieldDefIdentifier][$languageCode] = (string)$structField->value;
1085
        }
1086
1087
        return $mappedStructFields;
1088
    }
1089
1090
    /**
1091
     * Returns full, possibly redundant array of field values, indexed by field definition
1092
     * identifier and language code.
1093
     *
1094
     * @throws \RuntimeException Method is intended to be used only with consistent fixtures
1095
     *
1096
     * @param string $mainLanguageCode
1097
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1098
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1099
     * @param array $languageCodes
1100
     *
1101
     * @return array
1102
     */
1103
    protected function determineValuesForCreate(
1104
        $mainLanguageCode,
1105
        array $structFields,
1106
        array $fieldDefinitions,
1107
        array $languageCodes
1108
    ) {
1109
        $mappedStructFields = $this->mapStructFieldsForCreate(
1110
            $mainLanguageCode,
1111
            $structFields,
1112
            $fieldDefinitions
1113
        );
1114
1115
        $values = [];
1116
1117
        foreach ($fieldDefinitions as $fieldDefinition) {
1118
            $identifier = $fieldDefinition->identifier;
1119
            foreach ($languageCodes as $languageCode) {
1120 View Code Duplication
                if (!$fieldDefinition->isTranslatable) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1121
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
1122
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
1123
                    } else {
1124
                        $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1125
                    }
1126
                    continue;
1127
                }
1128
1129 View Code Duplication
                if (isset($mappedStructFields[$identifier][$languageCode])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1130
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
1131
                    continue;
1132
                }
1133
1134
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1135
            }
1136
        }
1137
1138
        return $this->stubValues($values);
1139
    }
1140
1141
    /**
1142
     * @param string $mainLanguageCode
1143
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1144
     *
1145
     * @return string[]
1146
     */
1147
    protected function determineLanguageCodesForCreate($mainLanguageCode, array $structFields)
1148
    {
1149
        $languageCodes = [];
1150
1151
        foreach ($structFields as $field) {
1152
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
1153
                continue;
1154
            }
1155
1156
            $languageCodes[$field->languageCode] = true;
1157
        }
1158
1159
        $languageCodes[$mainLanguageCode] = true;
1160
1161
        return array_keys($languageCodes);
1162
    }
1163
1164
    /**
1165
     * Asserts that calling createContent() with given API field set causes calling
1166
     * Handler::createContent() with given SPI field set.
1167
     *
1168
     * @param string $mainLanguageCode
1169
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1170
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
1171
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1172
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationCreateStructs
1173
     * @param \eZ\Publish\SPI\Persistence\Content\ObjectState\Group[] $objectStateGroups
0 ignored issues
show
Bug introduced by
There is no parameter named $objectStateGroups. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1174
     * @param bool $execute
1175
     *
1176
     * @return mixed
1177
     */
1178
    protected function assertForTestCreateContentNonRedundantFieldSet(
1179
        $mainLanguageCode,
1180
        array $structFields,
1181
        array $spiFields,
1182
        array $fieldDefinitions,
1183
        array $locationCreateStructs = [],
1184
        $withObjectStates = false,
1185
        $execute = true
1186
    ) {
1187
        $repositoryMock = $this->getRepositoryMock();
1188
        $mockedService = $this->getPartlyMockedContentService();
1189
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
1190
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
1191
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1192
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1193
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
1194
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
1195
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1196
        $fieldTypeServiceMock = $this->getFieldTypeServiceMock();
0 ignored issues
show
Unused Code introduced by
$fieldTypeServiceMock is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1197
        $domainMapperMock = $this->getDomainMapperMock();
1198
        $relationProcessorMock = $this->getRelationProcessorMock();
1199
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
1200
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
1201
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
1202
        $contentType = new ContentType(
1203
            [
1204
                'id' => 123,
1205
                'fieldDefinitions' => $fieldDefinitions,
1206
                'nameSchema' => '<nameSchema>',
1207
            ]
1208
        );
1209
        $contentCreateStruct = new ContentCreateStruct(
1210
            [
1211
                'fields' => $structFields,
1212
                'mainLanguageCode' => $mainLanguageCode,
1213
                'contentType' => $contentType,
1214
                'alwaysAvailable' => false,
1215
                'ownerId' => 169,
1216
                'sectionId' => 1,
1217
            ]
1218
        );
1219
1220
        $languageHandlerMock->expects($this->any())
1221
            ->method('loadByLanguageCode')
1222
            ->with($this->isType('string'))
1223
            ->will(
1224
                $this->returnCallback(
1225
                    function () {
1226
                        return new Language(['id' => 4242]);
1227
                    }
1228
                )
1229
            );
1230
1231
        $repositoryMock->expects($this->once())->method('beginTransaction');
1232
1233
        $contentTypeServiceMock->expects($this->once())
1234
            ->method('loadContentType')
1235
            ->with($this->equalTo($contentType->id))
1236
            ->will($this->returnValue($contentType));
1237
1238
        $repositoryMock->expects($this->once())
1239
            ->method('getContentTypeService')
1240
            ->will($this->returnValue($contentTypeServiceMock));
1241
1242
        $that = $this;
1243
        $repositoryMock->expects($this->once())
1244
            ->method('canUser')
1245
            ->with(
1246
                $this->equalTo('content'),
1247
                $this->equalTo('create'),
1248
                $this->isInstanceOf(APIContentCreateStruct::class),
1249
                $this->equalTo($locationCreateStructs)
1250
            )->will(
1251
                $this->returnCallback(
1252
                    function () use ($that, $contentCreateStruct) {
1253
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1254
1255
                        return true;
1256
                    }
1257
                )
1258
            );
1259
1260
        $domainMapperMock->expects($this->once())
1261
            ->method('getUniqueHash')
1262
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1263
            ->will(
1264
                $this->returnCallback(
1265
                    function ($object) use ($that, $contentCreateStruct) {
1266
                        $that->assertEquals($contentCreateStruct, $object);
1267
1268
                        return 'hash';
1269
                    }
1270
                )
1271
            );
1272
1273
        $fieldTypeMock->expects($this->any())
1274
            ->method('acceptValue')
1275
            ->will(
1276
                $this->returnCallback(
1277
                    function ($valueString) {
1278
                        return new ValueStub($valueString);
1279
                    }
1280
                )
1281
            );
1282
1283
        $fieldTypeMock->expects($this->any())
1284
            ->method('toPersistenceValue')
1285
            ->will(
1286
                $this->returnCallback(
1287
                    function (ValueStub $value) {
1288
                        return (string)$value;
1289
                    }
1290
                )
1291
            );
1292
1293
        $emptyValue = self::EMPTY_FIELD_VALUE;
1294
        $fieldTypeMock->expects($this->any())
1295
            ->method('isEmptyValue')
1296
            ->will(
1297
                $this->returnCallback(
1298
                    function (ValueStub $value) use ($emptyValue) {
1299
                        return $emptyValue === (string)$value;
1300
                    }
1301
                )
1302
            );
1303
1304
        $fieldTypeMock->expects($this->any())
1305
            ->method('validate')
1306
            ->will($this->returnValue([]));
1307
1308
        $this->getFieldTypeRegistryMock()->expects($this->any())
1309
            ->method('getFieldType')
1310
            ->will($this->returnValue($fieldTypeMock));
1311
1312
        $relationProcessorMock
1313
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
1314
            ->method('appendFieldRelations')
1315
            ->with(
1316
                $this->isType('array'),
1317
                $this->isType('array'),
1318
                $this->isInstanceOf(SPIFieldType::class),
1319
                $this->isInstanceOf(Value::class),
1320
                $this->anything()
1321
            );
1322
1323
        $values = $this->determineValuesForCreate(
1324
            $mainLanguageCode,
1325
            $structFields,
1326
            $fieldDefinitions,
1327
            $languageCodes
1328
        );
1329
        $nameSchemaServiceMock->expects($this->once())
1330
            ->method('resolve')
1331
            ->with(
1332
                $this->equalTo($contentType->nameSchema),
1333
                $this->equalTo($contentType),
1334
                $this->equalTo($values),
1335
                $this->equalTo($languageCodes)
1336
            )->will($this->returnValue([]));
1337
1338
        $relationProcessorMock->expects($this->any())
1339
            ->method('processFieldRelations')
1340
            ->with(
1341
                $this->isType('array'),
1342
                $this->equalTo(42),
1343
                $this->isType('int'),
1344
                $this->equalTo($contentType),
1345
                $this->equalTo([])
1346
            );
1347
1348
        if (!$withObjectStates) {
1349
            $objectStateHandlerMock->expects($this->once())
1350
                ->method('loadAllGroups')
1351
                ->will($this->returnValue([]));
1352
        }
1353
1354
        if ($execute) {
1355
            $spiContentCreateStruct = new SPIContentCreateStruct(
1356
                [
1357
                    'name' => [],
1358
                    'typeId' => 123,
1359
                    'sectionId' => 1,
1360
                    'ownerId' => 169,
1361
                    'remoteId' => 'hash',
1362
                    'fields' => $spiFields,
1363
                    'modified' => time(),
1364
                    'initialLanguageId' => 4242,
1365
                ]
1366
            );
1367
            $spiContentCreateStruct2 = clone $spiContentCreateStruct;
1368
            ++$spiContentCreateStruct2->modified;
1369
1370
            $spiContent = new SPIContent(
1371
                [
1372
                    'versionInfo' => new SPIContent\VersionInfo(
1373
                        [
1374
                            'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
1375
                            'versionNo' => 7,
1376
                        ]
1377
                    ),
1378
                ]
1379
            );
1380
1381
            $contentHandlerMock->expects($this->once())
1382
                ->method('create')
1383
                ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
1384
                ->will($this->returnValue($spiContent));
1385
1386
            $repositoryMock->expects($this->once())->method('commit');
1387
            $domainMapperMock->expects($this->once())
1388
                ->method('buildContentDomainObject')
1389
                ->with(
1390
                    $this->isInstanceOf(SPIContent::class),
1391
                    $this->equalTo($contentType)
1392
                );
1393
1394
            $mockedService->createContent($contentCreateStruct, []);
1395
        }
1396
1397
        return $contentCreateStruct;
1398
    }
1399
1400
    public function providerForTestCreateContentNonRedundantFieldSet1()
1401
    {
1402
        $spiFields = [
1403
            new SPIField(
1404
                [
1405
                    'fieldDefinitionId' => 'fieldDefinitionId',
1406
                    'type' => 'fieldTypeIdentifier',
1407
                    'value' => 'newValue',
1408
                    'languageCode' => 'eng-US',
1409
                ]
1410
            ),
1411
        ];
1412
1413
        return [
1414
            // 0. Without language set
1415
            [
1416
                'eng-US',
1417
                [
1418
                    new Field(
1419
                        [
1420
                            'fieldDefIdentifier' => 'identifier',
1421
                            'value' => 'newValue',
1422
                            'languageCode' => 'eng-US',
1423
                        ]
1424
                    ),
1425
                ],
1426
                $spiFields,
1427
            ],
1428
            // 1. Without language set
1429
            [
1430
                'eng-US',
1431
                [
1432
                    new Field(
1433
                        [
1434
                            'fieldDefIdentifier' => 'identifier',
1435
                            'value' => 'newValue',
1436
                            'languageCode' => null,
1437
                        ]
1438
                    ),
1439
                ],
1440
                $spiFields,
1441
            ],
1442
        ];
1443
    }
1444
1445
    /**
1446
     * Test for the createContent() method.
1447
     *
1448
     * Testing the simplest use case.
1449
     *
1450
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1451
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1452
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1453
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1454
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1455
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet1
1456
     */
1457 View Code Duplication
    public function testCreateContentNonRedundantFieldSet1($mainLanguageCode, $structFields, $spiFields)
1458
    {
1459
        $fieldDefinitions = [
1460
            new FieldDefinition(
1461
                [
1462
                    'id' => 'fieldDefinitionId',
1463
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1464
                    'isTranslatable' => false,
1465
                    'identifier' => 'identifier',
1466
                    'isRequired' => false,
1467
                    'defaultValue' => 'defaultValue',
1468
                ]
1469
            ),
1470
        ];
1471
1472
        $this->assertForTestCreateContentNonRedundantFieldSet(
1473
            $mainLanguageCode,
1474
            $structFields,
1475
            $spiFields,
1476
            $fieldDefinitions
1477
        );
1478
    }
1479
1480
    public function providerForTestCreateContentNonRedundantFieldSet2()
1481
    {
1482
        $spiFields = [
1483
            new SPIField(
1484
                [
1485
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1486
                    'type' => 'fieldTypeIdentifier',
1487
                    'value' => 'newValue1',
1488
                    'languageCode' => 'eng-US',
1489
                ]
1490
            ),
1491
            new SPIField(
1492
                [
1493
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1494
                    'type' => 'fieldTypeIdentifier',
1495
                    'value' => 'newValue2',
1496
                    'languageCode' => 'ger-DE',
1497
                ]
1498
            ),
1499
        ];
1500
1501
        return [
1502
            // 0. With language set
1503
            [
1504
                'eng-US',
1505
                [
1506
                    new Field(
1507
                        [
1508
                            'fieldDefIdentifier' => 'identifier1',
1509
                            'value' => 'newValue1',
1510
                            'languageCode' => 'eng-US',
1511
                        ]
1512
                    ),
1513
                    new Field(
1514
                        [
1515
                            'fieldDefIdentifier' => 'identifier2',
1516
                            'value' => 'newValue2',
1517
                            'languageCode' => 'ger-DE',
1518
                        ]
1519
                    ),
1520
                ],
1521
                $spiFields,
1522
            ],
1523
            // 1. Without language set
1524
            [
1525
                'eng-US',
1526
                [
1527
                    new Field(
1528
                        [
1529
                            'fieldDefIdentifier' => 'identifier1',
1530
                            'value' => 'newValue1',
1531
                            'languageCode' => null,
1532
                        ]
1533
                    ),
1534
                    new Field(
1535
                        [
1536
                            'fieldDefIdentifier' => 'identifier2',
1537
                            'value' => 'newValue2',
1538
                            'languageCode' => 'ger-DE',
1539
                        ]
1540
                    ),
1541
                ],
1542
                $spiFields,
1543
            ],
1544
        ];
1545
    }
1546
1547
    /**
1548
     * Test for the createContent() method.
1549
     *
1550
     * Testing multiple languages with multiple translatable fields with empty default value.
1551
     *
1552
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1553
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1554
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1555
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1556
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1557
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet2
1558
     */
1559
    public function testCreateContentNonRedundantFieldSet2($mainLanguageCode, $structFields, $spiFields)
1560
    {
1561
        $fieldDefinitions = [
1562
            new FieldDefinition(
1563
                [
1564
                    'id' => 'fieldDefinitionId1',
1565
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1566
                    'isTranslatable' => true,
1567
                    'identifier' => 'identifier1',
1568
                    'isRequired' => false,
1569
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1570
                ]
1571
            ),
1572
            new FieldDefinition(
1573
                [
1574
                    'id' => 'fieldDefinitionId2',
1575
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1576
                    'isTranslatable' => true,
1577
                    'identifier' => 'identifier2',
1578
                    'isRequired' => false,
1579
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1580
                ]
1581
            ),
1582
        ];
1583
1584
        $this->assertForTestCreateContentNonRedundantFieldSet(
1585
            $mainLanguageCode,
1586
            $structFields,
1587
            $spiFields,
1588
            $fieldDefinitions
1589
        );
1590
    }
1591
1592
    public function providerForTestCreateContentNonRedundantFieldSetComplex()
1593
    {
1594
        $spiFields0 = [
1595
            new SPIField(
1596
                [
1597
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1598
                    'type' => 'fieldTypeIdentifier',
1599
                    'value' => 'defaultValue2',
1600
                    'languageCode' => 'eng-US',
1601
                ]
1602
            ),
1603
            new SPIField(
1604
                [
1605
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1606
                    'type' => 'fieldTypeIdentifier',
1607
                    'value' => 'defaultValue4',
1608
                    'languageCode' => 'eng-US',
1609
                ]
1610
            ),
1611
        ];
1612
        $spiFields1 = [
1613
            new SPIField(
1614
                [
1615
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1616
                    'type' => 'fieldTypeIdentifier',
1617
                    'value' => 'newValue1',
1618
                    'languageCode' => 'ger-DE',
1619
                ]
1620
            ),
1621
            new SPIField(
1622
                [
1623
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1624
                    'type' => 'fieldTypeIdentifier',
1625
                    'value' => 'defaultValue2',
1626
                    'languageCode' => 'ger-DE',
1627
                ]
1628
            ),
1629
            new SPIField(
1630
                [
1631
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1632
                    'type' => 'fieldTypeIdentifier',
1633
                    'value' => 'newValue2',
1634
                    'languageCode' => 'eng-US',
1635
                ]
1636
            ),
1637
            new SPIField(
1638
                [
1639
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1640
                    'type' => 'fieldTypeIdentifier',
1641
                    'value' => 'newValue4',
1642
                    'languageCode' => 'eng-US',
1643
                ]
1644
            ),
1645
        ];
1646
1647
        return [
1648
            // 0. Creating by default values only
1649
            [
1650
                'eng-US',
1651
                [],
1652
                $spiFields0,
1653
            ],
1654
            // 1. Multiple languages with language set
1655
            [
1656
                'eng-US',
1657
                [
1658
                    new Field(
1659
                        [
1660
                            'fieldDefIdentifier' => 'identifier1',
1661
                            'value' => 'newValue1',
1662
                            'languageCode' => 'ger-DE',
1663
                        ]
1664
                    ),
1665
                    new Field(
1666
                        [
1667
                            'fieldDefIdentifier' => 'identifier2',
1668
                            'value' => 'newValue2',
1669
                            'languageCode' => 'eng-US',
1670
                        ]
1671
                    ),
1672
                    new Field(
1673
                        [
1674
                            'fieldDefIdentifier' => 'identifier4',
1675
                            'value' => 'newValue4',
1676
                            'languageCode' => 'eng-US',
1677
                        ]
1678
                    ),
1679
                ],
1680
                $spiFields1,
1681
            ],
1682
            // 2. Multiple languages without language set
1683
            [
1684
                'eng-US',
1685
                [
1686
                    new Field(
1687
                        [
1688
                            'fieldDefIdentifier' => 'identifier1',
1689
                            'value' => 'newValue1',
1690
                            'languageCode' => 'ger-DE',
1691
                        ]
1692
                    ),
1693
                    new Field(
1694
                        [
1695
                            'fieldDefIdentifier' => 'identifier2',
1696
                            'value' => 'newValue2',
1697
                            'languageCode' => null,
1698
                        ]
1699
                    ),
1700
                    new Field(
1701
                        [
1702
                            'fieldDefIdentifier' => 'identifier4',
1703
                            'value' => 'newValue4',
1704
                            'languageCode' => null,
1705
                        ]
1706
                    ),
1707
                ],
1708
                $spiFields1,
1709
            ],
1710
        ];
1711
    }
1712
1713
    protected function fixturesForTestCreateContentNonRedundantFieldSetComplex()
1714
    {
1715
        return [
1716
            new FieldDefinition(
1717
                [
1718
                    'id' => 'fieldDefinitionId1',
1719
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1720
                    'isTranslatable' => true,
1721
                    'identifier' => 'identifier1',
1722
                    'isRequired' => false,
1723
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1724
                ]
1725
            ),
1726
            new FieldDefinition(
1727
                [
1728
                    'id' => 'fieldDefinitionId2',
1729
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1730
                    'isTranslatable' => true,
1731
                    'identifier' => 'identifier2',
1732
                    'isRequired' => false,
1733
                    'defaultValue' => 'defaultValue2',
1734
                ]
1735
            ),
1736
            new FieldDefinition(
1737
                [
1738
                    'id' => 'fieldDefinitionId3',
1739
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1740
                    'isTranslatable' => false,
1741
                    'identifier' => 'identifier3',
1742
                    'isRequired' => false,
1743
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1744
                ]
1745
            ),
1746
            new FieldDefinition(
1747
                [
1748
                    'id' => 'fieldDefinitionId4',
1749
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1750
                    'isTranslatable' => false,
1751
                    'identifier' => 'identifier4',
1752
                    'isRequired' => false,
1753
                    'defaultValue' => 'defaultValue4',
1754
                ]
1755
            ),
1756
        ];
1757
    }
1758
1759
    /**
1760
     * Test for the createContent() method.
1761
     *
1762
     * Testing multiple languages with multiple translatable fields with empty default value.
1763
     *
1764
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1765
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1766
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1767
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1768
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1769
     * @dataProvider providerForTestCreateContentNonRedundantFieldSetComplex
1770
     */
1771
    public function testCreateContentNonRedundantFieldSetComplex($mainLanguageCode, $structFields, $spiFields)
1772
    {
1773
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
1774
1775
        $this->assertForTestCreateContentNonRedundantFieldSet(
1776
            $mainLanguageCode,
1777
            $structFields,
1778
            $spiFields,
1779
            $fieldDefinitions
1780
        );
1781
    }
1782
1783 View Code Duplication
    public function providerForTestCreateContentWithInvalidLanguage()
1784
    {
1785
        return [
1786
            [
1787
                'eng-GB',
1788
                [
1789
                    new Field(
1790
                        [
1791
                            'fieldDefIdentifier' => 'identifier',
1792
                            'value' => 'newValue',
1793
                            'languageCode' => 'Klingon',
1794
                        ]
1795
                    ),
1796
                ],
1797
            ],
1798
            [
1799
                'Klingon',
1800
                [
1801
                    new Field(
1802
                        [
1803
                            'fieldDefIdentifier' => 'identifier',
1804
                            'value' => 'newValue',
1805
                            'languageCode' => 'eng-GB',
1806
                        ]
1807
                    ),
1808
                ],
1809
            ],
1810
        ];
1811
    }
1812
1813
    /**
1814
     * Test for the updateContent() method.
1815
     *
1816
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1817
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1818
     * @dataProvider providerForTestCreateContentWithInvalidLanguage
1819
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
1820
     * @expectedExceptionMessage Could not find 'Language' with identifier 'Klingon'
1821
     */
1822
    public function testCreateContentWithInvalidLanguage($mainLanguageCode, $structFields)
1823
    {
1824
        $repositoryMock = $this->getRepositoryMock();
1825
        $mockedService = $this->getPartlyMockedContentService();
1826
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1827
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1828
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1829
        $domainMapperMock = $this->getDomainMapperMock();
1830
        $contentType = new ContentType(
1831
            [
1832
                'id' => 123,
1833
                'fieldDefinitions' => [],
1834
            ]
1835
        );
1836
        $contentCreateStruct = new ContentCreateStruct(
1837
            [
1838
                'fields' => $structFields,
1839
                'mainLanguageCode' => $mainLanguageCode,
1840
                'contentType' => $contentType,
1841
                'alwaysAvailable' => false,
1842
                'ownerId' => 169,
1843
                'sectionId' => 1,
1844
            ]
1845
        );
1846
1847
        $languageHandlerMock->expects($this->any())
1848
            ->method('loadByLanguageCode')
1849
            ->with($this->isType('string'))
1850
            ->will(
1851
                $this->returnCallback(
1852 View Code Duplication
                    function ($languageCode) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1853
                        if ($languageCode === 'Klingon') {
1854
                            throw new NotFoundException('Language', 'Klingon');
1855
                        }
1856
1857
                        return new Language(['id' => 4242]);
1858
                    }
1859
                )
1860
            );
1861
1862
        $contentTypeServiceMock->expects($this->once())
1863
            ->method('loadContentType')
1864
            ->with($this->equalTo($contentType->id))
1865
            ->will($this->returnValue($contentType));
1866
1867
        $repositoryMock->expects($this->once())
1868
            ->method('getContentTypeService')
1869
            ->will($this->returnValue($contentTypeServiceMock));
1870
1871
        $that = $this;
1872
        $repositoryMock->expects($this->once())
1873
            ->method('canUser')
1874
            ->with(
1875
                $this->equalTo('content'),
1876
                $this->equalTo('create'),
1877
                $this->isInstanceOf(APIContentCreateStruct::class),
1878
                $this->equalTo([])
1879
            )->will(
1880
                $this->returnCallback(
1881
                    function () use ($that, $contentCreateStruct) {
1882
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1883
1884
                        return true;
1885
                    }
1886
                )
1887
            );
1888
1889
        $domainMapperMock->expects($this->once())
1890
            ->method('getUniqueHash')
1891
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1892
            ->will(
1893
                $this->returnCallback(
1894
                    function ($object) use ($that, $contentCreateStruct) {
1895
                        $that->assertEquals($contentCreateStruct, $object);
1896
1897
                        return 'hash';
1898
                    }
1899
                )
1900
            );
1901
1902
        $mockedService->createContent($contentCreateStruct, []);
1903
    }
1904
1905
    protected function assertForCreateContentContentValidationException(
1906
        $mainLanguageCode,
1907
        $structFields,
1908
        $fieldDefinitions = []
1909
    ) {
1910
        $repositoryMock = $this->getRepositoryMock();
1911
        $mockedService = $this->getPartlyMockedContentService(['loadContentByRemoteId']);
1912
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1913
        $contentType = new ContentType(
1914
            [
1915
                'id' => 123,
1916
                'fieldDefinitions' => $fieldDefinitions,
1917
            ]
1918
        );
1919
        $contentCreateStruct = new ContentCreateStruct(
1920
            [
1921
                'ownerId' => 169,
1922
                'alwaysAvailable' => false,
1923
                'remoteId' => 'faraday',
1924
                'mainLanguageCode' => $mainLanguageCode,
1925
                'fields' => $structFields,
1926
                'contentType' => $contentType,
1927
            ]
1928
        );
1929
1930
        $contentTypeServiceMock->expects($this->once())
1931
            ->method('loadContentType')
1932
            ->with($this->equalTo(123))
1933
            ->will($this->returnValue($contentType));
1934
1935
        $repositoryMock->expects($this->once())
1936
            ->method('getContentTypeService')
1937
            ->will($this->returnValue($contentTypeServiceMock));
1938
1939
        $repositoryMock->expects($this->once())
1940
            ->method('canUser')
1941
            ->with(
1942
                $this->equalTo('content'),
1943
                $this->equalTo('create'),
1944
                $this->isInstanceOf(get_class($contentCreateStruct)),
1945
                $this->equalTo([])
1946
            )->will($this->returnValue(true));
1947
1948
        $mockedService->expects($this->once())
1949
            ->method('loadContentByRemoteId')
1950
            ->with($contentCreateStruct->remoteId)
1951
            ->will(
1952
                $this->throwException(new NotFoundException('Content', 'faraday'))
1953
            );
1954
1955
        $mockedService->createContent($contentCreateStruct, []);
1956
    }
1957
1958 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition()
1959
    {
1960
        return [
1961
            [
1962
                'eng-GB',
1963
                [
1964
                    new Field(
1965
                        [
1966
                            'fieldDefIdentifier' => 'identifier',
1967
                            'value' => 'newValue',
1968
                            'languageCode' => 'eng-GB',
1969
                        ]
1970
                    ),
1971
                ],
1972
            ],
1973
        ];
1974
    }
1975
1976
    /**
1977
     * Test for the createContent() method.
1978
     *
1979
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1980
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1981
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1982
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition
1983
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentValidationException
1984
     * @expectedExceptionMessage Field definition 'identifier' does not exist in given ContentType
1985
     */
1986
    public function testCreateContentThrowsContentValidationExceptionFieldDefinition($mainLanguageCode, $structFields)
1987
    {
1988
        $this->assertForCreateContentContentValidationException(
1989
            $mainLanguageCode,
1990
            $structFields,
1991
            []
1992
        );
1993
    }
1994
1995 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionTranslation()
1996
    {
1997
        return [
1998
            [
1999
                'eng-GB',
2000
                [
2001
                    new Field(
2002
                        [
2003
                            'fieldDefIdentifier' => 'identifier',
2004
                            'value' => 'newValue',
2005
                            'languageCode' => 'eng-US',
2006
                        ]
2007
                    ),
2008
                ],
2009
            ],
2010
        ];
2011
    }
2012
2013
    /**
2014
     * Test for the createContent() method.
2015
     *
2016
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2017
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2018
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2019
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2020
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentValidationException
2021
     * @expectedExceptionMessage A value is set for non translatable field definition 'identifier' with language 'eng-US'
2022
     */
2023 View Code Duplication
    public function testCreateContentThrowsContentValidationExceptionTranslation($mainLanguageCode, $structFields)
2024
    {
2025
        $fieldDefinitions = [
2026
            new FieldDefinition(
2027
                [
2028
                    'id' => 'fieldDefinitionId1',
2029
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2030
                    'isTranslatable' => false,
2031
                    'identifier' => 'identifier',
2032
                    'isRequired' => false,
2033
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
2034
                ]
2035
            ),
2036
        ];
2037
2038
        $this->assertForCreateContentContentValidationException(
2039
            $mainLanguageCode,
2040
            $structFields,
2041
            $fieldDefinitions
2042
        );
2043
    }
2044
2045
    /**
2046
     * Asserts behaviour necessary for testing ContentFieldValidationException because of required
2047
     * field being empty.
2048
     *
2049
     * @param string $mainLanguageCode
2050
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2051
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2052
     *
2053
     * @return mixed
2054
     */
2055
    protected function assertForTestCreateContentRequiredField(
2056
        $mainLanguageCode,
2057
        array $structFields,
2058
        array $fieldDefinitions
2059
    ) {
2060
        $repositoryMock = $this->getRepositoryMock();
2061
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2062
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2063
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2064
        $fieldTypeServiceMock = $this->getFieldTypeServiceMock();
0 ignored issues
show
Unused Code introduced by
$fieldTypeServiceMock is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2065
        $domainMapperMock = $this->getDomainMapperMock();
2066
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2067
        $contentType = new ContentType(
2068
            [
2069
                'id' => 123,
2070
                'fieldDefinitions' => $fieldDefinitions,
2071
                'nameSchema' => '<nameSchema>',
2072
            ]
2073
        );
2074
        $contentCreateStruct = new ContentCreateStruct(
2075
            [
2076
                'fields' => $structFields,
2077
                'mainLanguageCode' => $mainLanguageCode,
2078
                'contentType' => $contentType,
2079
                'alwaysAvailable' => false,
2080
                'ownerId' => 169,
2081
                'sectionId' => 1,
2082
            ]
2083
        );
2084
2085
        $languageHandlerMock->expects($this->any())
2086
            ->method('loadByLanguageCode')
2087
            ->with($this->isType('string'))
2088
            ->will(
2089
                $this->returnCallback(
2090
                    function () {
2091
                        return new Language(['id' => 4242]);
2092
                    }
2093
                )
2094
            );
2095
2096
        $contentTypeServiceMock->expects($this->once())
2097
            ->method('loadContentType')
2098
            ->with($this->equalTo($contentType->id))
2099
            ->will($this->returnValue($contentType));
2100
2101
        $repositoryMock->expects($this->once())
2102
            ->method('getContentTypeService')
2103
            ->will($this->returnValue($contentTypeServiceMock));
2104
2105
        $that = $this;
2106
        $repositoryMock->expects($this->once())
2107
            ->method('canUser')
2108
            ->with(
2109
                $this->equalTo('content'),
2110
                $this->equalTo('create'),
2111
                $this->isInstanceOf(APIContentCreateStruct::class),
2112
                $this->equalTo([])
2113
            )->will(
2114
                $this->returnCallback(
2115
                    function () use ($that, $contentCreateStruct) {
2116
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2117
2118
                        return true;
2119
                    }
2120
                )
2121
            );
2122
2123
        $domainMapperMock->expects($this->once())
2124
            ->method('getUniqueHash')
2125
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2126
            ->will(
2127
                $this->returnCallback(
2128
                    function ($object) use ($that, $contentCreateStruct) {
2129
                        $that->assertEquals($contentCreateStruct, $object);
2130
2131
                        return 'hash';
2132
                    }
2133
                )
2134
            );
2135
2136
        $fieldTypeMock->expects($this->any())
2137
            ->method('acceptValue')
2138
            ->will(
2139
                $this->returnCallback(
2140
                    function ($valueString) {
2141
                        return new ValueStub($valueString);
2142
                    }
2143
                )
2144
            );
2145
2146
        $emptyValue = self::EMPTY_FIELD_VALUE;
2147
        $fieldTypeMock->expects($this->any())
2148
            ->method('isEmptyValue')
2149
            ->will(
2150
                $this->returnCallback(
2151
                    function (ValueStub $value) use ($emptyValue) {
2152
                        return $emptyValue === (string)$value;
2153
                    }
2154
                )
2155
            );
2156
2157
        $fieldTypeMock->expects($this->any())
2158
            ->method('validate')
2159
            ->will($this->returnValue([]));
2160
2161
        $this->getFieldTypeRegistryMock()->expects($this->any())
2162
            ->method('getFieldType')
2163
            ->will($this->returnValue($fieldTypeMock));
2164
2165
        return $contentCreateStruct;
2166
    }
2167
2168 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionRequiredField()
2169
    {
2170
        return [
2171
            [
2172
                'eng-US',
2173
                [
2174
                    new Field(
2175
                        [
2176
                            'fieldDefIdentifier' => 'identifier',
2177
                            'value' => self::EMPTY_FIELD_VALUE,
2178
                            'languageCode' => null,
2179
                        ]
2180
                    ),
2181
                ],
2182
                'identifier',
2183
                'eng-US',
2184
            ],
2185
        ];
2186
    }
2187
2188
    /**
2189
     * Test for the createContent() method.
2190
     *
2191
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2192
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2193
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2194
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionRequiredField
2195
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
2196
     */
2197
    public function testCreateContentRequiredField(
2198
        $mainLanguageCode,
2199
        $structFields,
2200
        $identifier,
2201
        $languageCode
2202
    ) {
2203
        $fieldDefinitions = [
2204
            new FieldDefinition(
2205
                [
2206
                    'id' => 'fieldDefinitionId',
2207
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2208
                    'isTranslatable' => true,
2209
                    'identifier' => 'identifier',
2210
                    'isRequired' => true,
2211
                    'defaultValue' => 'defaultValue',
2212
                ]
2213
            ),
2214
        ];
2215
        $contentCreateStruct = $this->assertForTestCreateContentRequiredField(
2216
            $mainLanguageCode,
2217
            $structFields,
2218
            $fieldDefinitions
2219
        );
2220
2221
        $mockedService = $this->getPartlyMockedContentService();
2222
2223
        try {
2224
            $mockedService->createContent($contentCreateStruct, []);
2225
        } catch (ContentValidationException $e) {
2226
            $this->assertEquals(
2227
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
2228
                $e->getMessage()
2229
            );
2230
2231
            throw $e;
2232
        }
2233
    }
2234
2235
    /**
2236
     * Asserts behaviour necessary for testing ContentFieldValidationException because of
2237
     * field not being valid.
2238
     *
2239
     * @param string $mainLanguageCode
2240
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2241
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2242
     *
2243
     * @return mixed
2244
     */
2245
    protected function assertForTestCreateContentThrowsContentFieldValidationException(
2246
        $mainLanguageCode,
2247
        array $structFields,
2248
        array $fieldDefinitions
2249
    ) {
2250
        $repositoryMock = $this->getRepositoryMock();
2251
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2252
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2253
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2254
        $fieldTypeServiceMock = $this->getFieldTypeServiceMock();
0 ignored issues
show
Unused Code introduced by
$fieldTypeServiceMock is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2255
        $domainMapperMock = $this->getDomainMapperMock();
2256
        $relationProcessorMock = $this->getRelationProcessorMock();
2257
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2258
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
2259
        $contentType = new ContentType(
2260
            [
2261
                'id' => 123,
2262
                'fieldDefinitions' => $fieldDefinitions,
2263
                'nameSchema' => '<nameSchema>',
2264
            ]
2265
        );
2266
        $contentCreateStruct = new ContentCreateStruct(
2267
            [
2268
                'fields' => $structFields,
2269
                'mainLanguageCode' => $mainLanguageCode,
2270
                'contentType' => $contentType,
2271
                'alwaysAvailable' => false,
2272
                'ownerId' => 169,
2273
                'sectionId' => 1,
2274
            ]
2275
        );
2276
2277
        $languageHandlerMock->expects($this->any())
2278
            ->method('loadByLanguageCode')
2279
            ->with($this->isType('string'))
2280
            ->will(
2281
                $this->returnCallback(
2282
                    function () {
2283
                        return new Language(['id' => 4242]);
2284
                    }
2285
                )
2286
            );
2287
2288
        $contentTypeServiceMock->expects($this->once())
2289
            ->method('loadContentType')
2290
            ->with($this->equalTo($contentType->id))
2291
            ->will($this->returnValue($contentType));
2292
2293
        $repositoryMock->expects($this->once())
2294
            ->method('getContentTypeService')
2295
            ->will($this->returnValue($contentTypeServiceMock));
2296
2297
        $that = $this;
2298
        $repositoryMock->expects($this->once())
2299
            ->method('canUser')
2300
            ->with(
2301
                $this->equalTo('content'),
2302
                $this->equalTo('create'),
2303
                $this->isInstanceOf(APIContentCreateStruct::class),
2304
                $this->equalTo([])
2305
            )->will(
2306
                $this->returnCallback(
2307
                    function () use ($that, $contentCreateStruct) {
2308
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2309
2310
                        return true;
2311
                    }
2312
                )
2313
            );
2314
2315
        $domainMapperMock->expects($this->once())
2316
            ->method('getUniqueHash')
2317
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2318
            ->will(
2319
                $this->returnCallback(
2320
                    function ($object) use ($that, $contentCreateStruct) {
2321
                        $that->assertEquals($contentCreateStruct, $object);
2322
2323
                        return 'hash';
2324
                    }
2325
                )
2326
            );
2327
2328
        $this->getFieldTypeRegistryMock()->expects($this->any())
2329
            ->method('getFieldType')
2330
            ->will($this->returnValue($fieldTypeMock));
2331
2332
        $relationProcessorMock
2333
            ->expects($this->any())
2334
            ->method('appendFieldRelations')
2335
            ->with(
2336
                $this->isType('array'),
2337
                $this->isType('array'),
2338
                $this->isInstanceOf(SPIFieldType::class),
2339
                $this->isInstanceOf(Value::class),
2340
                $this->anything()
2341
            );
2342
2343
        $fieldValues = $this->determineValuesForCreate(
2344
            $mainLanguageCode,
2345
            $structFields,
2346
            $fieldDefinitions,
2347
            $languageCodes
2348
        );
2349
        $allFieldErrors = [];
2350
        $validateCount = 0;
2351
        $emptyValue = self::EMPTY_FIELD_VALUE;
2352
        foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
2353
            foreach ($fieldValues[$fieldDefinition->identifier] as $languageCode => $value) {
2354
                $fieldTypeMock->expects($this->at($validateCount++))
2355
                    ->method('acceptValue')
2356
                    ->will(
2357
                        $this->returnCallback(
2358
                            function ($valueString) {
2359
                                return new ValueStub($valueString);
2360
                            }
2361
                        )
2362
                    );
2363
2364
                $fieldTypeMock->expects($this->at($validateCount++))
2365
                    ->method('isEmptyValue')
2366
                    ->will(
2367
                        $this->returnCallback(
2368
                            function (ValueStub $value) use ($emptyValue) {
2369
                                return $emptyValue === (string)$value;
2370
                            }
2371
                        )
2372
                    );
2373
2374
                if (self::EMPTY_FIELD_VALUE === (string)$value) {
2375
                    continue;
2376
                }
2377
2378
                $fieldTypeMock->expects($this->at($validateCount++))
2379
                    ->method('validate')
2380
                    ->with(
2381
                        $this->equalTo($fieldDefinition),
2382
                        $this->equalTo($value)
2383
                    )->will($this->returnArgument(1));
2384
2385
                $allFieldErrors[$fieldDefinition->id][$languageCode] = $value;
2386
            }
2387
        }
2388
2389
        return [$contentCreateStruct, $allFieldErrors];
2390
    }
2391
2392
    public function providerForTestCreateContentThrowsContentFieldValidationException()
2393
    {
2394
        return $this->providerForTestCreateContentNonRedundantFieldSetComplex();
2395
    }
2396
2397
    /**
2398
     * Test for the createContent() method.
2399
     *
2400
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2401
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2402
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2403
     * @dataProvider providerForTestCreateContentThrowsContentFieldValidationException
2404
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
2405
     * @expectedExceptionMessage Content fields did not validate
2406
     */
2407
    public function testCreateContentThrowsContentFieldValidationException($mainLanguageCode, $structFields)
2408
    {
2409
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
2410
        list($contentCreateStruct, $allFieldErrors) =
2411
            $this->assertForTestCreateContentThrowsContentFieldValidationException(
2412
                $mainLanguageCode,
2413
                $structFields,
2414
                $fieldDefinitions
2415
            );
2416
2417
        $mockedService = $this->getPartlyMockedContentService();
2418
2419
        try {
2420
            $mockedService->createContent($contentCreateStruct);
2421
        } catch (ContentFieldValidationException $e) {
2422
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
2423
            throw $e;
2424
        }
2425
    }
2426
2427
    /**
2428
     * Test for the createContent() method.
2429
     *
2430
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2431
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2432
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2433
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2434
     */
2435
    public function testCreateContentWithLocations()
2436
    {
2437
        $spiFields = [
2438
            new SPIField(
2439
                [
2440
                    'fieldDefinitionId' => 'fieldDefinitionId',
2441
                    'type' => 'fieldTypeIdentifier',
2442
                    'value' => 'defaultValue',
2443
                    'languageCode' => 'eng-US',
2444
                ]
2445
            ),
2446
        ];
2447
        $fieldDefinitions = [
2448
            new FieldDefinition(
2449
                [
2450
                    'id' => 'fieldDefinitionId',
2451
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2452
                    'isTranslatable' => false,
2453
                    'identifier' => 'identifier',
2454
                    'isRequired' => false,
2455
                    'defaultValue' => 'defaultValue',
2456
                ]
2457
            ),
2458
        ];
2459
2460
        // Set up a simple case that will pass
2461
        $locationCreateStruct1 = new LocationCreateStruct(['parentLocationId' => 321]);
2462
        $locationCreateStruct2 = new LocationCreateStruct(['parentLocationId' => 654]);
2463
        $locationCreateStructs = [$locationCreateStruct1, $locationCreateStruct2];
2464
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2465
            'eng-US',
2466
            [],
2467
            $spiFields,
2468
            $fieldDefinitions,
2469
            $locationCreateStructs,
2470
            false,
2471
            // Do not execute
2472
            false
2473
        );
2474
2475
        $repositoryMock = $this->getRepositoryMock();
2476
        $mockedService = $this->getPartlyMockedContentService();
2477
        $locationServiceMock = $this->getLocationServiceMock();
2478
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2479
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2480
        $domainMapperMock = $this->getDomainMapperMock();
2481
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2482
        $parentLocation = new Location(['contentInfo' => new ContentInfo(['sectionId' => 1])]);
2483
2484
        $locationServiceMock->expects($this->at(0))
2485
            ->method('loadLocation')
2486
            ->with($this->equalTo(321))
2487
            ->will($this->returnValue($parentLocation));
2488
2489
        $locationServiceMock->expects($this->at(1))
2490
            ->method('loadLocation')
2491
            ->with($this->equalTo(654))
2492
            ->will($this->returnValue($parentLocation));
2493
2494
        $repositoryMock->expects($this->atLeastOnce())
2495
            ->method('getLocationService')
2496
            ->will($this->returnValue($locationServiceMock));
2497
2498
        $domainMapperMock->expects($this->at(1))
2499
            ->method('buildSPILocationCreateStruct')
2500
            ->with(
2501
                $this->equalTo($locationCreateStruct1),
2502
                $this->equalTo($parentLocation),
2503
                $this->equalTo(true),
2504
                $this->equalTo(null),
2505
                $this->equalTo(null)
2506
            )->will($this->returnValue($spiLocationCreateStruct));
2507
2508
        $domainMapperMock->expects($this->at(2))
2509
            ->method('buildSPILocationCreateStruct')
2510
            ->with(
2511
                $this->equalTo($locationCreateStruct2),
2512
                $this->equalTo($parentLocation),
2513
                $this->equalTo(false),
2514
                $this->equalTo(null),
2515
                $this->equalTo(null)
2516
            )->will($this->returnValue($spiLocationCreateStruct));
2517
2518
        $spiContentCreateStruct = new SPIContentCreateStruct(
2519
            [
2520
                'name' => [],
2521
                'typeId' => 123,
2522
                'sectionId' => 1,
2523
                'ownerId' => 169,
2524
                'remoteId' => 'hash',
2525
                'fields' => $spiFields,
2526
                'modified' => time(),
2527
                'initialLanguageId' => 4242,
2528
                'locations' => [$spiLocationCreateStruct, $spiLocationCreateStruct],
2529
            ]
2530
        );
2531
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2532
        ++$spiContentCreateStruct2->modified;
2533
2534
        $spiContent = new SPIContent(
2535
            [
2536
                'versionInfo' => new SPIContent\VersionInfo(
2537
                    [
2538
                        'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
2539
                        'versionNo' => 7,
2540
                    ]
2541
                ),
2542
            ]
2543
        );
2544
2545
        $handlerMock->expects($this->once())
2546
            ->method('create')
2547
            ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
2548
            ->will($this->returnValue($spiContent));
2549
2550
        $domainMapperMock->expects($this->once())
2551
            ->method('buildContentDomainObject')
2552
            ->with(
2553
                $this->isInstanceOf(SPIContent::class),
2554
                $this->isInstanceOf(APIContentType::class)
2555
            );
2556
2557
        $repositoryMock->expects($this->once())->method('commit');
2558
2559
        // Execute
2560
        $mockedService->createContent($contentCreateStruct, $locationCreateStructs);
2561
    }
2562
2563
    /**
2564
     * Test for the createContent() method.
2565
     *
2566
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2567
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2568
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2569
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2570
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2571
     * @expectedExceptionMessage Multiple LocationCreateStructs with the same parent Location '321' are given
2572
     */
2573
    public function testCreateContentWithLocationsDuplicateUnderParent()
2574
    {
2575
        $fieldDefinitions = [
2576
            new FieldDefinition(
2577
                [
2578
                    'id' => 'fieldDefinitionId',
2579
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2580
                    'isTranslatable' => false,
2581
                    'identifier' => 'identifier',
2582
                    'isRequired' => false,
2583
                    'defaultValue' => 'defaultValue',
2584
                ]
2585
            ),
2586
        ];
2587
2588
        $repositoryMock = $this->getRepositoryMock();
2589
        $mockedService = $this->getPartlyMockedContentService();
2590
        $locationServiceMock = $this->getLocationServiceMock();
2591
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2592
        $domainMapperMock = $this->getDomainMapperMock();
2593
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2594
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2595
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2596
        $parentLocation = new Location(['id' => 321]);
2597
        $locationCreateStruct = new LocationCreateStruct(['parentLocationId' => 321]);
2598
        $locationCreateStructs = [$locationCreateStruct, clone $locationCreateStruct];
2599
        $contentType = new ContentType(
2600
            [
2601
                'id' => 123,
2602
                'fieldDefinitions' => $fieldDefinitions,
2603
                'nameSchema' => '<nameSchema>',
2604
            ]
2605
        );
2606
        $contentCreateStruct = new ContentCreateStruct(
2607
            [
2608
                'fields' => [],
2609
                'mainLanguageCode' => 'eng-US',
2610
                'contentType' => $contentType,
2611
                'alwaysAvailable' => false,
2612
                'ownerId' => 169,
2613
                'sectionId' => 1,
2614
            ]
2615
        );
2616
2617
        $languageHandlerMock->expects($this->any())
2618
            ->method('loadByLanguageCode')
2619
            ->with($this->isType('string'))
2620
            ->will(
2621
                $this->returnCallback(
2622
                    function () {
2623
                        return new Language(['id' => 4242]);
2624
                    }
2625
                )
2626
            );
2627
2628
        $contentTypeServiceMock->expects($this->once())
2629
            ->method('loadContentType')
2630
            ->with($this->equalTo($contentType->id))
2631
            ->will($this->returnValue($contentType));
2632
2633
        $repositoryMock->expects($this->once())
2634
            ->method('getContentTypeService')
2635
            ->will($this->returnValue($contentTypeServiceMock));
2636
2637
        $that = $this;
2638
        $repositoryMock->expects($this->once())
2639
            ->method('canUser')
2640
            ->with(
2641
                $this->equalTo('content'),
2642
                $this->equalTo('create'),
2643
                $this->isInstanceOf(APIContentCreateStruct::class),
2644
                $this->equalTo($locationCreateStructs)
2645
            )->will(
2646
                $this->returnCallback(
2647
                    function () use ($that, $contentCreateStruct) {
2648
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2649
2650
                        return true;
2651
                    }
2652
                )
2653
            );
2654
2655
        $domainMapperMock->expects($this->once())
2656
            ->method('getUniqueHash')
2657
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2658
            ->will(
2659
                $this->returnCallback(
2660
                    function ($object) use ($that, $contentCreateStruct) {
2661
                        $that->assertEquals($contentCreateStruct, $object);
2662
2663
                        return 'hash';
2664
                    }
2665
                )
2666
            );
2667
2668
        $locationServiceMock->expects($this->once())
2669
            ->method('loadLocation')
2670
            ->with($this->equalTo(321))
2671
            ->will($this->returnValue($parentLocation));
2672
2673
        $repositoryMock->expects($this->any())
2674
            ->method('getLocationService')
2675
            ->will($this->returnValue($locationServiceMock));
2676
2677
        $domainMapperMock->expects($this->any())
2678
            ->method('buildSPILocationCreateStruct')
2679
            ->with(
2680
                $this->equalTo($locationCreateStruct),
2681
                $this->equalTo($parentLocation),
2682
                $this->equalTo(true),
2683
                $this->equalTo(null),
2684
                $this->equalTo(null)
2685
            )->will($this->returnValue($spiLocationCreateStruct));
2686
2687
        $mockedService->createContent(
2688
            $contentCreateStruct,
2689
            $locationCreateStructs
2690
        );
2691
    }
2692
2693
    /**
2694
     * Test for the createContent() method.
2695
     *
2696
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2697
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2698
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2699
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2700
     */
2701
    public function testCreateContentObjectStates()
2702
    {
2703
        $spiFields = [
2704
            new SPIField(
2705
                [
2706
                    'fieldDefinitionId' => 'fieldDefinitionId',
2707
                    'type' => 'fieldTypeIdentifier',
2708
                    'value' => 'defaultValue',
2709
                    'languageCode' => 'eng-US',
2710
                ]
2711
            ),
2712
        ];
2713
        $fieldDefinitions = [
2714
            new FieldDefinition(
2715
                [
2716
                    'id' => 'fieldDefinitionId',
2717
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2718
                    'isTranslatable' => false,
2719
                    'identifier' => 'identifier',
2720
                    'isRequired' => false,
2721
                    'defaultValue' => 'defaultValue',
2722
                ]
2723
            ),
2724
        ];
2725
        $objectStateGroups = [
0 ignored issues
show
Unused Code introduced by
$objectStateGroups is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2726
            new SPIObjectStateGroup(['id' => 10]),
2727
            new SPIObjectStateGroup(['id' => 20]),
2728
        ];
2729
2730
        // Set up a simple case that will pass
2731
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2732
            'eng-US',
2733
            [],
2734
            $spiFields,
2735
            $fieldDefinitions,
2736
            [],
2737
            true,
2738
            // Do not execute
2739
            false
2740
        );
2741
        $timestamp = time();
2742
        $contentCreateStruct->modificationDate = new \DateTime("@{$timestamp}");
2743
2744
        $repositoryMock = $this->getRepositoryMock();
2745
        $mockedService = $this->getPartlyMockedContentService();
2746
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2747
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2748
        $domainMapperMock = $this->getDomainMapperMock();
2749
2750
        $this->mockGetDefaultObjectStates();
2751
        $this->mockSetDefaultObjectStates();
2752
2753
        $spiContentCreateStruct = new SPIContentCreateStruct(
2754
            [
2755
                'name' => [],
2756
                'typeId' => 123,
2757
                'sectionId' => 1,
2758
                'ownerId' => 169,
2759
                'remoteId' => 'hash',
2760
                'fields' => $spiFields,
2761
                'modified' => $timestamp,
2762
                'initialLanguageId' => 4242,
2763
                'locations' => [],
2764
            ]
2765
        );
2766
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2767
        ++$spiContentCreateStruct2->modified;
2768
2769
        $spiContent = new SPIContent(
2770
            [
2771
                'versionInfo' => new SPIContent\VersionInfo(
2772
                    [
2773
                        'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
2774
                        'versionNo' => 7,
2775
                    ]
2776
                ),
2777
            ]
2778
        );
2779
2780
        $handlerMock->expects($this->once())
2781
            ->method('create')
2782
            ->with($this->equalTo($spiContentCreateStruct))
2783
            ->will($this->returnValue($spiContent));
2784
2785
        $domainMapperMock->expects($this->once())
2786
            ->method('buildContentDomainObject')
2787
            ->with(
2788
                $this->isInstanceOf(SPIContent::class),
2789
                $this->isInstanceOf(APIContentType::class)
2790
            );
2791
2792
        $repositoryMock->expects($this->once())->method('commit');
2793
2794
        // Execute
2795
        $mockedService->createContent($contentCreateStruct, []);
2796
    }
2797
2798
    /**
2799
     * Test for the createContent() method.
2800
     *
2801
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2802
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2803
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2804
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2805
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2806
     * @expectedException \Exception
2807
     * @expectedExceptionMessage Store failed
2808
     */
2809
    public function testCreateContentWithRollback()
2810
    {
2811
        $fieldDefinitions = [
2812
            new FieldDefinition(
2813
                [
2814
                    'id' => 'fieldDefinitionId',
2815
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2816
                    'isTranslatable' => false,
2817
                    'identifier' => 'identifier',
2818
                    'isRequired' => false,
2819
                    'defaultValue' => 'defaultValue',
2820
                ]
2821
            ),
2822
        ];
2823
2824
        // Setup a simple case that will pass
2825
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2826
            'eng-US',
2827
            [],
2828
            [],
2829
            $fieldDefinitions,
2830
            [],
2831
            false,
2832
            // Do not execute test
2833
            false
2834
        );
2835
2836
        $repositoryMock = $this->getRepositoryMock();
2837
        $repositoryMock->expects($this->never())->method('commit');
2838
        $repositoryMock->expects($this->once())->method('rollback');
2839
2840
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
2841
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
2842
        $contentHandlerMock->expects($this->once())
2843
            ->method('create')
2844
            ->with($this->anything())
2845
            ->will($this->throwException(new \Exception('Store failed')));
2846
2847
        // Execute
2848
        $this->partlyMockedContentService->createContent($contentCreateStruct, []);
2849
    }
2850
2851
    public function providerForTestUpdateContentThrowsBadStateException()
2852
    {
2853
        return [
2854
            [VersionInfo::STATUS_PUBLISHED],
2855
            [VersionInfo::STATUS_ARCHIVED],
2856
        ];
2857
    }
2858
2859
    /**
2860
     * Test for the updateContent() method.
2861
     *
2862
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2863
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
2864
     * @dataProvider providerForTestUpdateContentThrowsBadStateException
2865
     */
2866
    public function testUpdateContentThrowsBadStateException($status)
2867
    {
2868
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
2869
        $contentUpdateStruct = new ContentUpdateStruct();
2870
        $versionInfo = new VersionInfo(
2871
            [
2872
                'contentInfo' => new ContentInfo(['id' => 42]),
2873
                'versionNo' => 7,
2874
                'status' => $status,
2875
            ]
2876
        );
2877
        $content = new Content(
2878
            [
2879
                'versionInfo' => $versionInfo,
2880
                'internalFields' => [],
2881
            ]
2882
        );
2883
2884
        $mockedService->expects($this->once())
2885
            ->method('loadContent')
2886
            ->with(
2887
                $this->equalTo(42),
2888
                $this->equalTo(null),
2889
                $this->equalTo(7)
2890
            )->will(
2891
                $this->returnValue($content)
2892
            );
2893
2894
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2895
    }
2896
2897
    /**
2898
     * Test for the updateContent() method.
2899
     *
2900
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2901
     * @expectedException \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2902
     */
2903
    public function testUpdateContentThrowsUnauthorizedException()
2904
    {
2905
        $permissionResolverMock = $this->getPermissionResolverMock();
2906
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
2907
        $contentUpdateStruct = new ContentUpdateStruct();
2908
        $versionInfo = new VersionInfo(
2909
            [
2910
                'contentInfo' => new ContentInfo(['id' => 42]),
2911
                'versionNo' => 7,
2912
                'status' => VersionInfo::STATUS_DRAFT,
2913
            ]
2914
        );
2915
        $content = new Content(
2916
            [
2917
                'versionInfo' => $versionInfo,
2918
                'internalFields' => [],
2919
            ]
2920
        );
2921
2922
        $mockedService->expects($this->once())
2923
            ->method('loadContent')
2924
            ->with(
2925
                $this->equalTo(42),
2926
                $this->equalTo(null),
2927
                $this->equalTo(7)
2928
            )->will(
2929
                $this->returnValue($content)
2930
            );
2931
2932
        $permissionResolverMock->expects($this->once())
2933
            ->method('canUser')
2934
            ->with(
2935
                $this->equalTo('content'),
2936
                $this->equalTo('edit'),
2937
                $this->equalTo($content),
2938
                $this->isType('array')
2939
            )->will($this->returnValue(false));
2940
2941
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2942
    }
2943
2944
    /**
2945
     * @param string $initialLanguageCode
2946
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2947
     * @param string[] $existingLanguages
2948
     *
2949
     * @return string[]
2950
     */
2951
    protected function determineLanguageCodesForUpdate($initialLanguageCode, array $structFields, $existingLanguages)
2952
    {
2953
        $languageCodes = array_fill_keys($existingLanguages, true);
2954
        if ($initialLanguageCode !== null) {
2955
            $languageCodes[$initialLanguageCode] = true;
2956
        }
2957
2958
        foreach ($structFields as $field) {
2959
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
2960
                continue;
2961
            }
2962
2963
            $languageCodes[$field->languageCode] = true;
2964
        }
2965
2966
        return array_keys($languageCodes);
2967
    }
2968
2969
    /**
2970
     * @param string $initialLanguageCode
2971
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2972
     * @param string $mainLanguageCode
2973
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2974
     *
2975
     * @return array
2976
     */
2977
    protected function mapStructFieldsForUpdate($initialLanguageCode, $structFields, $mainLanguageCode, $fieldDefinitions)
2978
    {
2979
        $initialLanguageCode = $initialLanguageCode ?: $mainLanguageCode;
2980
2981
        $mappedFieldDefinitions = [];
2982
        foreach ($fieldDefinitions as $fieldDefinition) {
2983
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
2984
        }
2985
2986
        $mappedStructFields = [];
2987
        foreach ($structFields as $structField) {
2988
            $identifier = $structField->fieldDefIdentifier;
2989
2990
            if ($structField->languageCode !== null) {
2991
                $languageCode = $structField->languageCode;
2992
            } elseif ($mappedFieldDefinitions[$identifier]->isTranslatable) {
2993
                $languageCode = $initialLanguageCode;
2994
            } else {
2995
                $languageCode = $mainLanguageCode;
2996
            }
2997
2998
            $mappedStructFields[$identifier][$languageCode] = (string)$structField->value;
2999
        }
3000
3001
        return $mappedStructFields;
3002
    }
3003
3004
    /**
3005
     * Returns full, possibly redundant array of field values, indexed by field definition
3006
     * identifier and language code.
3007
     *
3008
     * @param string $initialLanguageCode
3009
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
3010
     * @param \eZ\Publish\Core\Repository\Values\Content\Content $content
3011
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
3012
     * @param array $languageCodes
3013
     *
3014
     * @return array
3015
     */
3016
    protected function determineValuesForUpdate(
3017
        $initialLanguageCode,
3018
        array $structFields,
3019
        Content $content,
3020
        array $fieldDefinitions,
3021
        array $languageCodes
3022
    ) {
3023
        $mainLanguageCode = $content->versionInfo->contentInfo->mainLanguageCode;
3024
3025
        $mappedStructFields = $this->mapStructFieldsForUpdate(
3026
            $initialLanguageCode,
3027
            $structFields,
3028
            $mainLanguageCode,
3029
            $fieldDefinitions
3030
        );
3031
3032
        $values = [];
3033
3034
        foreach ($fieldDefinitions as $fieldDefinition) {
3035
            $identifier = $fieldDefinition->identifier;
3036
            foreach ($languageCodes as $languageCode) {
3037 View Code Duplication
                if (!$fieldDefinition->isTranslatable) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3038
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
3039
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
3040
                    } else {
3041
                        $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$mainLanguageCode];
3042
                    }
3043
                    continue;
3044
                }
3045
3046 View Code Duplication
                if (isset($mappedStructFields[$identifier][$languageCode])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3047
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
3048
                    continue;
3049
                }
3050
3051
                if (isset($content->fields[$identifier][$languageCode])) {
3052
                    $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$languageCode];
3053
                    continue;
3054
                }
3055
3056
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
3057
            }
3058
        }
3059
3060
        return $this->stubValues($values);
3061
    }
3062
3063
    protected function stubValues(array $fieldValues)
3064
    {
3065
        foreach ($fieldValues as &$languageValues) {
3066
            foreach ($languageValues as &$value) {
3067
                $value = new ValueStub($value);
3068
            }
3069
        }
3070
3071
        return $fieldValues;
3072
    }
3073
3074
    /**
3075
     * Asserts that calling updateContent() with given API field set causes calling
3076
     * Handler::updateContent() with given SPI field set.
3077
     *
3078
     * @param string $initialLanguageCode
3079
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
3080
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
3081
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $existingFields
3082
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
3083
     * @param bool $execute
3084
     *
3085
     * @return mixed
3086
     */
3087
    protected function assertForTestUpdateContentNonRedundantFieldSet(
3088
        $initialLanguageCode,
3089
        array $structFields,
3090
        array $spiFields,
3091
        array $existingFields,
3092
        array $fieldDefinitions,
3093
        $execute = true
3094
    ) {
3095
        $repositoryMock = $this->getRepositoryMock();
3096
        $permissionResolverMock = $this->getPermissionResolverMock();
3097
        $mockedService = $this->getPartlyMockedContentService(['loadContent', 'loadRelations']);
3098
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
3099
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
3100
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
3101
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
3102
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
3103
        $fieldTypeServiceMock = $this->getFieldTypeServiceMock();
0 ignored issues
show
Unused Code introduced by
$fieldTypeServiceMock is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3104
        $domainMapperMock = $this->getDomainMapperMock();
3105
        $relationProcessorMock = $this->getRelationProcessorMock();
3106
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
3107
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
3108
        $existingLanguageCodes = array_map(
3109
            function (Field $field) {
3110
                return $field->languageCode;
3111
            },
3112
            $existingFields
3113
        );
3114
        $languageCodes = $this->determineLanguageCodesForUpdate(
3115
            $initialLanguageCode,
3116
            $structFields,
3117
            $existingLanguageCodes
3118
        );
3119
        $versionInfo = new VersionInfo(
3120
            [
3121
                'contentInfo' => new ContentInfo(
3122
                    [
3123
                        'id' => 42,
3124
                        'contentTypeId' => 24,
3125
                        'mainLanguageCode' => 'eng-GB',
3126
                    ]
3127
                ),
3128
                'versionNo' => 7,
3129
                'languageCodes' => $existingLanguageCodes,
3130
                'status' => VersionInfo::STATUS_DRAFT,
3131
            ]
3132
        );
3133
        $content = new Content(
3134
            [
3135
                'versionInfo' => $versionInfo,
3136
                'internalFields' => $existingFields,
3137
            ]
3138
        );
3139
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
3140
3141
        $languageHandlerMock->expects($this->any())
3142
            ->method('loadByLanguageCode')
3143
            ->with($this->isType('string'))
3144
            ->will(
3145
                $this->returnCallback(
3146
                    function () {
3147
                        return new Language(['id' => 4242]);
3148
                    }
3149
                )
3150
            );
3151
3152
        $mockedService->expects($this->once())
3153
            ->method('loadContent')
3154
            ->with(
3155
                $this->equalTo(42),
3156
                $this->equalTo(null),
3157
                $this->equalTo(7)
3158
            )->will(
3159
                $this->returnValue($content)
3160
            );
3161
3162
        $repositoryMock->expects($this->once())->method('beginTransaction');
3163
3164
        $permissionResolverMock->expects($this->once())
3165
            ->method('canUser')
3166
            ->with(
3167
                $this->equalTo('content'),
3168
                $this->equalTo('edit'),
3169
                $this->equalTo($content),
3170
                $this->isType('array')
3171
            )->will($this->returnValue(true));
3172
3173
        $contentTypeServiceMock->expects($this->once())
3174
            ->method('loadContentType')
3175
            ->with($this->equalTo(24))
3176
            ->will($this->returnValue($contentType));
3177
3178
        $repositoryMock->expects($this->once())
3179
            ->method('getContentTypeService')
3180
            ->will($this->returnValue($contentTypeServiceMock));
3181
3182
        $repositoryMock->expects($this->once())
3183
            ->method('getCurrentUserReference')
3184
            ->will($this->returnValue(new UserReference(169)));
3185
3186
        $fieldTypeMock->expects($this->any())
3187
            ->method('acceptValue')
3188
            ->will(
3189
                $this->returnCallback(
3190
                    function ($valueString) {
3191
                        return new ValueStub($valueString);
3192
                    }
3193
                )
3194
            );
3195
3196
        $emptyValue = self::EMPTY_FIELD_VALUE;
3197
        $fieldTypeMock->expects($this->any())
3198
            ->method('toPersistenceValue')
3199
            ->will(
3200
                $this->returnCallback(
3201
                    function (ValueStub $value) {
3202
                        return (string)$value;
3203
                    }
3204
                )
3205
            );
3206
3207
        $fieldTypeMock->expects($this->any())
3208
            ->method('isEmptyValue')
3209
            ->will(
3210
                $this->returnCallback(
3211
                    function (ValueStub $value) use ($emptyValue) {
3212
                        return $emptyValue === (string)$value;
3213
                    }
3214
                )
3215
            );
3216
3217
        $fieldTypeMock->expects($this->any())
3218
            ->method('validate')
3219
            ->will($this->returnValue([]));
3220
3221
        $this->getFieldTypeRegistryMock()->expects($this->any())
3222
            ->method('getFieldType')
3223
            ->will($this->returnValue($fieldTypeMock));
3224
3225
        $relationProcessorMock
3226
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
3227
            ->method('appendFieldRelations')
3228
            ->with(
3229
                $this->isType('array'),
3230
                $this->isType('array'),
3231
                $this->isInstanceOf(SPIFieldType::class),
3232
                $this->isInstanceOf(Value::class),
3233
                $this->anything()
3234
            );
3235
3236
        $values = $this->determineValuesForUpdate(
3237
            $initialLanguageCode,
3238
            $structFields,
3239
            $content,
3240
            $fieldDefinitions,
3241
            $languageCodes
3242
        );
3243
        $nameSchemaServiceMock->expects($this->once())
3244
            ->method('resolveNameSchema')
3245
            ->with(
3246
                $this->equalTo($content),
3247
                $this->equalTo($values),
3248
                $this->equalTo($languageCodes)
3249
            )->will($this->returnValue([]));
3250
3251
        $existingRelations = ['RELATIONS!!!'];
3252
        $mockedService->expects($this->once())
3253
            ->method('loadRelations')
3254
            ->with($content->versionInfo)
3255
            ->will($this->returnValue($existingRelations));
3256
        $relationProcessorMock->expects($this->any())
3257
            ->method('processFieldRelations')
3258
            ->with(
3259
                $this->isType('array'),
3260
                $this->equalTo(42),
3261
                $this->isType('int'),
3262
                $this->equalTo($contentType),
3263
                $this->equalTo($existingRelations)
3264
            );
3265
3266
        $contentUpdateStruct = new ContentUpdateStruct(
3267
            [
3268
                'fields' => $structFields,
3269
                'initialLanguageCode' => $initialLanguageCode,
3270
            ]
3271
        );
3272
3273
        if ($execute) {
3274
            $spiContentUpdateStruct = new SPIContentUpdateStruct(
3275
                [
3276
                    'creatorId' => 169,
3277
                    'fields' => $spiFields,
3278
                    'modificationDate' => time(),
3279
                    'initialLanguageId' => 4242,
3280
                ]
3281
            );
3282
3283
            // During code coverage runs, timestamp might differ 1-3 seconds
3284
            $spiContentUpdateStructTs1 = clone $spiContentUpdateStruct;
3285
            ++$spiContentUpdateStructTs1->modificationDate;
3286
3287
            $spiContentUpdateStructTs2 = clone $spiContentUpdateStructTs1;
3288
            ++$spiContentUpdateStructTs2->modificationDate;
3289
3290
            $spiContentUpdateStructTs3 = clone $spiContentUpdateStructTs2;
3291
            ++$spiContentUpdateStructTs3->modificationDate;
3292
3293
            $spiContent = new SPIContent(
3294
                [
3295
                    'versionInfo' => new SPIContent\VersionInfo(
3296
                        [
3297
                            'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
3298
                            'versionNo' => 7,
3299
                        ]
3300
                    ),
3301
                ]
3302
            );
3303
3304
            $contentHandlerMock->expects($this->once())
3305
                ->method('updateContent')
3306
                ->with(
3307
                    42,
3308
                    7,
3309
                    $this->logicalOr($spiContentUpdateStruct, $spiContentUpdateStructTs1, $spiContentUpdateStructTs2, $spiContentUpdateStructTs3)
3310
                )
3311
                ->will($this->returnValue($spiContent));
3312
3313
            $repositoryMock->expects($this->once())->method('commit');
3314
            $domainMapperMock->expects($this->once())
3315
                ->method('buildContentDomainObject')
3316
                ->with(
3317
                    $this->isInstanceOf(SPIContent::class),
3318
                    $this->isInstanceOf(APIContentType::class)
3319
                );
3320
3321
            $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
3322
        }
3323
3324
        return [$content->versionInfo, $contentUpdateStruct];
3325
    }
3326
3327
    public function providerForTestUpdateContentNonRedundantFieldSet1()
3328
    {
3329
        $spiFields = [
3330
            new SPIField(
3331
                [
3332
                    'id' => '100',
3333
                    'fieldDefinitionId' => 'fieldDefinitionId',
3334
                    'type' => 'fieldTypeIdentifier',
3335
                    'value' => 'newValue',
3336
                    'languageCode' => 'eng-GB',
3337
                    'versionNo' => 7,
3338
                ]
3339
            ),
3340
        ];
3341
3342
        return [
3343
            // With languages set
3344
            [
3345
                'eng-GB',
3346
                [
3347
                    new Field(
3348
                        [
3349
                            'fieldDefIdentifier' => 'identifier',
3350
                            'value' => 'newValue',
3351
                            'languageCode' => 'eng-GB',
3352
                        ]
3353
                    ),
3354
                ],
3355
                $spiFields,
3356
            ],
3357
            // Without languages set
3358
            [
3359
                null,
3360
                [
3361
                    new Field(
3362
                        [
3363
                            'fieldDefIdentifier' => 'identifier',
3364
                            'value' => 'newValue',
3365
                            'languageCode' => null,
3366
                        ]
3367
                    ),
3368
                ],
3369
                $spiFields,
3370
            ],
3371
            // Adding new language without fields
3372
            [
3373
                'eng-US',
3374
                [],
3375
                [],
3376
            ],
3377
        ];
3378
    }
3379
3380
    /**
3381
     * Test for the updateContent() method.
3382
     *
3383
     * Testing the simplest use case.
3384
     *
3385
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3386
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3387
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3388
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet1
3389
     */
3390 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet1($initialLanguageCode, $structFields, $spiFields)
3391
    {
3392
        $existingFields = [
3393
            new Field(
3394
                [
3395
                    'id' => '100',
3396
                    'fieldDefIdentifier' => 'identifier',
3397
                    'value' => 'initialValue',
3398
                    'languageCode' => 'eng-GB',
3399
                ]
3400
            ),
3401
        ];
3402
3403
        $fieldDefinitions = [
3404
            new FieldDefinition(
3405
                [
3406
                    'id' => 'fieldDefinitionId',
3407
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3408
                    'isTranslatable' => false,
3409
                    'identifier' => 'identifier',
3410
                    'isRequired' => false,
3411
                    'defaultValue' => 'defaultValue',
3412
                ]
3413
            ),
3414
        ];
3415
3416
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3417
            $initialLanguageCode,
3418
            $structFields,
3419
            $spiFields,
3420
            $existingFields,
3421
            $fieldDefinitions
3422
        );
3423
    }
3424
3425
    public function providerForTestUpdateContentNonRedundantFieldSet2()
3426
    {
3427
        $spiFields0 = [
3428
            new SPIField(
3429
                [
3430
                    'id' => '100',
3431
                    'fieldDefinitionId' => 'fieldDefinitionId',
3432
                    'type' => 'fieldTypeIdentifier',
3433
                    'value' => 'newValue',
3434
                    'languageCode' => 'eng-GB',
3435
                    'versionNo' => 7,
3436
                ]
3437
            ),
3438
        ];
3439
        $spiFields1 = [
3440
            new SPIField(
3441
                [
3442
                    'id' => null,
3443
                    'fieldDefinitionId' => 'fieldDefinitionId',
3444
                    'type' => 'fieldTypeIdentifier',
3445
                    'value' => 'newValue',
3446
                    'languageCode' => 'eng-US',
3447
                    'versionNo' => 7,
3448
                ]
3449
            ),
3450
        ];
3451
        $spiFields2 = [
3452
            new SPIField(
3453
                [
3454
                    'id' => 100,
3455
                    'fieldDefinitionId' => 'fieldDefinitionId',
3456
                    'type' => 'fieldTypeIdentifier',
3457
                    'value' => 'newValue2',
3458
                    'languageCode' => 'eng-GB',
3459
                    'versionNo' => 7,
3460
                ]
3461
            ),
3462
            new SPIField(
3463
                [
3464
                    'id' => null,
3465
                    'fieldDefinitionId' => 'fieldDefinitionId',
3466
                    'type' => 'fieldTypeIdentifier',
3467
                    'value' => 'newValue1',
3468
                    'languageCode' => 'eng-US',
3469
                    'versionNo' => 7,
3470
                ]
3471
            ),
3472
        ];
3473
3474
        return [
3475
            // 0. With languages set
3476
            [
3477
                'eng-GB',
3478
                [
3479
                    new Field(
3480
                        [
3481
                            'fieldDefIdentifier' => 'identifier',
3482
                            'value' => 'newValue',
3483
                            'languageCode' => 'eng-GB',
3484
                        ]
3485
                    ),
3486
                ],
3487
                $spiFields0,
3488
            ],
3489
            // 1. Without languages set
3490
            [
3491
                null,
3492
                [
3493
                    new Field(
3494
                        [
3495
                            'fieldDefIdentifier' => 'identifier',
3496
                            'value' => 'newValue',
3497
                            'languageCode' => null,
3498
                        ]
3499
                    ),
3500
                ],
3501
                $spiFields0,
3502
            ],
3503
            // 2. New language with language set
3504
            [
3505
                'eng-GB',
3506
                [
3507
                    new Field(
3508
                        [
3509
                            'fieldDefIdentifier' => 'identifier',
3510
                            'value' => 'newValue',
3511
                            'languageCode' => 'eng-US',
3512
                        ]
3513
                    ),
3514
                ],
3515
                $spiFields1,
3516
            ],
3517
            // 3. New language without language set
3518
            [
3519
                'eng-US',
3520
                [
3521
                    new Field(
3522
                        [
3523
                            'fieldDefIdentifier' => 'identifier',
3524
                            'value' => 'newValue',
3525
                            'languageCode' => null,
3526
                        ]
3527
                    ),
3528
                ],
3529
                $spiFields1,
3530
            ],
3531
            // 4. New language and existing language with language set
3532
            [
3533
                'eng-GB',
3534
                [
3535
                    new Field(
3536
                        [
3537
                            'fieldDefIdentifier' => 'identifier',
3538
                            'value' => 'newValue1',
3539
                            'languageCode' => 'eng-US',
3540
                        ]
3541
                    ),
3542
                    new Field(
3543
                        [
3544
                            'fieldDefIdentifier' => 'identifier',
3545
                            'value' => 'newValue2',
3546
                            'languageCode' => 'eng-GB',
3547
                        ]
3548
                    ),
3549
                ],
3550
                $spiFields2,
3551
            ],
3552
            // 5. New language and existing language without language set
3553
            [
3554
                'eng-US',
3555
                [
3556
                    new Field(
3557
                        [
3558
                            'fieldDefIdentifier' => 'identifier',
3559
                            'value' => 'newValue1',
3560
                            'languageCode' => null,
3561
                        ]
3562
                    ),
3563
                    new Field(
3564
                        [
3565
                            'fieldDefIdentifier' => 'identifier',
3566
                            'value' => 'newValue2',
3567
                            'languageCode' => 'eng-GB',
3568
                        ]
3569
                    ),
3570
                ],
3571
                $spiFields2,
3572
            ],
3573
            // 6. Adding new language without fields
3574
            [
3575
                'eng-US',
3576
                [],
3577
                [
3578
                    new SPIField(
3579
                        [
3580
                            'id' => null,
3581
                            'fieldDefinitionId' => 'fieldDefinitionId',
3582
                            'type' => 'fieldTypeIdentifier',
3583
                            'value' => 'defaultValue',
3584
                            'languageCode' => 'eng-US',
3585
                            'versionNo' => 7,
3586
                        ]
3587
                    ),
3588
                ],
3589
            ],
3590
        ];
3591
    }
3592
3593
    /**
3594
     * Test for the updateContent() method.
3595
     *
3596
     * Testing with translatable field.
3597
     *
3598
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3599
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3600
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3601
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet2
3602
     */
3603 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet2($initialLanguageCode, $structFields, $spiFields)
3604
    {
3605
        $existingFields = [
3606
            new Field(
3607
                [
3608
                    'id' => '100',
3609
                    'fieldDefIdentifier' => 'identifier',
3610
                    'value' => 'initialValue',
3611
                    'languageCode' => 'eng-GB',
3612
                ]
3613
            ),
3614
        ];
3615
3616
        $fieldDefinitions = [
3617
            new FieldDefinition(
3618
                [
3619
                    'id' => 'fieldDefinitionId',
3620
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3621
                    'isTranslatable' => true,
3622
                    'identifier' => 'identifier',
3623
                    'isRequired' => false,
3624
                    'defaultValue' => 'defaultValue',
3625
                ]
3626
            ),
3627
        ];
3628
3629
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3630
            $initialLanguageCode,
3631
            $structFields,
3632
            $spiFields,
3633
            $existingFields,
3634
            $fieldDefinitions
3635
        );
3636
    }
3637
3638
    public function providerForTestUpdateContentNonRedundantFieldSet3()
3639
    {
3640
        $spiFields0 = [
3641
            new SPIField(
3642
                [
3643
                    'id' => null,
3644
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3645
                    'type' => 'fieldTypeIdentifier',
3646
                    'value' => 'newValue1',
3647
                    'languageCode' => 'eng-US',
3648
                    'versionNo' => 7,
3649
                ]
3650
            ),
3651
        ];
3652
        $spiFields1 = [
3653
            new SPIField(
3654
                [
3655
                    'id' => 100,
3656
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3657
                    'type' => 'fieldTypeIdentifier',
3658
                    'value' => 'newValue2',
3659
                    'languageCode' => 'eng-GB',
3660
                    'versionNo' => 7,
3661
                ]
3662
            ),
3663
            new SPIField(
3664
                [
3665
                    'id' => null,
3666
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3667
                    'type' => 'fieldTypeIdentifier',
3668
                    'value' => 'newValue1',
3669
                    'languageCode' => 'eng-US',
3670
                    'versionNo' => 7,
3671
                ]
3672
            ),
3673
        ];
3674
        $spiFields2 = [
3675
            new SPIField(
3676
                [
3677
                    'id' => 100,
3678
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3679
                    'type' => 'fieldTypeIdentifier',
3680
                    'value' => 'newValue2',
3681
                    'languageCode' => 'eng-GB',
3682
                    'versionNo' => 7,
3683
                ]
3684
            ),
3685
            new SPIField(
3686
                [
3687
                    'id' => null,
3688
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3689
                    'type' => 'fieldTypeIdentifier',
3690
                    'value' => 'newValue1',
3691
                    'languageCode' => 'eng-US',
3692
                    'versionNo' => 7,
3693
                ]
3694
            ),
3695
            new SPIField(
3696
                [
3697
                    'id' => 101,
3698
                    'fieldDefinitionId' => 'fieldDefinitionId2',
3699
                    'type' => 'fieldTypeIdentifier',
3700
                    'value' => 'newValue3',
3701
                    'languageCode' => 'eng-GB',
3702
                    'versionNo' => 7,
3703
                ]
3704
            ),
3705
        ];
3706
        $spiFields3 = [
3707
            new SPIField(
3708
                [
3709
                    'id' => null,
3710
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3711
                    'type' => 'fieldTypeIdentifier',
3712
                    'value' => 'defaultValue1',
3713
                    'languageCode' => 'eng-US',
3714
                    'versionNo' => 7,
3715
                ]
3716
            ),
3717
        ];
3718
3719
        return [
3720
            // 0. ew language with language set
3721
            [
3722
                'eng-US',
3723
                [
3724
                    new Field(
3725
                        [
3726
                            'fieldDefIdentifier' => 'identifier1',
3727
                            'value' => 'newValue1',
3728
                            'languageCode' => 'eng-US',
3729
                        ]
3730
                    ),
3731
                ],
3732
                $spiFields0,
3733
            ],
3734
            // 1. New language without language set
3735
            [
3736
                'eng-US',
3737
                [
3738
                    new Field(
3739
                        [
3740
                            'fieldDefIdentifier' => 'identifier1',
3741
                            'value' => 'newValue1',
3742
                            'languageCode' => null,
3743
                        ]
3744
                    ),
3745
                ],
3746
                $spiFields0,
3747
            ],
3748
            // 2. New language and existing language with language set
3749
            [
3750
                'eng-US',
3751
                [
3752
                    new Field(
3753
                        [
3754
                            'fieldDefIdentifier' => 'identifier1',
3755
                            'value' => 'newValue1',
3756
                            'languageCode' => 'eng-US',
3757
                        ]
3758
                    ),
3759
                    new Field(
3760
                        [
3761
                            'fieldDefIdentifier' => 'identifier1',
3762
                            'value' => 'newValue2',
3763
                            'languageCode' => 'eng-GB',
3764
                        ]
3765
                    ),
3766
                ],
3767
                $spiFields1,
3768
            ],
3769
            // 3. New language and existing language without language set
3770
            [
3771
                'eng-US',
3772
                [
3773
                    new Field(
3774
                        [
3775
                            'fieldDefIdentifier' => 'identifier1',
3776
                            'value' => 'newValue1',
3777
                            'languageCode' => null,
3778
                        ]
3779
                    ),
3780
                    new Field(
3781
                        [
3782
                            'fieldDefIdentifier' => 'identifier1',
3783
                            'value' => 'newValue2',
3784
                            'languageCode' => 'eng-GB',
3785
                        ]
3786
                    ),
3787
                ],
3788
                $spiFields1,
3789
            ],
3790
            // 4. New language and existing language with untranslatable field, with language set
3791
            [
3792
                'eng-US',
3793
                [
3794
                    new Field(
3795
                        [
3796
                            'fieldDefIdentifier' => 'identifier1',
3797
                            'value' => 'newValue1',
3798
                            'languageCode' => 'eng-US',
3799
                        ]
3800
                    ),
3801
                    new Field(
3802
                        [
3803
                            'fieldDefIdentifier' => 'identifier1',
3804
                            'value' => 'newValue2',
3805
                            'languageCode' => 'eng-GB',
3806
                        ]
3807
                    ),
3808
                    new Field(
3809
                        [
3810
                            'fieldDefIdentifier' => 'identifier2',
3811
                            'value' => 'newValue3',
3812
                            'languageCode' => 'eng-GB',
3813
                        ]
3814
                    ),
3815
                ],
3816
                $spiFields2,
3817
            ],
3818
            // 5. New language and existing language with untranslatable field, without language set
3819
            [
3820
                'eng-US',
3821
                [
3822
                    new Field(
3823
                        [
3824
                            'fieldDefIdentifier' => 'identifier1',
3825
                            'value' => 'newValue1',
3826
                            'languageCode' => null,
3827
                        ]
3828
                    ),
3829
                    new Field(
3830
                        [
3831
                            'fieldDefIdentifier' => 'identifier1',
3832
                            'value' => 'newValue2',
3833
                            'languageCode' => 'eng-GB',
3834
                        ]
3835
                    ),
3836
                    new Field(
3837
                        [
3838
                            'fieldDefIdentifier' => 'identifier2',
3839
                            'value' => 'newValue3',
3840
                            'languageCode' => null,
3841
                        ]
3842
                    ),
3843
                ],
3844
                $spiFields2,
3845
            ],
3846
            // 6. Adding new language without fields
3847
            [
3848
                'eng-US',
3849
                [],
3850
                $spiFields3,
3851
            ],
3852
        ];
3853
    }
3854
3855
    /**
3856
     * Test for the updateContent() method.
3857
     *
3858
     * Testing with new language and untranslatable field.
3859
     *
3860
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3861
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3862
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3863
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet3
3864
     */
3865
    public function testUpdateContentNonRedundantFieldSet3($initialLanguageCode, $structFields, $spiFields)
3866
    {
3867
        $existingFields = [
3868
            new Field(
3869
                [
3870
                    'id' => '100',
3871
                    'fieldDefIdentifier' => 'identifier1',
3872
                    'value' => 'initialValue1',
3873
                    'languageCode' => 'eng-GB',
3874
                ]
3875
            ),
3876
            new Field(
3877
                [
3878
                    'id' => '101',
3879
                    'fieldDefIdentifier' => 'identifier2',
3880
                    'value' => 'initialValue2',
3881
                    'languageCode' => 'eng-GB',
3882
                ]
3883
            ),
3884
        ];
3885
3886
        $fieldDefinitions = [
3887
            new FieldDefinition(
3888
                [
3889
                    'id' => 'fieldDefinitionId1',
3890
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3891
                    'isTranslatable' => true,
3892
                    'identifier' => 'identifier1',
3893
                    'isRequired' => false,
3894
                    'defaultValue' => 'defaultValue1',
3895
                ]
3896
            ),
3897
            new FieldDefinition(
3898
                [
3899
                    'id' => 'fieldDefinitionId2',
3900
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3901
                    'isTranslatable' => false,
3902
                    'identifier' => 'identifier2',
3903
                    'isRequired' => false,
3904
                    'defaultValue' => 'defaultValue2',
3905
                ]
3906
            ),
3907
        ];
3908
3909
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3910
            $initialLanguageCode,
3911
            $structFields,
3912
            $spiFields,
3913
            $existingFields,
3914
            $fieldDefinitions
3915
        );
3916
    }
3917
3918
    public function providerForTestUpdateContentNonRedundantFieldSet4()
3919
    {
3920
        $spiFields0 = [
3921
            new SPIField(
3922
                [
3923
                    'id' => null,
3924
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3925
                    'type' => 'fieldTypeIdentifier',
3926
                    'value' => 'newValue1',
3927
                    'languageCode' => 'eng-US',
3928
                    'versionNo' => 7,
3929
                ]
3930
            ),
3931
        ];
3932
        $spiFields1 = [
3933
            new SPIField(
3934
                [
3935
                    'id' => 100,
3936
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3937
                    'type' => 'fieldTypeIdentifier',
3938
                    'value' => self::EMPTY_FIELD_VALUE,
3939
                    'languageCode' => 'eng-GB',
3940
                    'versionNo' => 7,
3941
                ]
3942
            ),
3943
            new SPIField(
3944
                [
3945
                    'id' => null,
3946
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3947
                    'type' => 'fieldTypeIdentifier',
3948
                    'value' => 'newValue1',
3949
                    'languageCode' => 'eng-US',
3950
                    'versionNo' => 7,
3951
                ]
3952
            ),
3953
        ];
3954
        $spiFields2 = [
3955
            new SPIField(
3956
                [
3957
                    'id' => 100,
3958
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3959
                    'type' => 'fieldTypeIdentifier',
3960
                    'value' => self::EMPTY_FIELD_VALUE,
3961
                    'languageCode' => 'eng-GB',
3962
                    'versionNo' => 7,
3963
                ]
3964
            ),
3965
        ];
3966
3967
        return [
3968
            // 0. New translation with empty field by default
3969
            [
3970
                'eng-US',
3971
                [
3972
                    new Field(
3973
                        [
3974
                            'fieldDefIdentifier' => 'identifier1',
3975
                            'value' => 'newValue1',
3976
                            'languageCode' => 'eng-US',
3977
                        ]
3978
                    ),
3979
                ],
3980
                $spiFields0,
3981
            ],
3982
            // 1. New translation with empty field by default, without language set
3983
            [
3984
                'eng-US',
3985
                [
3986
                    new Field(
3987
                        [
3988
                            'fieldDefIdentifier' => 'identifier1',
3989
                            'value' => 'newValue1',
3990
                            'languageCode' => null,
3991
                        ]
3992
                    ),
3993
                ],
3994
                $spiFields0,
3995
            ],
3996
            // 2. New translation with empty field given
3997
            [
3998
                'eng-US',
3999
                [
4000
                    new Field(
4001
                        [
4002
                            'fieldDefIdentifier' => 'identifier1',
4003
                            'value' => 'newValue1',
4004
                            'languageCode' => 'eng-US',
4005
                        ]
4006
                    ),
4007
                    new Field(
4008
                        [
4009
                            'fieldDefIdentifier' => 'identifier2',
4010
                            'value' => self::EMPTY_FIELD_VALUE,
4011
                            'languageCode' => 'eng-US',
4012
                        ]
4013
                    ),
4014
                ],
4015
                $spiFields0,
4016
            ],
4017
            // 3. New translation with empty field given, without language set
4018
            [
4019
                'eng-US',
4020
                [
4021
                    new Field(
4022
                        [
4023
                            'fieldDefIdentifier' => 'identifier1',
4024
                            'value' => 'newValue1',
4025
                            'languageCode' => null,
4026
                        ]
4027
                    ),
4028
                    new Field(
4029
                        [
4030
                            'fieldDefIdentifier' => 'identifier2',
4031
                            'value' => self::EMPTY_FIELD_VALUE,
4032
                            'languageCode' => null,
4033
                        ]
4034
                    ),
4035
                ],
4036
                $spiFields0,
4037
            ],
4038
            // 4. Updating existing language with empty value
4039
            [
4040
                'eng-US',
4041
                [
4042
                    new Field(
4043
                        [
4044
                            'fieldDefIdentifier' => 'identifier1',
4045
                            'value' => 'newValue1',
4046
                            'languageCode' => 'eng-US',
4047
                        ]
4048
                    ),
4049
                    new Field(
4050
                        [
4051
                            'fieldDefIdentifier' => 'identifier1',
4052
                            'value' => self::EMPTY_FIELD_VALUE,
4053
                            'languageCode' => 'eng-GB',
4054
                        ]
4055
                    ),
4056
                ],
4057
                $spiFields1,
4058
            ],
4059
            // 5. Updating existing language with empty value, without language set
4060
            [
4061
                'eng-US',
4062
                [
4063
                    new Field(
4064
                        [
4065
                            'fieldDefIdentifier' => 'identifier1',
4066
                            'value' => 'newValue1',
4067
                            'languageCode' => null,
4068
                        ]
4069
                    ),
4070
                    new Field(
4071
                        [
4072
                            'fieldDefIdentifier' => 'identifier1',
4073
                            'value' => self::EMPTY_FIELD_VALUE,
4074
                            'languageCode' => 'eng-GB',
4075
                        ]
4076
                    ),
4077
                ],
4078
                $spiFields1,
4079
            ],
4080
            // 6. Updating existing language with empty value and adding new language with empty value
4081
            [
4082
                'eng-US',
4083
                [
4084
                    new Field(
4085
                        [
4086
                            'fieldDefIdentifier' => 'identifier1',
4087
                            'value' => self::EMPTY_FIELD_VALUE,
4088
                            'languageCode' => 'eng-US',
4089
                        ]
4090
                    ),
4091
                    new Field(
4092
                        [
4093
                            'fieldDefIdentifier' => 'identifier1',
4094
                            'value' => self::EMPTY_FIELD_VALUE,
4095
                            'languageCode' => 'eng-GB',
4096
                        ]
4097
                    ),
4098
                ],
4099
                $spiFields2,
4100
            ],
4101
            // 7. Updating existing language with empty value and adding new language with empty value,
4102
            // without language set
4103
            [
4104
                'eng-US',
4105
                [
4106
                    new Field(
4107
                        [
4108
                            'fieldDefIdentifier' => 'identifier1',
4109
                            'value' => self::EMPTY_FIELD_VALUE,
4110
                            'languageCode' => null,
4111
                        ]
4112
                    ),
4113
                    new Field(
4114
                        [
4115
                            'fieldDefIdentifier' => 'identifier1',
4116
                            'value' => self::EMPTY_FIELD_VALUE,
4117
                            'languageCode' => 'eng-GB',
4118
                        ]
4119
                    ),
4120
                ],
4121
                $spiFields2,
4122
            ],
4123
            // 8. Adding new language with no fields given
4124
            [
4125
                'eng-US',
4126
                [],
4127
                [],
4128
            ],
4129
            // 9. Adding new language with fields
4130
            [
4131
                'eng-US',
4132
                [
4133
                    new Field(
4134
                        [
4135
                            'fieldDefIdentifier' => 'identifier1',
4136
                            'value' => self::EMPTY_FIELD_VALUE,
4137
                            'languageCode' => 'eng-US',
4138
                        ]
4139
                    ),
4140
                ],
4141
                [],
4142
            ],
4143
            // 10. Adding new language with fields, without language set
4144
            [
4145
                'eng-US',
4146
                [
4147
                    new Field(
4148
                        [
4149
                            'fieldDefIdentifier' => 'identifier1',
4150
                            'value' => self::EMPTY_FIELD_VALUE,
4151
                            'languageCode' => null,
4152
                        ]
4153
                    ),
4154
                ],
4155
                [],
4156
            ],
4157
        ];
4158
    }
4159
4160
    /**
4161
     * Test for the updateContent() method.
4162
     *
4163
     * Testing with empty values.
4164
     *
4165
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4166
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4167
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4168
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet4
4169
     */
4170
    public function testUpdateContentNonRedundantFieldSet4($initialLanguageCode, $structFields, $spiFields)
4171
    {
4172
        $existingFields = [
4173
            new Field(
4174
                [
4175
                    'id' => '100',
4176
                    'fieldDefIdentifier' => 'identifier1',
4177
                    'value' => 'initialValue1',
4178
                    'languageCode' => 'eng-GB',
4179
                ]
4180
            ),
4181
            new Field(
4182
                [
4183
                    'id' => '101',
4184
                    'fieldDefIdentifier' => 'identifier2',
4185
                    'value' => 'initialValue2',
4186
                    'languageCode' => 'eng-GB',
4187
                ]
4188
            ),
4189
        ];
4190
4191
        $fieldDefinitions = [
4192
            new FieldDefinition(
4193
                [
4194
                    'id' => 'fieldDefinitionId1',
4195
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4196
                    'isTranslatable' => true,
4197
                    'identifier' => 'identifier1',
4198
                    'isRequired' => false,
4199
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4200
                ]
4201
            ),
4202
            new FieldDefinition(
4203
                [
4204
                    'id' => 'fieldDefinitionId2',
4205
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4206
                    'isTranslatable' => true,
4207
                    'identifier' => 'identifier2',
4208
                    'isRequired' => false,
4209
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4210
                ]
4211
            ),
4212
        ];
4213
4214
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4215
            $initialLanguageCode,
4216
            $structFields,
4217
            $spiFields,
4218
            $existingFields,
4219
            $fieldDefinitions
4220
        );
4221
    }
4222
4223
    /**
4224
     * @todo add first field empty
4225
     *
4226
     * @return array
4227
     */
4228
    public function providerForTestUpdateContentNonRedundantFieldSetComplex()
4229
    {
4230
        $spiFields0 = [
4231
            new SPIField(
4232
                [
4233
                    'id' => 100,
4234
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4235
                    'type' => 'fieldTypeIdentifier',
4236
                    'value' => 'newValue1-eng-GB',
4237
                    'languageCode' => 'eng-GB',
4238
                    'versionNo' => 7,
4239
                ]
4240
            ),
4241
            new SPIField(
4242
                [
4243
                    'id' => null,
4244
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4245
                    'type' => 'fieldTypeIdentifier',
4246
                    'value' => 'newValue4',
4247
                    'languageCode' => 'eng-US',
4248
                    'versionNo' => 7,
4249
                ]
4250
            ),
4251
        ];
4252
        $spiFields1 = [
4253
            new SPIField(
4254
                [
4255
                    'id' => 100,
4256
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4257
                    'type' => 'fieldTypeIdentifier',
4258
                    'value' => 'newValue1-eng-GB',
4259
                    'languageCode' => 'eng-GB',
4260
                    'versionNo' => 7,
4261
                ]
4262
            ),
4263
            new SPIField(
4264
                [
4265
                    'id' => null,
4266
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4267
                    'type' => 'fieldTypeIdentifier',
4268
                    'value' => 'newValue2',
4269
                    'languageCode' => 'eng-US',
4270
                    'versionNo' => 7,
4271
                ]
4272
            ),
4273
            new SPIField(
4274
                [
4275
                    'id' => null,
4276
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4277
                    'type' => 'fieldTypeIdentifier',
4278
                    'value' => 'defaultValue4',
4279
                    'languageCode' => 'eng-US',
4280
                    'versionNo' => 7,
4281
                ]
4282
            ),
4283
        ];
4284
        $spiFields2 = [
4285
            new SPIField(
4286
                [
4287
                    'id' => 100,
4288
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4289
                    'type' => 'fieldTypeIdentifier',
4290
                    'value' => 'newValue1-eng-GB',
4291
                    'languageCode' => 'eng-GB',
4292
                    'versionNo' => 7,
4293
                ]
4294
            ),
4295
            new SPIField(
4296
                [
4297
                    'id' => null,
4298
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4299
                    'type' => 'fieldTypeIdentifier',
4300
                    'value' => 'newValue2',
4301
                    'languageCode' => 'eng-US',
4302
                    'versionNo' => 7,
4303
                ]
4304
            ),
4305
            new SPIField(
4306
                [
4307
                    'id' => null,
4308
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4309
                    'type' => 'fieldTypeIdentifier',
4310
                    'value' => 'defaultValue4',
4311
                    'languageCode' => 'ger-DE',
4312
                    'versionNo' => 7,
4313
                ]
4314
            ),
4315
            new SPIField(
4316
                [
4317
                    'id' => null,
4318
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4319
                    'type' => 'fieldTypeIdentifier',
4320
                    'value' => 'defaultValue4',
4321
                    'languageCode' => 'eng-US',
4322
                    'versionNo' => 7,
4323
                ]
4324
            ),
4325
        ];
4326
4327
        return [
4328
            // 0. Add new language and update existing
4329
            [
4330
                'eng-US',
4331
                [
4332
                    new Field(
4333
                        [
4334
                            'fieldDefIdentifier' => 'identifier4',
4335
                            'value' => 'newValue4',
4336
                            'languageCode' => 'eng-US',
4337
                        ]
4338
                    ),
4339
                    new Field(
4340
                        [
4341
                            'fieldDefIdentifier' => 'identifier1',
4342
                            'value' => 'newValue1-eng-GB',
4343
                            'languageCode' => 'eng-GB',
4344
                        ]
4345
                    ),
4346
                ],
4347
                $spiFields0,
4348
            ],
4349
            // 1. Add new language and update existing, without language set
4350
            [
4351
                'eng-US',
4352
                [
4353
                    new Field(
4354
                        [
4355
                            'fieldDefIdentifier' => 'identifier4',
4356
                            'value' => 'newValue4',
4357
                            'languageCode' => null,
4358
                        ]
4359
                    ),
4360
                    new Field(
4361
                        [
4362
                            'fieldDefIdentifier' => 'identifier1',
4363
                            'value' => 'newValue1-eng-GB',
4364
                            'languageCode' => 'eng-GB',
4365
                        ]
4366
                    ),
4367
                ],
4368
                $spiFields0,
4369
            ],
4370
            // 2. Add new language and update existing variant
4371
            [
4372
                'eng-US',
4373
                [
4374
                    new Field(
4375
                        [
4376
                            'fieldDefIdentifier' => 'identifier2',
4377
                            'value' => 'newValue2',
4378
                            'languageCode' => 'eng-US',
4379
                        ]
4380
                    ),
4381
                    new Field(
4382
                        [
4383
                            'fieldDefIdentifier' => 'identifier1',
4384
                            'value' => 'newValue1-eng-GB',
4385
                            'languageCode' => 'eng-GB',
4386
                        ]
4387
                    ),
4388
                ],
4389
                $spiFields1,
4390
            ],
4391
            // 3. Add new language and update existing variant, without language set
4392
            [
4393
                'eng-US',
4394
                [
4395
                    new Field(
4396
                        [
4397
                            'fieldDefIdentifier' => 'identifier2',
4398
                            'value' => 'newValue2',
4399
                            'languageCode' => null,
4400
                        ]
4401
                    ),
4402
                    new Field(
4403
                        [
4404
                            'fieldDefIdentifier' => 'identifier1',
4405
                            'value' => 'newValue1-eng-GB',
4406
                            'languageCode' => 'eng-GB',
4407
                        ]
4408
                    ),
4409
                ],
4410
                $spiFields1,
4411
            ],
4412
            // 4. Update with multiple languages
4413
            [
4414
                'ger-DE',
4415
                [
4416
                    new Field(
4417
                        [
4418
                            'fieldDefIdentifier' => 'identifier2',
4419
                            'value' => 'newValue2',
4420
                            'languageCode' => 'eng-US',
4421
                        ]
4422
                    ),
4423
                    new Field(
4424
                        [
4425
                            'fieldDefIdentifier' => 'identifier1',
4426
                            'value' => 'newValue1-eng-GB',
4427
                            'languageCode' => 'eng-GB',
4428
                        ]
4429
                    ),
4430
                ],
4431
                $spiFields2,
4432
            ],
4433
            // 5. Update with multiple languages without language set
4434
            [
4435
                'ger-DE',
4436
                [
4437
                    new Field(
4438
                        [
4439
                            'fieldDefIdentifier' => 'identifier2',
4440
                            'value' => 'newValue2',
4441
                            'languageCode' => 'eng-US',
4442
                        ]
4443
                    ),
4444
                    new Field(
4445
                        [
4446
                            'fieldDefIdentifier' => 'identifier1',
4447
                            'value' => 'newValue1-eng-GB',
4448
                            'languageCode' => null,
4449
                        ]
4450
                    ),
4451
                ],
4452
                $spiFields2,
4453
            ],
4454
        ];
4455
    }
4456
4457
    protected function fixturesForTestUpdateContentNonRedundantFieldSetComplex()
4458
    {
4459
        $existingFields = [
4460
            new Field(
4461
                [
4462
                    'id' => '100',
4463
                    'fieldDefIdentifier' => 'identifier1',
4464
                    'value' => 'initialValue1',
4465
                    'languageCode' => 'eng-GB',
4466
                ]
4467
            ),
4468
            new Field(
4469
                [
4470
                    'id' => '101',
4471
                    'fieldDefIdentifier' => 'identifier2',
4472
                    'value' => 'initialValue2',
4473
                    'languageCode' => 'eng-GB',
4474
                ]
4475
            ),
4476
            new Field(
4477
                [
4478
                    'id' => '102',
4479
                    'fieldDefIdentifier' => 'identifier3',
4480
                    'value' => 'initialValue3',
4481
                    'languageCode' => 'eng-GB',
4482
                ]
4483
            ),
4484
            new Field(
4485
                [
4486
                    'id' => '103',
4487
                    'fieldDefIdentifier' => 'identifier4',
4488
                    'value' => 'initialValue4',
4489
                    'languageCode' => 'eng-GB',
4490
                ]
4491
            ),
4492
        ];
4493
4494
        $fieldDefinitions = [
4495
            new FieldDefinition(
4496
                [
4497
                    'id' => 'fieldDefinitionId1',
4498
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4499
                    'isTranslatable' => false,
4500
                    'identifier' => 'identifier1',
4501
                    'isRequired' => false,
4502
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4503
                ]
4504
            ),
4505
            new FieldDefinition(
4506
                [
4507
                    'id' => 'fieldDefinitionId2',
4508
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4509
                    'isTranslatable' => true,
4510
                    'identifier' => 'identifier2',
4511
                    'isRequired' => false,
4512
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4513
                ]
4514
            ),
4515
            new FieldDefinition(
4516
                [
4517
                    'id' => 'fieldDefinitionId3',
4518
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4519
                    'isTranslatable' => false,
4520
                    'identifier' => 'identifier3',
4521
                    'isRequired' => false,
4522
                    'defaultValue' => 'defaultValue3',
4523
                ]
4524
            ),
4525
            new FieldDefinition(
4526
                [
4527
                    'id' => 'fieldDefinitionId4',
4528
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4529
                    'isTranslatable' => true,
4530
                    'identifier' => 'identifier4',
4531
                    'isRequired' => false,
4532
                    'defaultValue' => 'defaultValue4',
4533
                ]
4534
            ),
4535
        ];
4536
4537
        return [$existingFields, $fieldDefinitions];
4538
    }
4539
4540
    /**
4541
     * Test for the updateContent() method.
4542
     *
4543
     * Testing more complex cases.
4544
     *
4545
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4546
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4547
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4548
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSetComplex
4549
     */
4550
    public function testUpdateContentNonRedundantFieldSetComplex($initialLanguageCode, $structFields, $spiFields)
4551
    {
4552
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
4553
4554
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4555
            $initialLanguageCode,
4556
            $structFields,
4557
            $spiFields,
4558
            $existingFields,
4559
            $fieldDefinitions
4560
        );
4561
    }
4562
4563 View Code Duplication
    public function providerForTestUpdateContentWithInvalidLanguage()
4564
    {
4565
        return [
4566
            [
4567
                'eng-GB',
4568
                [
4569
                    new Field(
4570
                        [
4571
                            'fieldDefIdentifier' => 'identifier',
4572
                            'value' => 'newValue',
4573
                            'languageCode' => 'Klingon',
4574
                        ]
4575
                    ),
4576
                ],
4577
            ],
4578
            [
4579
                'Klingon',
4580
                [
4581
                    new Field(
4582
                        [
4583
                            'fieldDefIdentifier' => 'identifier',
4584
                            'value' => 'newValue',
4585
                            'languageCode' => 'eng-GB',
4586
                        ]
4587
                    ),
4588
                ],
4589
            ],
4590
        ];
4591
    }
4592
4593
    /**
4594
     * Test for the updateContent() method.
4595
     *
4596
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4597
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4598
     * @dataProvider providerForTestUpdateContentWithInvalidLanguage
4599
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
4600
     * @expectedExceptionMessage Could not find 'Language' with identifier 'Klingon'
4601
     */
4602
    public function testUpdateContentWithInvalidLanguage($initialLanguageCode, $structFields)
4603
    {
4604
        $repositoryMock = $this->getRepositoryMock();
0 ignored issues
show
Unused Code introduced by
$repositoryMock is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
4605
        $permissionResolverMock = $this->getPermissionResolverMock();
4606
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4607
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4608
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4609
        $versionInfo = new VersionInfo(
4610
            [
4611
                'contentInfo' => new ContentInfo(
4612
                    [
4613
                        'id' => 42,
4614
                        'contentTypeId' => 24,
4615
                        'mainLanguageCode' => 'eng-GB',
4616
                    ]
4617
                ),
4618
                'versionNo' => 7,
4619
                'languageCodes' => ['eng-GB'],
4620
                'status' => VersionInfo::STATUS_DRAFT,
4621
            ]
4622
        );
4623
        $content = new Content(
4624
            [
4625
                'versionInfo' => $versionInfo,
4626
                'internalFields' => [],
4627
            ]
4628
        );
4629
4630
        $languageHandlerMock->expects($this->any())
4631
            ->method('loadByLanguageCode')
4632
            ->with($this->isType('string'))
4633
            ->will(
4634
                $this->returnCallback(
4635 View Code Duplication
                    function ($languageCode) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
4636
                        if ($languageCode === 'Klingon') {
4637
                            throw new NotFoundException('Language', 'Klingon');
4638
                        }
4639
4640
                        return new Language(['id' => 4242]);
4641
                    }
4642
                )
4643
            );
4644
4645
        $mockedService->expects($this->once())
4646
            ->method('loadContent')
4647
            ->with(
4648
                $this->equalTo(42),
4649
                $this->equalTo(null),
4650
                $this->equalTo(7)
4651
            )->will(
4652
                $this->returnValue($content)
4653
            );
4654
4655
        $permissionResolverMock->expects($this->once())
4656
            ->method('canUser')
4657
            ->with(
4658
                $this->equalTo('content'),
4659
                $this->equalTo('edit'),
4660
                $this->equalTo($content),
4661
                $this->isType('array')
4662
            )->will($this->returnValue(true));
4663
4664
        $contentUpdateStruct = new ContentUpdateStruct(
4665
            [
4666
                'fields' => $structFields,
4667
                'initialLanguageCode' => $initialLanguageCode,
4668
            ]
4669
        );
4670
4671
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4672
    }
4673
4674
    protected function assertForUpdateContentContentValidationException(
4675
        $initialLanguageCode,
4676
        $structFields,
4677
        $fieldDefinitions = []
4678
    ) {
4679
        $repositoryMock = $this->getRepositoryMock();
4680
        $permissionResolverMock = $this->getPermissionResolverMock();
4681
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4682
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4683
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4684
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4685
        $versionInfo = new VersionInfo(
4686
            [
4687
                'contentInfo' => new ContentInfo(
4688
                    [
4689
                        'id' => 42,
4690
                        'contentTypeId' => 24,
4691
                        'mainLanguageCode' => 'eng-GB',
4692
                    ]
4693
                ),
4694
                'versionNo' => 7,
4695
                'languageCodes' => ['eng-GB'],
4696
                'status' => VersionInfo::STATUS_DRAFT,
4697
            ]
4698
        );
4699
        $content = new Content(
4700
            [
4701
                'versionInfo' => $versionInfo,
4702
                'internalFields' => [],
4703
            ]
4704
        );
4705
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
4706
4707
        $languageHandlerMock->expects($this->any())
4708
            ->method('loadByLanguageCode')
4709
            ->with($this->isType('string'))
4710
            ->will(
4711
                $this->returnCallback(
4712 View Code Duplication
                    function ($languageCode) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
4713
                        if ($languageCode === 'Klingon') {
4714
                            throw new NotFoundException('Language', 'Klingon');
4715
                        }
4716
4717
                        return new Language(['id' => 4242]);
4718
                    }
4719
                )
4720
            );
4721
4722
        $mockedService->expects($this->once())
4723
            ->method('loadContent')
4724
            ->with(
4725
                $this->equalTo(42),
4726
                $this->equalTo(null),
4727
                $this->equalTo(7)
4728
            )->will(
4729
                $this->returnValue($content)
4730
            );
4731
4732
        $permissionResolverMock->expects($this->once())
4733
            ->method('canUser')
4734
            ->with(
4735
                $this->equalTo('content'),
4736
                $this->equalTo('edit'),
4737
                $this->equalTo($content),
4738
                $this->isType('array')
4739
            )->will($this->returnValue(true));
4740
4741
        $contentTypeServiceMock->expects($this->once())
4742
            ->method('loadContentType')
4743
            ->with($this->equalTo(24))
4744
            ->will($this->returnValue($contentType));
4745
4746
        $repositoryMock->expects($this->once())
4747
            ->method('getContentTypeService')
4748
            ->will($this->returnValue($contentTypeServiceMock));
4749
4750
        $contentUpdateStruct = new ContentUpdateStruct(
4751
            [
4752
                'fields' => $structFields,
4753
                'initialLanguageCode' => $initialLanguageCode,
4754
            ]
4755
        );
4756
4757
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4758
    }
4759
4760 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition()
4761
    {
4762
        return [
4763
            [
4764
                'eng-GB',
4765
                [
4766
                    new Field(
4767
                        [
4768
                            'fieldDefIdentifier' => 'identifier',
4769
                            'value' => 'newValue',
4770
                            'languageCode' => 'eng-GB',
4771
                        ]
4772
                    ),
4773
                ],
4774
            ],
4775
        ];
4776
    }
4777
4778
    /**
4779
     * Test for the updateContent() method.
4780
     *
4781
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4782
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4783
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4784
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition
4785
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentValidationException
4786
     * @expectedExceptionMessage Field definition 'identifier' does not exist in given ContentType
4787
     */
4788
    public function testUpdateContentThrowsContentValidationExceptionFieldDefinition($initialLanguageCode, $structFields)
4789
    {
4790
        $this->assertForUpdateContentContentValidationException(
4791
            $initialLanguageCode,
4792
            $structFields,
4793
            []
4794
        );
4795
    }
4796
4797 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionTranslation()
4798
    {
4799
        return [
4800
            [
4801
                'eng-US',
4802
                [
4803
                    new Field(
4804
                        [
4805
                            'fieldDefIdentifier' => 'identifier',
4806
                            'value' => 'newValue',
4807
                            'languageCode' => 'eng-US',
4808
                        ]
4809
                    ),
4810
                ],
4811
            ],
4812
        ];
4813
    }
4814
4815
    /**
4816
     * Test for the updateContent() method.
4817
     *
4818
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4819
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4820
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4821
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionTranslation
4822
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentValidationException
4823
     * @expectedExceptionMessage A value is set for non translatable field definition 'identifier' with language 'eng-US'
4824
     */
4825 View Code Duplication
    public function testUpdateContentThrowsContentValidationExceptionTranslation($initialLanguageCode, $structFields)
4826
    {
4827
        $fieldDefinitions = [
4828
            new FieldDefinition(
4829
                [
4830
                    'id' => 'fieldDefinitionId1',
4831
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4832
                    'isTranslatable' => false,
4833
                    'identifier' => 'identifier',
4834
                    'isRequired' => false,
4835
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4836
                ]
4837
            ),
4838
        ];
4839
4840
        $this->assertForUpdateContentContentValidationException(
4841
            $initialLanguageCode,
4842
            $structFields,
4843
            $fieldDefinitions
4844
        );
4845
    }
4846
4847
    public function assertForTestUpdateContentRequiredField(
4848
        $initialLanguageCode,
4849
        $structFields,
4850
        $existingFields,
4851
        $fieldDefinitions
4852
    ) {
4853
        $repositoryMock = $this->getRepositoryMock();
4854
        $permissionResolver = $this->getPermissionResolverMock();
4855
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4856
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4857
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4858
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4859
        $fieldTypeServiceMock = $this->getFieldTypeServiceMock();
0 ignored issues
show
Unused Code introduced by
$fieldTypeServiceMock is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
4860
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
4861
        $existingLanguageCodes = array_map(
4862
            function (Field $field) {
4863
                return $field->languageCode;
4864
            },
4865
            $existingFields
4866
        );
4867
        $versionInfo = new VersionInfo(
4868
            [
4869
                'contentInfo' => new ContentInfo(
4870
                    [
4871
                        'id' => 42,
4872
                        'contentTypeId' => 24,
4873
                        'mainLanguageCode' => 'eng-GB',
4874
                    ]
4875
                ),
4876
                'versionNo' => 7,
4877
                'languageCodes' => $existingLanguageCodes,
4878
                'status' => VersionInfo::STATUS_DRAFT,
4879
            ]
4880
        );
4881
        $content = new Content(
4882
            [
4883
                'versionInfo' => $versionInfo,
4884
                'internalFields' => $existingFields,
4885
            ]
4886
        );
4887
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
4888
4889
        $languageHandlerMock->expects($this->any())
4890
            ->method('loadByLanguageCode')
4891
            ->with($this->isType('string'))
4892
            ->will(
4893
                $this->returnCallback(
4894
                    function () {
4895
                        return new Language(['id' => 4242]);
4896
                    }
4897
                )
4898
            );
4899
4900
        $mockedService->expects($this->once())
4901
            ->method('loadContent')
4902
            ->with(
4903
                $this->equalTo(42),
4904
                $this->equalTo(null),
4905
                $this->equalTo(7)
4906
            )->will(
4907
                $this->returnValue($content)
4908
            );
4909
4910
        $permissionResolver->expects($this->once())
4911
            ->method('canUser')
4912
            ->with(
4913
                $this->equalTo('content'),
4914
                $this->equalTo('edit'),
4915
                $this->equalTo($content),
4916
                $this->isType('array')
4917
            )->will($this->returnValue(true));
4918
4919
        $contentTypeServiceMock->expects($this->once())
4920
            ->method('loadContentType')
4921
            ->with($this->equalTo(24))
4922
            ->will($this->returnValue($contentType));
4923
4924
        $repositoryMock->expects($this->once())
4925
            ->method('getContentTypeService')
4926
            ->will($this->returnValue($contentTypeServiceMock));
4927
4928
        $fieldTypeMock->expects($this->any())
4929
            ->method('acceptValue')
4930
            ->will(
4931
                $this->returnCallback(
4932
                    function ($valueString) {
4933
                        return new ValueStub($valueString);
4934
                    }
4935
                )
4936
            );
4937
4938
        $emptyValue = self::EMPTY_FIELD_VALUE;
4939
        $fieldTypeMock->expects($this->any())
4940
            ->method('isEmptyValue')
4941
            ->will(
4942
                $this->returnCallback(
4943
                    function (ValueStub $value) use ($emptyValue) {
4944
                        return $emptyValue === (string)$value;
4945
                    }
4946
                )
4947
            );
4948
4949
        $fieldTypeMock->expects($this->any())
4950
            ->method('validate')
4951
            ->with(
4952
                $this->isInstanceOf(APIFieldDefinition::class),
4953
                $this->isInstanceOf(Value::class)
4954
            );
4955
4956
        $this->getFieldTypeRegistryMock()->expects($this->any())
4957
            ->method('getFieldType')
4958
            ->will($this->returnValue($fieldTypeMock));
4959
4960
        $contentUpdateStruct = new ContentUpdateStruct(
4961
            [
4962
                'fields' => $structFields,
4963
                'initialLanguageCode' => $initialLanguageCode,
4964
            ]
4965
        );
4966
4967
        return [$content->versionInfo, $contentUpdateStruct];
4968
    }
4969
4970 View Code Duplication
    public function providerForTestUpdateContentRequiredField()
4971
    {
4972
        return [
4973
            [
4974
                'eng-US',
4975
                [
4976
                    new Field(
4977
                        [
4978
                            'fieldDefIdentifier' => 'identifier',
4979
                            'value' => self::EMPTY_FIELD_VALUE,
4980
                            'languageCode' => null,
4981
                        ]
4982
                    ),
4983
                ],
4984
                'identifier',
4985
                'eng-US',
4986
            ],
4987
        ];
4988
    }
4989
4990
    /**
4991
     * Test for the updateContent() method.
4992
     *
4993
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4994
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4995
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4996
     * @dataProvider providerForTestUpdateContentRequiredField
4997
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
4998
     */
4999
    public function testUpdateContentRequiredField(
5000
        $initialLanguageCode,
5001
        $structFields,
5002
        $identifier,
5003
        $languageCode
5004
    ) {
5005
        $existingFields = [
5006
            new Field(
5007
                [
5008
                    'id' => '100',
5009
                    'fieldDefIdentifier' => 'identifier',
5010
                    'value' => 'initialValue',
5011
                    'languageCode' => 'eng-GB',
5012
                ]
5013
            ),
5014
        ];
5015
        $fieldDefinitions = [
5016
            new FieldDefinition(
5017
                [
5018
                    'id' => 'fieldDefinitionId',
5019
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5020
                    'isTranslatable' => true,
5021
                    'identifier' => 'identifier',
5022
                    'isRequired' => true,
5023
                    'defaultValue' => 'defaultValue',
5024
                ]
5025
            ),
5026
        ];
5027
        list($versionInfo, $contentUpdateStruct) =
5028
            $this->assertForTestUpdateContentRequiredField(
5029
                $initialLanguageCode,
5030
                $structFields,
5031
                $existingFields,
5032
                $fieldDefinitions
5033
            );
5034
5035
        try {
5036
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5037
        } catch (ContentValidationException $e) {
5038
            $this->assertEquals(
5039
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
5040
                $e->getMessage()
5041
            );
5042
5043
            throw $e;
5044
        }
5045
    }
5046
5047
    public function assertForTestUpdateContentThrowsContentFieldValidationException(
5048
        $initialLanguageCode,
5049
        $structFields,
5050
        $existingFields,
5051
        $fieldDefinitions
5052
    ) {
5053
        $repositoryMock = $this->getRepositoryMock();
5054
        $permissionResolverMock = $this->getPermissionResolverMock();
5055
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
5056
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
5057
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
5058
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5059
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
5060
        $existingLanguageCodes = array_map(
5061
            function (Field $field) {
5062
                return $field->languageCode;
5063
            },
5064
            $existingFields
5065
        );
5066
        $languageCodes = $this->determineLanguageCodesForUpdate(
5067
            $initialLanguageCode,
5068
            $structFields,
5069
            $existingLanguageCodes
5070
        );
5071
        $versionInfo = new VersionInfo(
5072
            [
5073
                'contentInfo' => new ContentInfo(
5074
                    [
5075
                        'id' => 42,
5076
                        'contentTypeId' => 24,
5077
                        'mainLanguageCode' => 'eng-GB',
5078
                    ]
5079
                ),
5080
                'versionNo' => 7,
5081
                'languageCodes' => $existingLanguageCodes,
5082
                'status' => VersionInfo::STATUS_DRAFT,
5083
            ]
5084
        );
5085
        $content = new Content(
5086
            [
5087
                'versionInfo' => $versionInfo,
5088
                'internalFields' => $existingFields,
5089
            ]
5090
        );
5091
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
5092
5093
        $languageHandlerMock->expects($this->any())
5094
            ->method('loadByLanguageCode')
5095
            ->with($this->isType('string'))
5096
            ->will(
5097
                $this->returnCallback(
5098
                    function () {
5099
                        return new Language(['id' => 4242]);
5100
                    }
5101
                )
5102
            );
5103
5104
        $mockedService->expects($this->once())
5105
            ->method('loadContent')
5106
            ->with(
5107
                $this->equalTo(42),
5108
                $this->equalTo(null),
5109
                $this->equalTo(7)
5110
            )->will(
5111
                $this->returnValue($content)
5112
            );
5113
5114
        $permissionResolverMock->expects($this->once())
5115
            ->method('canUser')
5116
            ->with(
5117
                $this->equalTo('content'),
5118
                $this->equalTo('edit'),
5119
                $this->equalTo($content),
5120
                $this->isType('array')
5121
            )->will($this->returnValue(true));
5122
5123
        $contentTypeServiceMock->expects($this->once())
5124
            ->method('loadContentType')
5125
            ->with($this->equalTo(24))
5126
            ->will($this->returnValue($contentType));
5127
5128
        $repositoryMock->expects($this->once())
5129
            ->method('getContentTypeService')
5130
            ->will($this->returnValue($contentTypeServiceMock));
5131
5132
        $fieldValues = $this->determineValuesForUpdate(
5133
            $initialLanguageCode,
5134
            $structFields,
5135
            $content,
5136
            $fieldDefinitions,
5137
            $languageCodes
5138
        );
5139
        $allFieldErrors = [];
5140
        $emptyValue = self::EMPTY_FIELD_VALUE;
5141
5142
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5143
            ->method('acceptValue')
5144
            ->will(
5145
                $this->returnCallback(
5146
                    function ($valueString) {
5147
                        return new ValueStub($valueString);
5148
                    }
5149
                )
5150
            );
5151
5152
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5153
            ->method('isEmptyValue')
5154
            ->will(
5155
                $this->returnCallback(
5156
                    function (ValueStub $value) use ($emptyValue) {
5157
                        return $emptyValue === (string)$value;
5158
                    }
5159
                )
5160
            );
5161
5162
        $fieldTypeMock
5163
            ->expects($this->any())
5164
            ->method('validate')
5165
            ->willReturnArgument(1);
5166
5167
        $this->getFieldTypeRegistryMock()->expects($this->any())
5168
            ->method('getFieldType')
5169
            ->will($this->returnValue($fieldTypeMock));
5170
5171
        $contentUpdateStruct = new ContentUpdateStruct(
5172
            [
5173
                'fields' => $structFields,
5174
                'initialLanguageCode' => $initialLanguageCode,
5175
            ]
5176
        );
5177
5178
        return [$content->versionInfo, $contentUpdateStruct, $allFieldErrors];
5179
    }
5180
5181
    public function providerForTestUpdateContentThrowsContentFieldValidationException()
5182
    {
5183
        $allFieldErrors = [
5184
            [
5185
                'fieldDefinitionId1' => [
5186
                    'eng-GB' => 'newValue1-eng-GB',
5187
                    'eng-US' => 'newValue1-eng-GB',
5188
                ],
5189
                'fieldDefinitionId2' => [
5190
                    'eng-GB' => 'initialValue2',
5191
                ],
5192
                'fieldDefinitionId3' => [
5193
                    'eng-GB' => 'initialValue3',
5194
                    'eng-US' => 'initialValue3',
5195
                ],
5196
                'fieldDefinitionId4' => [
5197
                    'eng-GB' => 'initialValue4',
5198
                    'eng-US' => 'newValue4',
5199
                ],
5200
            ],
5201
            [
5202
                'fieldDefinitionId1' => [
5203
                    'eng-GB' => 'newValue1-eng-GB',
5204
                    'eng-US' => 'newValue1-eng-GB',
5205
                ],
5206
                'fieldDefinitionId2' => [
5207
                    'eng-GB' => 'initialValue2',
5208
                ],
5209
                'fieldDefinitionId3' => [
5210
                    'eng-GB' => 'initialValue3',
5211
                    'eng-US' => 'initialValue3',
5212
                ],
5213
                'fieldDefinitionId4' => [
5214
                    'eng-GB' => 'initialValue4',
5215
                    'eng-US' => 'newValue4',
5216
                ],
5217
            ],
5218
            [
5219
                'fieldDefinitionId1' => [
5220
                    'eng-GB' => 'newValue1-eng-GB',
5221
                    'eng-US' => 'newValue1-eng-GB',
5222
                ],
5223
                'fieldDefinitionId2' => [
5224
                    'eng-GB' => 'initialValue2',
5225
                    'eng-US' => 'newValue2',
5226
                ],
5227
                'fieldDefinitionId3' => [
5228
                    'eng-GB' => 'initialValue3',
5229
                    'eng-US' => 'initialValue3',
5230
                ],
5231
                'fieldDefinitionId4' => [
5232
                    'eng-GB' => 'initialValue4',
5233
                    'eng-US' => 'defaultValue4',
5234
                ],
5235
            ],
5236
            [
5237
                'fieldDefinitionId1' => [
5238
                    'eng-GB' => 'newValue1-eng-GB',
5239
                    'eng-US' => 'newValue1-eng-GB',
5240
                ],
5241
                'fieldDefinitionId2' => [
5242
                    'eng-GB' => 'initialValue2',
5243
                    'eng-US' => 'newValue2',
5244
                ],
5245
                'fieldDefinitionId3' => [
5246
                    'eng-GB' => 'initialValue3',
5247
                    'eng-US' => 'initialValue3',
5248
                ],
5249
                'fieldDefinitionId4' => [
5250
                    'eng-GB' => 'initialValue4',
5251
                    'eng-US' => 'defaultValue4',
5252
                ],
5253
            ],
5254
            [
5255
                'fieldDefinitionId1' => [
5256
                    'eng-GB' => 'newValue1-eng-GB',
5257
                    'ger-DE' => 'newValue1-eng-GB',
5258
                    'eng-US' => 'newValue1-eng-GB',
5259
                ],
5260
                'fieldDefinitionId2' => [
5261
                    'eng-GB' => 'initialValue2',
5262
                    'eng-US' => 'newValue2',
5263
                ],
5264
                'fieldDefinitionId3' => [
5265
                    'eng-GB' => 'initialValue3',
5266
                    'ger-DE' => 'initialValue3',
5267
                    'eng-US' => 'initialValue3',
5268
                ],
5269
                'fieldDefinitionId4' => [
5270
                    'eng-GB' => 'initialValue4',
5271
                    'eng-US' => 'defaultValue4',
5272
                    'ger-DE' => 'defaultValue4',
5273
                ],
5274
            ],
5275
            [
5276
                'fieldDefinitionId1' => [
5277
                    'eng-US' => 'newValue1-eng-GB',
5278
                    'ger-DE' => 'newValue1-eng-GB',
5279
                ],
5280
                'fieldDefinitionId2' => [
5281
                    'eng-US' => 'newValue2',
5282
                ],
5283
                'fieldDefinitionId3' => [
5284
                    'ger-DE' => 'initialValue3',
5285
                    'eng-US' => 'initialValue3',
5286
                ],
5287
                'fieldDefinitionId4' => [
5288
                    'ger-DE' => 'defaultValue4',
5289
                    'eng-US' => 'defaultValue4',
5290
                ],
5291
            ],
5292
        ];
5293
5294
        $data = $this->providerForTestUpdateContentNonRedundantFieldSetComplex();
5295
        $count = count($data);
5296
        for ($i = 0; $i < $count; ++$i) {
5297
            $data[$i][] = $allFieldErrors[$i];
5298
        }
5299
5300
        return $data;
5301
    }
5302
5303
    /**
5304
     * Test for the updateContent() method.
5305
     *
5306
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5307
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5308
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5309
     * @dataProvider providerForTestUpdateContentThrowsContentFieldValidationException
5310
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
5311
     * @expectedExceptionMessage Content fields did not validate
5312
     */
5313
    public function testUpdateContentThrowsContentFieldValidationException($initialLanguageCode, $structFields, $spiField, $allFieldErrors)
0 ignored issues
show
Unused Code introduced by
The parameter $spiField 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...
5314
    {
5315
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
5316
        list($versionInfo, $contentUpdateStruct) =
5317
            $this->assertForTestUpdateContentThrowsContentFieldValidationException(
5318
                $initialLanguageCode,
5319
                $structFields,
5320
                $existingFields,
5321
                $fieldDefinitions
5322
            );
5323
5324
        try {
5325
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5326
        } catch (ContentFieldValidationException $e) {
5327
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
5328
            throw $e;
5329
        }
5330
    }
5331
5332
    /**
5333
     * Test for the updateContent() method.
5334
     *
5335
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5336
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5337
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5338
     * @expectedException \Exception
5339
     * @expectedExceptionMessage Store failed
5340
     */
5341
    public function testUpdateContentTransactionRollback()
5342
    {
5343
        $existingFields = [
5344
            new Field(
5345
                [
5346
                    'id' => '100',
5347
                    'fieldDefIdentifier' => 'identifier',
5348
                    'value' => 'initialValue',
5349
                    'languageCode' => 'eng-GB',
5350
                ]
5351
            ),
5352
        ];
5353
5354
        $fieldDefinitions = [
5355
            new FieldDefinition(
5356
                [
5357
                    'id' => 'fieldDefinitionId',
5358
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5359
                    'isTranslatable' => false,
5360
                    'identifier' => 'identifier',
5361
                    'isRequired' => false,
5362
                    'defaultValue' => 'defaultValue',
5363
                ]
5364
            ),
5365
        ];
5366
5367
        // Setup a simple case that will pass
5368
        list($versionInfo, $contentUpdateStruct) = $this->assertForTestUpdateContentNonRedundantFieldSet(
5369
            'eng-US',
5370
            [],
5371
            [],
5372
            $existingFields,
5373
            $fieldDefinitions,
5374
            // Do not execute test
5375
            false
5376
        );
5377
5378
        $repositoryMock = $this->getRepositoryMock();
5379
        $repositoryMock->expects($this->never())->method('commit');
5380
        $repositoryMock->expects($this->once())->method('rollback');
5381
5382
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5383
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5384
        $contentHandlerMock->expects($this->once())
5385
            ->method('updateContent')
5386
            ->with(
5387
                $this->anything(),
5388
                $this->anything(),
5389
                $this->anything()
5390
            )->will($this->throwException(new \Exception('Store failed')));
5391
5392
        // Execute
5393
        $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5394
    }
5395
5396
    /**
5397
     * Test for the copyContent() method.
5398
     *
5399
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5400
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
5401
     */
5402
    public function testCopyContentThrowsUnauthorizedException()
5403
    {
5404
        $repository = $this->getRepositoryMock();
5405
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
5406
        $contentInfo = $this->createMock(APIContentInfo::class);
5407
        $locationCreateStruct = new LocationCreateStruct();
5408
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5409
        $locationServiceMock = $this->getLocationServiceMock();
5410
5411
        $repository->expects($this->once())
5412
            ->method('getLocationService')
5413
            ->will($this->returnValue($locationServiceMock))
5414
        ;
5415
5416
        $locationServiceMock->expects($this->once())
5417
            ->method('loadLocation')
5418
            ->with(
5419
                $locationCreateStruct->parentLocationId
5420
            )
5421
            ->will($this->returnValue($location))
5422
        ;
5423
5424
        $contentInfo->expects($this->any())
5425
            ->method('__get')
5426
            ->with('sectionId')
5427
            ->will($this->returnValue(42));
5428
5429
        $repository->expects($this->once())
5430
            ->method('canUser')
5431
            ->with(
5432
                'content',
5433
                'create',
5434
                $contentInfo,
5435
                [$location]
5436
            )
5437
            ->will($this->returnValue(false));
5438
5439
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
5440
        $contentService->copyContent($contentInfo, $locationCreateStruct);
5441
    }
5442
5443
    /**
5444
     * Test for the copyContent() method.
5445
     *
5446
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5447
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5448
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5449
     */
5450
    public function testCopyContent()
5451
    {
5452
        $repositoryMock = $this->getRepositoryMock();
5453
        $contentService = $this->getPartlyMockedContentService([
5454
            'internalLoadContentInfo',
5455
            'internalLoadContent',
5456
            'getUnixTimestamp',
5457
        ]);
5458
        $locationServiceMock = $this->getLocationServiceMock();
5459
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5460
        $locationCreateStruct = new LocationCreateStruct();
5461
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5462
        $user = $this->getStubbedUser(14);
5463
5464
        $permissionResolverMock = $this->getPermissionResolverMock();
5465
5466
        $permissionResolverMock
5467
            ->method('getCurrentUserReference')
5468
            ->willReturn($user);
5469
5470
        $repositoryMock
5471
            ->method('getPermissionResolver')
5472
            ->willReturn($permissionResolverMock);
5473
5474
        $repositoryMock->expects($this->exactly(3))
5475
            ->method('getLocationService')
5476
            ->will($this->returnValue($locationServiceMock));
5477
5478
        $locationServiceMock->expects($this->once())
5479
            ->method('loadLocation')
5480
            ->with($locationCreateStruct->parentLocationId)
5481
            ->will($this->returnValue($location))
5482
        ;
5483
5484
        $contentInfoMock->expects($this->any())
5485
            ->method('__get')
5486
            ->with('id')
5487
            ->will($this->returnValue(42));
5488
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5489
5490
        $versionInfoMock->expects($this->any())
5491
            ->method('__get')
5492
            ->will(
5493
                $this->returnValueMap(
5494
                    [
5495
                        ['versionNo', 123],
5496
                    ]
5497
                )
5498
            );
5499
5500
        $versionInfoMock->expects($this->once())
5501
            ->method('isDraft')
5502
            ->willReturn(true);
5503
5504
        $versionInfoMock->expects($this->once())
5505
            ->method('getContentInfo')
5506
            ->will($this->returnValue($contentInfoMock));
5507
5508
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5509
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5510
        $domainMapperMock = $this->getDomainMapperMock();
5511
5512
        $repositoryMock->expects($this->once())->method('beginTransaction');
5513
        $repositoryMock->expects($this->once())->method('commit');
5514
        $repositoryMock
5515
            ->method('canUser')
5516
            ->willReturnMap(
5517
                [
5518
                    ['content', 'create', $contentInfoMock, [$location], true],
5519
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5520
                ]
5521
            );
5522
5523
        $spiContentInfo = new SPIContentInfo(['id' => 42]);
5524
        $spiVersionInfo = new SPIVersionInfo(
5525
            [
5526
                'contentInfo' => $spiContentInfo,
5527
                'creationDate' => 123456,
5528
            ]
5529
        );
5530
        $spiContent = new SPIContent(['versionInfo' => $spiVersionInfo]);
5531
        $contentHandlerMock->expects($this->once())
5532
            ->method('copy')
5533
            ->with(42, null)
5534
            ->will($this->returnValue($spiContent));
5535
5536
        $this->mockGetDefaultObjectStates();
5537
        $this->mockSetDefaultObjectStates();
5538
5539
        $domainMapperMock->expects($this->once())
5540
            ->method('buildVersionInfoDomainObject')
5541
            ->with($spiVersionInfo)
5542
            ->will($this->returnValue($versionInfoMock));
5543
5544
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5545
        $content = $this->mockPublishVersion(123456, 126666);
5546
        $locationServiceMock->expects($this->once())
5547
            ->method('createLocation')
5548
            ->with(
5549
                $content->getVersionInfo()->getContentInfo(),
5550
                $locationCreateStruct
5551
            );
5552
5553
        $contentService->expects($this->once())
5554
            ->method('internalLoadContent')
5555
            ->with(
5556
                $content->id
5557
            )
5558
            ->will($this->returnValue($content));
5559
5560
        $contentService->expects($this->once())
5561
            ->method('getUnixTimestamp')
5562
            ->will($this->returnValue(126666));
5563
5564
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5565
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5566
    }
5567
5568
    /**
5569
     * Test for the copyContent() method.
5570
     *
5571
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5572
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5573
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5574
     */
5575
    public function testCopyContentWithVersionInfo()
5576
    {
5577
        $repositoryMock = $this->getRepositoryMock();
5578
        $contentService = $this->getPartlyMockedContentService([
5579
            'internalLoadContentInfo',
5580
            'internalLoadContent',
5581
            'getUnixTimestamp',
5582
        ]);
5583
        $locationServiceMock = $this->getLocationServiceMock();
5584
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5585
        $locationCreateStruct = new LocationCreateStruct();
5586
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5587
        $user = $this->getStubbedUser(14);
5588
5589
        $permissionResolverMock = $this->getPermissionResolverMock();
5590
5591
        $permissionResolverMock
5592
            ->method('getCurrentUserReference')
5593
            ->willReturn($user);
5594
5595
        $repositoryMock
5596
            ->method('getPermissionResolver')
5597
            ->willReturn($permissionResolverMock);
5598
5599
        $repositoryMock->expects($this->exactly(3))
5600
            ->method('getLocationService')
5601
            ->will($this->returnValue($locationServiceMock));
5602
5603
        $locationServiceMock->expects($this->once())
5604
            ->method('loadLocation')
5605
            ->with($locationCreateStruct->parentLocationId)
5606
            ->will($this->returnValue($location))
5607
        ;
5608
5609
        $contentInfoMock->expects($this->any())
5610
            ->method('__get')
5611
            ->with('id')
5612
            ->will($this->returnValue(42));
5613
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5614
5615
        $versionInfoMock->expects($this->any())
5616
            ->method('__get')
5617
            ->will(
5618
                $this->returnValueMap(
5619
                    [
5620
                        ['versionNo', 123],
5621
                    ]
5622
                )
5623
            );
5624
        $versionInfoMock->expects($this->once())
5625
            ->method('isDraft')
5626
            ->willReturn(true);
5627
        $versionInfoMock->expects($this->once())
5628
            ->method('getContentInfo')
5629
            ->will($this->returnValue($contentInfoMock));
5630
5631
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5632
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5633
        $domainMapperMock = $this->getDomainMapperMock();
5634
5635
        $repositoryMock->expects($this->once())->method('beginTransaction');
5636
        $repositoryMock->expects($this->once())->method('commit');
5637
        $repositoryMock
5638
            ->method('canUser')
5639
            ->willReturnMap(
5640
                [
5641
                    ['content', 'create', $contentInfoMock, [$location], true],
5642
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5643
                ]
5644
            );
5645
5646
        $spiContentInfo = new SPIContentInfo(['id' => 42]);
5647
        $spiVersionInfo = new SPIVersionInfo(
5648
            [
5649
                'contentInfo' => $spiContentInfo,
5650
                'creationDate' => 123456,
5651
            ]
5652
        );
5653
        $spiContent = new SPIContent(['versionInfo' => $spiVersionInfo]);
5654
        $contentHandlerMock->expects($this->once())
5655
            ->method('copy')
5656
            ->with(42, 123)
5657
            ->will($this->returnValue($spiContent));
5658
5659
        $this->mockGetDefaultObjectStates();
5660
        $this->mockSetDefaultObjectStates();
5661
5662
        $domainMapperMock->expects($this->once())
5663
            ->method('buildVersionInfoDomainObject')
5664
            ->with($spiVersionInfo)
5665
            ->will($this->returnValue($versionInfoMock));
5666
5667
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5668
        $content = $this->mockPublishVersion(123456, 126666);
5669
        $locationServiceMock->expects($this->once())
5670
            ->method('createLocation')
5671
            ->with(
5672
                $content->getVersionInfo()->getContentInfo(),
5673
                $locationCreateStruct
5674
            );
5675
5676
        $contentService->expects($this->once())
5677
            ->method('internalLoadContent')
5678
            ->with(
5679
                $content->id
5680
            )
5681
            ->will($this->returnValue($content));
5682
5683
        $contentService->expects($this->once())
5684
            ->method('getUnixTimestamp')
5685
            ->will($this->returnValue(126666));
5686
5687
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5688
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, $versionInfoMock);
5689
    }
5690
5691
    /**
5692
     * Test for the copyContent() method.
5693
     *
5694
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5695
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5696
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5697
     * @expectedException \Exception
5698
     * @expectedExceptionMessage Handler threw an exception
5699
     */
5700
    public function testCopyContentWithRollback()
5701
    {
5702
        $repositoryMock = $this->getRepositoryMock();
5703
        $contentService = $this->getPartlyMockedContentService();
5704
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5705
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5706
        $locationCreateStruct = new LocationCreateStruct();
5707
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5708
        $locationServiceMock = $this->getLocationServiceMock();
5709
        $user = $this->getStubbedUser(14);
5710
5711
        $permissionResolverMock = $this->getPermissionResolverMock();
5712
5713
        $permissionResolverMock
5714
            ->method('getCurrentUserReference')
5715
            ->willReturn($user);
5716
5717
        $repositoryMock
5718
            ->method('getPermissionResolver')
5719
            ->willReturn($permissionResolverMock);
5720
5721
        $repositoryMock->expects($this->once())
5722
            ->method('getLocationService')
5723
            ->will($this->returnValue($locationServiceMock))
5724
        ;
5725
5726
        $locationServiceMock->expects($this->once())
5727
            ->method('loadLocation')
5728
            ->with($locationCreateStruct->parentLocationId)
5729
            ->will($this->returnValue($location))
5730
        ;
5731
5732
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5733
        $contentInfoMock->expects($this->any())
5734
            ->method('__get')
5735
            ->with('id')
5736
            ->will($this->returnValue(42));
5737
5738
        $this->mockGetDefaultObjectStates();
5739
5740
        $repositoryMock->expects($this->once())->method('beginTransaction');
5741
        $repositoryMock->expects($this->once())->method('rollback');
5742
        $repositoryMock
5743
            ->method('canUser')
5744
            ->willReturnMap(
5745
                [
5746
                    ['content', 'create', $contentInfoMock, [$location], true],
5747
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5748
                ]
5749
            );
5750
5751
        $contentHandlerMock->expects($this->once())
5752
            ->method('copy')
5753
            ->with(42, null)
5754
            ->will($this->throwException(new Exception('Handler threw an exception')));
5755
5756
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5757
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5758
    }
5759
5760
    /**
5761
     * Reusable method for setting exceptions on buildContentDomainObject usage.
5762
     *
5763
     * Plain usage as in when content type is loaded directly.
5764
     *
5765
     * @param \eZ\Publish\SPI\Persistence\Content $spiContent
5766
     * @param array $translations
5767
     * @param bool $useAlwaysAvailable
5768
     *
5769
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\Values\Content\Content
5770
     */
5771
    private function mockBuildContentDomainObject(SPIContent $spiContent, array $translations = null, bool $useAlwaysAvailable = null)
5772
    {
5773
        $contentTypeId = $spiContent->versionInfo->contentInfo->contentTypeId;
5774
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5775
        $repositoryMock = $this->getRepositoryMock();
5776
5777
        $contentType = new ContentType([
5778
            'id' => $contentTypeId,
5779
            'fieldDefinitions' => [],
5780
        ]);
5781
5782
        $repositoryMock->expects($this->once())
5783
            ->method('getContentTypeService')
5784
            ->willReturn($contentTypeServiceMock);
5785
5786
        $contentTypeServiceMock->expects($this->once())
5787
            ->method('loadContentType')
5788
            ->with($this->equalTo($contentTypeId))
5789
            ->willReturn($contentType);
5790
5791
        $content = $this->createMock(APIContent::class);
5792
5793
        $this->getDomainMapperMock()
5794
            ->expects($this->once())
5795
            ->method('buildContentDomainObject')
5796
            ->with($spiContent, $contentType, $translations ?? [], $useAlwaysAvailable)
5797
            ->willReturn($content);
5798
5799
        return $content;
5800
    }
5801
5802
    protected function mockGetDefaultObjectStates()
5803
    {
5804
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5805
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5806
5807
        $objectStateGroups = [
5808
            new SPIObjectStateGroup(['id' => 10]),
5809
            new SPIObjectStateGroup(['id' => 20]),
5810
        ];
5811
5812
        /* @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5813
        $objectStateHandlerMock->expects($this->once())
5814
            ->method('loadAllGroups')
5815
            ->will($this->returnValue($objectStateGroups));
5816
5817
        $objectStateHandlerMock->expects($this->at(1))
5818
            ->method('loadObjectStates')
5819
            ->with($this->equalTo(10))
5820
            ->will(
5821
                $this->returnValue(
5822
                    [
5823
                        new SPIObjectState(['id' => 11, 'groupId' => 10]),
5824
                        new SPIObjectState(['id' => 12, 'groupId' => 10]),
5825
                    ]
5826
                )
5827
            );
5828
5829
        $objectStateHandlerMock->expects($this->at(2))
5830
            ->method('loadObjectStates')
5831
            ->with($this->equalTo(20))
5832
            ->will(
5833
                $this->returnValue(
5834
                    [
5835
                        new SPIObjectState(['id' => 21, 'groupId' => 20]),
5836
                        new SPIObjectState(['id' => 22, 'groupId' => 20]),
5837
                    ]
5838
                )
5839
            );
5840
    }
5841
5842
    protected function mockSetDefaultObjectStates()
5843
    {
5844
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5845
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5846
5847
        $defaultObjectStates = [
5848
            new SPIObjectState(['id' => 11, 'groupId' => 10]),
5849
            new SPIObjectState(['id' => 21, 'groupId' => 20]),
5850
        ];
5851
        foreach ($defaultObjectStates as $index => $objectState) {
5852
            $objectStateHandlerMock->expects($this->at($index + 3))
5853
                ->method('setContentState')
5854
                ->with(
5855
                    42,
5856
                    $objectState->groupId,
5857
                    $objectState->id
5858
                );
5859
        }
5860
    }
5861
5862
    /**
5863
     * @param int|null $publicationDate
5864
     * @param int|null $modificationDate
5865
     *
5866
     * @return \eZ\Publish\API\Repository\Values\Content\Content
5867
     */
5868
    protected function mockPublishVersion($publicationDate = null, $modificationDate = null)
5869
    {
5870
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5871
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5872
        /* @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5873
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5874
        $metadataUpdateStruct = new SPIMetadataUpdateStruct();
5875
5876
        $spiContent = new SPIContent([
5877
            'versionInfo' => new VersionInfo([
5878
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
5879
            ]),
5880
        ]);
5881
5882
        $contentMock = $this->mockBuildContentDomainObject($spiContent);
5883
        $contentMock->expects($this->any())
5884
            ->method('__get')
5885
            ->will(
5886
                $this->returnValueMap(
5887
                    [
5888
                        ['id', 42],
5889
                        ['contentInfo', $contentInfoMock],
5890
                        ['versionInfo', $versionInfoMock],
5891
                    ]
5892
                )
5893
            );
5894
        $contentMock->expects($this->any())
5895
            ->method('getVersionInfo')
5896
            ->will($this->returnValue($versionInfoMock));
5897
        $versionInfoMock->expects($this->any())
5898
            ->method('getContentInfo')
5899
            ->will($this->returnValue($contentInfoMock));
5900
        $versionInfoMock->expects($this->any())
5901
            ->method('__get')
5902
            ->will(
5903
                $this->returnValueMap(
5904
                    [
5905
                        ['languageCodes', ['eng-GB']],
5906
                    ]
5907
                )
5908
            );
5909
        $contentInfoMock->expects($this->any())
5910
            ->method('__get')
5911
            ->will(
5912
                $this->returnValueMap(
5913
                    [
5914
                        ['alwaysAvailable', true],
5915
                        ['mainLanguageCode', 'eng-GB'],
5916
                    ]
5917
                )
5918
            );
5919
5920
        $currentTime = time();
5921
        if ($publicationDate === null && $versionInfoMock->versionNo === 1) {
5922
            $publicationDate = $currentTime;
5923
        }
5924
5925
        // Account for 1 second of test execution time
5926
        $metadataUpdateStruct->publicationDate = $publicationDate;
5927
        $metadataUpdateStruct->modificationDate = $modificationDate ?? $currentTime;
5928
5929
        $contentHandlerMock->expects($this->once())
5930
            ->method('publish')
5931
            ->with(
5932
                42,
5933
                123,
5934
                $metadataUpdateStruct
5935
            )
5936
            ->will($this->returnValue($spiContent));
5937
5938
        /* @var \eZ\Publish\API\Repository\Values\Content\Content $contentMock */
5939
        $this->mockPublishUrlAliasesForContent($contentMock);
5940
5941
        return $contentMock;
5942
    }
5943
5944
    /**
5945
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
5946
     */
5947
    protected function mockPublishUrlAliasesForContent(APIContent $content)
5948
    {
5949
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
5950
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandlerMock */
5951
        $urlAliasHandlerMock = $this->getPersistenceMock()->urlAliasHandler();
5952
        $locationServiceMock = $this->getLocationServiceMock();
5953
        $location = $this->createMock(APILocation::class);
5954
5955
        $location->expects($this->at(0))
5956
            ->method('__get')
5957
            ->with('id')
5958
            ->will($this->returnValue(123));
5959
        $location->expects($this->at(1))
5960
            ->method('__get')
5961
            ->with('parentLocationId')
5962
            ->will($this->returnValue(456));
5963
5964
        $urlAliasNames = ['eng-GB' => 'hello'];
5965
        $nameSchemaServiceMock->expects($this->once())
5966
            ->method('resolveUrlAliasSchema')
5967
            ->with($content)
5968
            ->will($this->returnValue($urlAliasNames));
5969
5970
        $locationServiceMock->expects($this->once())
5971
            ->method('loadLocations')
5972
            ->with($content->getVersionInfo()->getContentInfo())
5973
            ->will($this->returnValue([$location]));
5974
5975
        $urlAliasHandlerMock->expects($this->once())
5976
            ->method('publishUrlAliasForLocation')
5977
            ->with(123, 456, 'hello', 'eng-GB', true, true);
5978
5979
        $location->expects($this->at(2))
5980
            ->method('__get')
5981
            ->with('id')
5982
            ->will($this->returnValue(123));
5983
5984
        $location->expects($this->at(3))
5985
            ->method('__get')
5986
            ->with('parentLocationId')
5987
            ->will($this->returnValue(456));
5988
5989
        $urlAliasHandlerMock->expects($this->once())
5990
            ->method('archiveUrlAliasesForDeletedTranslations')
5991
            ->with(123, 456, ['eng-GB']);
5992
    }
5993
5994
    protected $domainMapperMock;
5995
5996
    /**
5997
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\DomainMapper
5998
     */
5999
    protected function getDomainMapperMock()
6000
    {
6001
        if (!isset($this->domainMapperMock)) {
6002
            $this->domainMapperMock = $this->createMock(DomainMapper::class);
6003
        }
6004
6005
        return $this->domainMapperMock;
6006
    }
6007
6008
    protected $relationProcessorMock;
6009
6010
    /**
6011
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\RelationProcessor
6012
     */
6013
    protected function getRelationProcessorMock()
6014
    {
6015
        if (!isset($this->relationProcessorMock)) {
6016
            $this->relationProcessorMock = $this->createMock(RelationProcessor::class);
6017
        }
6018
6019
        return $this->relationProcessorMock;
6020
    }
6021
6022
    protected $nameSchemaServiceMock;
6023
6024
    /**
6025
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\NameSchemaService
6026
     */
6027
    protected function getNameSchemaServiceMock()
6028
    {
6029
        if (!isset($this->nameSchemaServiceMock)) {
6030
            $this->nameSchemaServiceMock = $this->createMock(NameSchemaService::class);
6031
        }
6032
6033
        return $this->nameSchemaServiceMock;
6034
    }
6035
6036
    protected $contentTypeServiceMock;
6037
6038
    /**
6039
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\ContentTypeService
6040
     */
6041
    protected function getContentTypeServiceMock()
6042
    {
6043
        if (!isset($this->contentTypeServiceMock)) {
6044
            $this->contentTypeServiceMock = $this->createMock(APIContentTypeService::class);
6045
        }
6046
6047
        return $this->contentTypeServiceMock;
6048
    }
6049
6050
    protected $locationServiceMock;
6051
6052
    /**
6053
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\LocationService
6054
     */
6055
    protected function getLocationServiceMock()
6056
    {
6057
        if (!isset($this->locationServiceMock)) {
6058
            $this->locationServiceMock = $this->createMock(APILocationService::class);
6059
        }
6060
6061
        return $this->locationServiceMock;
6062
    }
6063
6064
    /** @var \eZ\Publish\Core\Repository\ContentService */
6065
    protected $partlyMockedContentService;
6066
6067
    /**
6068
     * Returns the content service to test with $methods mocked.
6069
     *
6070
     * Injected Repository comes from {@see getRepositoryMock()} and persistence handler from {@see getPersistenceMock()}
6071
     *
6072
     * @param string[] $methods
6073
     *
6074
     * @return \eZ\Publish\Core\Repository\ContentService|\PHPUnit\Framework\MockObject\MockObject
6075
     */
6076
    protected function getPartlyMockedContentService(array $methods = null)
6077
    {
6078
        if (!isset($this->partlyMockedContentService)) {
6079
            $this->partlyMockedContentService = $this->getMockBuilder(ContentService::class)
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getMockBuilder(\e...), array()))->getMock() of type object<PHPUnit\Framework\MockObject\MockObject> is incompatible with the declared type object<eZ\Publish\Core\Repository\ContentService> of property $partlyMockedContentService.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
6080
                ->setMethods($methods)
6081
                ->setConstructorArgs(
6082
                    [
6083
                        $this->getRepositoryMock(),
6084
                        $this->getPersistenceMock(),
6085
                        $this->getDomainMapperMock(),
6086
                        $this->getRelationProcessorMock(),
6087
                        $this->getNameSchemaServiceMock(),
6088
                        $this->getFieldTypeRegistryMock(),
6089
                        [],
6090
                    ]
6091
                )
6092
                ->getMock();
6093
        }
6094
6095
        return $this->partlyMockedContentService;
6096
    }
6097
6098
    /**
6099
     * @return \eZ\Publish\API\Repository\Repository|\PHPUnit\Framework\MockObject\MockObject
6100
     */
6101
    protected function getRepositoryMock(): Repository
6102
    {
6103
        $repositoryMock = parent::getRepositoryMock();
6104
        $repositoryMock
6105
            ->expects($this->any())
6106
            ->method('getPermissionResolver')
6107
            ->willReturn($this->getPermissionResolverMock());
6108
6109
        return $repositoryMock;
6110
    }
6111
}
6112