Completed
Push — master ( 161dc8...90572a )
by
unknown
27:22 queued 10:00
created

ContentTest::testCreateContentWithLocations()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 127

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 127
rs 8
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * File 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.
137
     *
138
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
139
     */
140
    public function testLoadVersionInfoById()
141
    {
142
        $repository = $this->getRepositoryMock();
143
        $contentServiceMock = $this->getPartlyMockedContentService(array('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->once())
154
            ->method('loadContentInfo')
155
            ->with($this->equalTo(42))
156
            ->will(
157
                $this->returnValue(
158
                    new ContentInfo(array('currentVersionNo' => 24))
159
                )
160
            );
161
162
        $contentHandler->expects($this->once())
163
            ->method('loadVersionInfo')
164
            ->with(
165
                $this->equalTo(42),
166
                $this->equalTo(24)
167
            )->will(
168
                $this->returnValue(new SPIVersionInfo())
169
            );
170
171
        $domainMapperMock->expects($this->once())
172
            ->method('buildVersionInfoDomainObject')
173
            ->with(new SPIVersionInfo())
174
            ->will($this->returnValue($versionInfoMock));
175
176
        $repository->expects($this->once())
177
            ->method('canUser')
178
            ->with(
179
                $this->equalTo('content'),
180
                $this->equalTo('read'),
181
                $this->equalTo($versionInfoMock)
182
            )->will($this->returnValue(true));
183
184
        $result = $contentServiceMock->loadVersionInfoById(42);
185
186
        $this->assertEquals($versionInfoMock, $result);
187
    }
188
189
    /**
190
     * Test for the loadVersionInfo() method.
191
     *
192
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
193
     */
194
    public function testLoadVersionInfoByIdThrowsNotFoundException()
195
    {
196
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFoundException::class);
197
198
        $contentServiceMock = $this->getPartlyMockedContentService(array('loadContentInfo'));
199
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
200
        $contentHandler = $this->getPersistenceMock()->contentHandler();
201
202
        $contentHandler->expects($this->once())
203
            ->method('loadVersionInfo')
204
            ->with(
205
                $this->equalTo(42),
206
                $this->equalTo(24)
207
            )->will(
208
                $this->throwException(
209
                    new NotFoundException(
210
                        'Content',
211
                        array(
212
                            'contentId' => 42,
213
                            'versionNo' => 24,
214
                        )
215
                    )
216
                )
217
            );
218
219
        $contentServiceMock->loadVersionInfoById(42, 24);
220
    }
221
222
    /**
223
     * Test for the loadVersionInfo() method.
224
     *
225
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
226
     */
227
    public function testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion()
228
    {
229
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
230
231
        $repository = $this->getRepositoryMock();
232
        $contentServiceMock = $this->getPartlyMockedContentService();
233
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
234
        $contentHandler = $this->getPersistenceMock()->contentHandler();
235
        $domainMapperMock = $this->getDomainMapperMock();
236
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
237
238
        $versionInfoMock->expects($this->any())
239
            ->method('isPublished')
240
            ->willReturn(false);
241
242
        $contentHandler->expects($this->once())
243
            ->method('loadVersionInfo')
244
            ->with(
245
                $this->equalTo(42),
246
                $this->equalTo(24)
247
            )->will(
248
                $this->returnValue(new SPIVersionInfo())
249
            );
250
251
        $domainMapperMock->expects($this->once())
252
            ->method('buildVersionInfoDomainObject')
253
            ->with(new SPIVersionInfo())
254
            ->will($this->returnValue($versionInfoMock));
255
256
        $repository->expects($this->once())
257
            ->method('canUser')
258
            ->with(
259
                $this->equalTo('content'),
260
                $this->equalTo('versionread'),
261
                $this->equalTo($versionInfoMock)
262
            )->will($this->returnValue(false));
263
264
        $contentServiceMock->loadVersionInfoById(42, 24);
265
    }
266
267
    /**
268
     * Test for the loadVersionInfo() method.
269
     *
270
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
271
     */
272 View Code Duplication
    public function testLoadVersionInfoByIdPublishedVersion()
273
    {
274
        $repository = $this->getRepositoryMock();
275
        $contentServiceMock = $this->getPartlyMockedContentService();
276
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
277
        $contentHandler = $this->getPersistenceMock()->contentHandler();
278
        $domainMapperMock = $this->getDomainMapperMock();
279
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
280
281
        $versionInfoMock->expects($this->once())
282
            ->method('isPublished')
283
            ->willReturn(true);
284
285
        $contentHandler->expects($this->once())
286
            ->method('loadVersionInfo')
287
            ->with(
288
                $this->equalTo(42),
289
                $this->equalTo(24)
290
            )->will(
291
                $this->returnValue(new SPIVersionInfo())
292
            );
293
294
        $domainMapperMock->expects($this->once())
295
            ->method('buildVersionInfoDomainObject')
296
            ->with(new SPIVersionInfo())
297
            ->will($this->returnValue($versionInfoMock));
298
299
        $repository->expects($this->once())
300
            ->method('canUser')
301
            ->with(
302
                $this->equalTo('content'),
303
                $this->equalTo('read'),
304
                $this->equalTo($versionInfoMock)
305
            )->will($this->returnValue(true));
306
307
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
308
309
        $this->assertEquals($versionInfoMock, $result);
310
    }
311
312
    /**
313
     * Test for the loadVersionInfo() method.
314
     *
315
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
316
     */
317 View Code Duplication
    public function testLoadVersionInfoByIdNonPublishedVersion()
318
    {
319
        $repository = $this->getRepositoryMock();
320
        $contentServiceMock = $this->getPartlyMockedContentService();
321
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
322
        $contentHandler = $this->getPersistenceMock()->contentHandler();
323
        $domainMapperMock = $this->getDomainMapperMock();
324
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
325
326
        $versionInfoMock->expects($this->once())
327
            ->method('isPublished')
328
            ->willReturn(false);
329
330
        $contentHandler->expects($this->once())
331
            ->method('loadVersionInfo')
332
            ->with(
333
                $this->equalTo(42),
334
                $this->equalTo(24)
335
            )->will(
336
                $this->returnValue(new SPIVersionInfo())
337
            );
338
339
        $domainMapperMock->expects($this->once())
340
            ->method('buildVersionInfoDomainObject')
341
            ->with(new SPIVersionInfo())
342
            ->will($this->returnValue($versionInfoMock));
343
344
        $repository->expects($this->once())
345
            ->method('canUser')
346
            ->with(
347
                $this->equalTo('content'),
348
                $this->equalTo('versionread'),
349
                $this->equalTo($versionInfoMock)
350
            )->will($this->returnValue(true));
351
352
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
353
354
        $this->assertEquals($versionInfoMock, $result);
355
    }
356
357
    /**
358
     * Test for the loadVersionInfo() method.
359
     *
360
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfo
361
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoById
362
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsNotFoundException
363
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion
364
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdPublishedVersion
365
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdNonPublishedVersion
366
     */
367
    public function testLoadVersionInfo()
368
    {
369
        $contentServiceMock = $this->getPartlyMockedContentService(
370
            array('loadVersionInfoById')
371
        );
372
        $contentServiceMock->expects(
373
            $this->once()
374
        )->method(
375
            'loadVersionInfoById'
376
        )->with(
377
            $this->equalTo(42),
378
            $this->equalTo(7)
379
        )->will(
380
            $this->returnValue('result')
381
        );
382
383
        $result = $contentServiceMock->loadVersionInfo(
384
            new ContentInfo(array('id' => 42)),
385
            7
386
        );
387
388
        $this->assertEquals('result', $result);
389
    }
390
391
    public function testLoadContent()
392
    {
393
        $repository = $this->getRepositoryMock();
394
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
395
        $content = $this->createMock(APIContent::class);
396
        $versionInfo = $this->createMock(APIVersionInfo::class);
397
        $content
398
            ->expects($this->once())
399
            ->method('getVersionInfo')
400
            ->will($this->returnValue($versionInfo));
401
        $versionInfo
402
            ->expects($this->once())
403
            ->method('isPublished')
404
            ->willReturn(true);
405
        $contentId = 123;
406
        $contentService
407
            ->expects($this->once())
408
            ->method('internalLoadContent')
409
            ->with($contentId)
410
            ->will($this->returnValue($content));
411
412
        $repository
413
            ->expects($this->once())
414
            ->method('canUser')
415
            ->with('content', 'read', $content)
416
            ->will($this->returnValue(true));
417
418
        $this->assertSame($content, $contentService->loadContent($contentId));
419
    }
420
421 View Code Duplication
    public function testLoadContentNonPublished()
422
    {
423
        $repository = $this->getRepositoryMock();
424
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
425
        $content = $this->createMock(APIContent::class);
426
        $versionInfo = $this
427
            ->getMockBuilder(APIVersionInfo::class)
428
            ->getMockForAbstractClass();
429
        $content
430
            ->expects($this->once())
431
            ->method('getVersionInfo')
432
            ->will($this->returnValue($versionInfo));
433
        $contentId = 123;
434
        $contentService
435
            ->expects($this->once())
436
            ->method('internalLoadContent')
437
            ->with($contentId)
438
            ->will($this->returnValue($content));
439
440
        $repository
441
            ->expects($this->exactly(2))
442
            ->method('canUser')
443
            ->will(
444
                $this->returnValueMap(
445
                    array(
446
                        array('content', 'read', $content, null, true),
447
                        array('content', 'versionread', $content, null, true),
448
                    )
449
                )
450
            );
451
452
        $this->assertSame($content, $contentService->loadContent($contentId));
453
    }
454
455
    /**
456
     */
457
    public function testLoadContentUnauthorized()
458
    {
459
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
460
461
        $repository = $this->getRepositoryMock();
462
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
463
        $content = $this->createMock(APIContent::class);
464
        $contentId = 123;
465
        $contentService
466
            ->expects($this->once())
467
            ->method('internalLoadContent')
468
            ->with($contentId)
469
            ->will($this->returnValue($content));
470
471
        $repository
472
            ->expects($this->once())
473
            ->method('canUser')
474
            ->with('content', 'read', $content)
475
            ->will($this->returnValue(false));
476
477
        $contentService->loadContent($contentId);
478
    }
479
480
    /**
481
     */
482 View Code Duplication
    public function testLoadContentNotPublishedStatusUnauthorized()
483
    {
484
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
485
486
        $repository = $this->getRepositoryMock();
487
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
488
        $content = $this->createMock(APIContent::class);
489
        $versionInfo = $this
490
            ->getMockBuilder(APIVersionInfo::class)
491
            ->getMockForAbstractClass();
492
        $content
493
            ->expects($this->once())
494
            ->method('getVersionInfo')
495
            ->will($this->returnValue($versionInfo));
496
        $contentId = 123;
497
        $contentService
498
            ->expects($this->once())
499
            ->method('internalLoadContent')
500
            ->with($contentId)
501
            ->will($this->returnValue($content));
502
503
        $repository
504
            ->expects($this->exactly(2))
505
            ->method('canUser')
506
            ->will(
507
                $this->returnValueMap(
508
                    array(
509
                        array('content', 'read', $content, null, true),
510
                        array('content', 'versionread', $content, null, false),
511
                    )
512
                )
513
            );
514
515
        $contentService->loadContent($contentId);
516
    }
517
518
    /**
519
     * @dataProvider internalLoadContentProvider
520
     */
521
    public function testInternalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
522
    {
523
        $contentService = $this->getPartlyMockedContentService();
524
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
525
        $contentHandler = $this->getPersistenceMock()->contentHandler();
526
        $realId = $id;
527
528
        if ($isRemoteId) {
529
            $realId = 123;
530
            $spiContentInfo = new SPIContentInfo(array('currentVersionNo' => $versionNo ?: 7, 'id' => $realId));
531
            $contentHandler
532
                ->expects($this->once())
533
                ->method('loadContentInfoByRemoteId')
534
                ->with($id)
535
                ->will($this->returnValue($spiContentInfo));
536
        } elseif (!empty($languages) && $useAlwaysAvailable) {
537
            $spiContentInfo = new SPIContentInfo(array('alwaysAvailable' => false));
538
            $contentHandler
539
                ->expects($this->once())
540
                ->method('loadContentInfo')
541
                ->with($id)
542
                ->will($this->returnValue($spiContentInfo));
543
        }
544
545
        $spiContent = new SPIContent([
546
            'versionInfo' => new VersionInfo([
547
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
548
            ]),
549
        ]);
550
        $contentHandler
551
            ->expects($this->once())
552
            ->method('load')
553
            ->with($realId, $versionNo, $languages)
554
            ->willReturn($spiContent);
555
556
        $content = $this->mockBuildContentDomainObject($spiContent, $languages);
557
558
        $this->assertSame(
559
            $content,
560
            $contentService->internalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
561
        );
562
    }
563
564
    public function internalLoadContentProvider()
565
    {
566
        return array(
567
            array(123, null, null, false, false),
568
            array(123, null, 456, false, false),
569
            array(456, null, 123, false, true),
570
            array(456, null, 2, false, false),
571
            array(456, array('eng-GB'), 2, false, true),
572
            array(456, array('eng-GB', 'fre-FR'), null, false, false),
573
            array(456, array('eng-GB', 'fre-FR', 'nor-NO'), 2, false, false),
574
            // With remoteId
575
            array(123, null, null, true, false),
576
            array('someRemoteId', null, 456, true, false),
577
            array(456, null, 123, true, false),
578
            array('someRemoteId', null, 2, true, false),
579
            array('someRemoteId', array('eng-GB'), 2, true, false),
580
            array(456, array('eng-GB', 'fre-FR'), null, true, false),
581
            array('someRemoteId', array('eng-GB', 'fre-FR', 'nor-NO'), 2, true, false),
582
        );
583
    }
584
585
    /**
586
     */
587
    public function testInternalLoadContentNotFound()
588
    {
589
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFoundException::class);
590
591
        $contentService = $this->getPartlyMockedContentService();
592
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
593
        $contentHandler = $this->getPersistenceMock()->contentHandler();
594
        $id = 123;
595
        $versionNo = 7;
596
        $languages = null;
597
        $contentHandler
598
            ->expects($this->once())
599
            ->method('load')
600
            ->with($id, $versionNo, $languages)
601
            ->will(
602
                $this->throwException(
603
                    $this->createMock(APINotFoundException::class)
604
                )
605
            );
606
607
        $contentService->internalLoadContent($id, $languages, $versionNo);
608
    }
609
610
    /**
611
     * Test for the loadContentByContentInfo() method.
612
     *
613
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByContentInfo
614
     */
615
    public function testLoadContentByContentInfo()
616
    {
617
        $contentServiceMock = $this->getPartlyMockedContentService(
618
            array('loadContent')
619
        );
620
        $contentServiceMock->expects(
621
            $this->once()
622
        )->method(
623
            'loadContent'
624
        )->with(
625
            $this->equalTo(42),
626
            $this->equalTo(array('cro-HR')),
627
            $this->equalTo(7),
628
            $this->equalTo(false)
629
        )->will(
630
            $this->returnValue('result')
631
        );
632
633
        $result = $contentServiceMock->loadContentByContentInfo(
634
            new ContentInfo(array('id' => 42)),
635
            array('cro-HR'),
636
            7
637
        );
638
639
        $this->assertEquals('result', $result);
640
    }
641
642
    /**
643
     * Test for the loadContentByVersionInfo() method.
644
     *
645
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByVersionInfo
646
     */
647
    public function testLoadContentByVersionInfo()
648
    {
649
        $contentServiceMock = $this->getPartlyMockedContentService(
650
            array('loadContent')
651
        );
652
        $contentServiceMock->expects(
653
            $this->once()
654
        )->method(
655
            'loadContent'
656
        )->with(
657
            $this->equalTo(42),
658
            $this->equalTo(array('cro-HR')),
659
            $this->equalTo(7),
660
            $this->equalTo(false)
661
        )->will(
662
            $this->returnValue('result')
663
        );
664
665
        $result = $contentServiceMock->loadContentByVersionInfo(
666
            new VersionInfo(
667
                array(
668
                    'contentInfo' => new ContentInfo(array('id' => 42)),
669
                    'versionNo' => 7,
670
                )
671
            ),
672
            array('cro-HR')
673
        );
674
675
        $this->assertEquals('result', $result);
676
    }
677
678
    /**
679
     * Test for the deleteContent() method.
680
     *
681
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
682
     */
683
    public function testDeleteContentThrowsUnauthorizedException()
684
    {
685
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
686
687
        $repository = $this->getRepositoryMock();
688
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
689
        $contentInfo = $this->createMock(APIContentInfo::class);
690
691
        $contentInfo->expects($this->any())
692
            ->method('__get')
693
            ->with('id')
694
            ->will($this->returnValue(42));
695
696
        $contentService->expects($this->once())
697
            ->method('internalLoadContentInfo')
698
            ->with(42)
699
            ->will($this->returnValue($contentInfo));
700
701
        $repository->expects($this->once())
702
            ->method('canUser')
703
            ->with('content', 'remove')
704
            ->will($this->returnValue(false));
705
706
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
707
        $contentService->deleteContent($contentInfo);
708
    }
709
710
    /**
711
     * Test for the deleteContent() method.
712
     *
713
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
714
     */
715
    public function testDeleteContent()
716
    {
717
        $repository = $this->getRepositoryMock();
718
719
        $repository->expects($this->once())
720
            ->method('canUser')
721
            ->with('content', 'remove')
722
            ->will($this->returnValue(true));
723
724
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
725
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandler */
726
        $urlAliasHandler = $this->getPersistenceMock()->urlAliasHandler();
727
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
728
        $locationHandler = $this->getPersistenceMock()->locationHandler();
729
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
730
        $contentHandler = $this->getPersistenceMock()->contentHandler();
731
732
        $contentInfo = $this->createMock(APIContentInfo::class);
733
734
        $contentService->expects($this->once())
735
            ->method('internalLoadContentInfo')
736
            ->with(42)
737
            ->will($this->returnValue($contentInfo));
738
739
        $contentInfo->expects($this->any())
740
            ->method('__get')
741
            ->with('id')
742
            ->will($this->returnValue(42));
743
744
        $repository->expects($this->once())->method('beginTransaction');
745
746
        $spiLocations = array(
747
            new SPILocation(array('id' => 1)),
748
            new SPILocation(array('id' => 2)),
749
        );
750
        $locationHandler->expects($this->once())
751
            ->method('loadLocationsByContent')
752
            ->with(42)
753
            ->will($this->returnValue($spiLocations));
754
755
        $contentHandler->expects($this->once())
756
            ->method('deleteContent')
757
            ->with(42);
758
759
        foreach ($spiLocations as $index => $spiLocation) {
760
            $urlAliasHandler->expects($this->at($index))
761
                ->method('locationDeleted')
762
                ->with($spiLocation->id);
763
        }
764
765
        $repository->expects($this->once())->method('commit');
766
767
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
768
        $contentService->deleteContent($contentInfo);
769
    }
770
771
    /**
772
     * Test for the deleteContent() method.
773
     *
774
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
775
     */
776
    public function testDeleteContentWithRollback()
777
    {
778
        $this->expectException(\Exception::class);
779
780
        $repository = $this->getRepositoryMock();
781
782
        $repository->expects($this->once())
783
            ->method('canUser')
784
            ->with('content', 'remove')
785
            ->will($this->returnValue(true));
786
787
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
788
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
789
        $locationHandler = $this->getPersistenceMock()->locationHandler();
790
791
        $contentInfo = $this->createMock(APIContentInfo::class);
792
793
        $contentService->expects($this->once())
794
            ->method('internalLoadContentInfo')
795
            ->with(42)
796
            ->will($this->returnValue($contentInfo));
797
798
        $contentInfo->expects($this->any())
799
            ->method('__get')
800
            ->with('id')
801
            ->will($this->returnValue(42));
802
803
        $repository->expects($this->once())->method('beginTransaction');
804
805
        $locationHandler->expects($this->once())
806
            ->method('loadLocationsByContent')
807
            ->with(42)
808
            ->will($this->throwException(new \Exception()));
809
810
        $repository->expects($this->once())->method('rollback');
811
812
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
813
        $contentService->deleteContent($contentInfo);
814
    }
815
816
    /**
817
     * Test for the deleteVersion() method.
818
     *
819
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
820
     */
821
    public function testDeleteVersionThrowsBadStateExceptionLastVersion()
822
    {
823
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
824
825
        $repository = $this->getRepositoryMock();
826
        $repository
827
            ->expects($this->once())
828
            ->method('canUser')
829
            ->with('content', 'versionremove')
830
            ->will($this->returnValue(true));
831
        $repository
832
            ->expects($this->never())
833
            ->method('beginTransaction');
834
835
        $contentService = $this->getPartlyMockedContentService();
836
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
837
        $contentHandler = $this->getPersistenceMock()->contentHandler();
838
        $contentInfo = $this->createMock(APIContentInfo::class);
839
        $versionInfo = $this->createMock(APIVersionInfo::class);
840
841
        $contentInfo
842
            ->expects($this->any())
843
            ->method('__get')
844
            ->with('id')
845
            ->will($this->returnValue(42));
846
847
        $versionInfo
848
            ->expects($this->any())
849
            ->method('__get')
850
            ->will(
851
                $this->returnValueMap(
852
                    array(
853
                        array('versionNo', 123),
854
                        array('contentInfo', $contentInfo),
855
                    )
856
                )
857
            );
858
        $versionInfo
859
            ->expects($this->once())
860
            ->method('isPublished')
861
            ->willReturn(false);
862
863
        $contentHandler
864
            ->expects($this->once())
865
            ->method('listVersions')
866
            ->with(42)
867
            ->will($this->returnValue(array('version')));
868
869
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo */
870
        $contentService->deleteVersion($versionInfo);
871
    }
872
873
    /**
874
     * Test for the createContent() method.
875
     *
876
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
877
     */
878 View Code Duplication
    public function testCreateContentThrowsInvalidArgumentExceptionMainLanguageCodeNotSet()
879
    {
880
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
881
        $this->expectExceptionMessage('Argument \'$contentCreateStruct\' is invalid: \'mainLanguageCode\' property must be set');
882
883
        $mockedService = $this->getPartlyMockedContentService();
884
        $mockedService->createContent(new ContentCreateStruct(), array());
885
    }
886
887
    /**
888
     * Test for the createContent() method.
889
     *
890
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
891
     */
892 View Code Duplication
    public function testCreateContentThrowsInvalidArgumentExceptionContentTypeNotSet()
893
    {
894
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
895
        $this->expectExceptionMessage('Argument \'$contentCreateStruct\' is invalid: \'contentType\' property must be set');
896
897
        $mockedService = $this->getPartlyMockedContentService();
898
        $mockedService->createContent(
899
            new ContentCreateStruct(array('mainLanguageCode' => 'eng-US')),
900
            array()
901
        );
902
    }
903
904
    /**
905
     * Test for the createContent() method.
906
     *
907
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
908
     */
909
    public function testCreateContentThrowsUnauthorizedException()
910
    {
911
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
912
913
        $repositoryMock = $this->getRepositoryMock();
914
        $mockedService = $this->getPartlyMockedContentService();
915
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
916
        $contentType = new ContentType(
917
            array(
918
                'id' => 123,
919
                'fieldDefinitions' => array(),
920
            )
921
        );
922
        $contentCreateStruct = new ContentCreateStruct(
923
            array(
924
                'ownerId' => 169,
925
                'alwaysAvailable' => false,
926
                'mainLanguageCode' => 'eng-US',
927
                'contentType' => $contentType,
928
            )
929
        );
930
931
        $repositoryMock->expects($this->once())
932
            ->method('getCurrentUserReference')
933
            ->will($this->returnValue(new UserReference(169)));
934
935
        $contentTypeServiceMock->expects($this->once())
936
            ->method('loadContentType')
937
            ->with($this->equalTo(123))
938
            ->will($this->returnValue($contentType));
939
940
        $repositoryMock->expects($this->once())
941
            ->method('getContentTypeService')
942
            ->will($this->returnValue($contentTypeServiceMock));
943
944
        $repositoryMock->expects($this->once())
945
            ->method('canUser')
946
            ->with(
947
                $this->equalTo('content'),
948
                $this->equalTo('create'),
949
                $this->isInstanceOf(get_class($contentCreateStruct)),
950
                $this->equalTo(array())
951
            )->will($this->returnValue(false));
952
953
        $mockedService->createContent(
954
            new ContentCreateStruct(
955
                array(
956
                    'mainLanguageCode' => 'eng-US',
957
                    'contentType' => $contentType,
958
                )
959
            ),
960
            array()
961
        );
962
    }
963
964
    /**
965
     * Test for the createContent() method.
966
     *
967
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
968
     * @exceptionMessage Argument '$contentCreateStruct' is invalid: Another content with remoteId 'faraday' exists
969
     */
970
    public function testCreateContentThrowsInvalidArgumentExceptionDuplicateRemoteId()
971
    {
972
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
973
974
        $repositoryMock = $this->getRepositoryMock();
975
        $mockedService = $this->getPartlyMockedContentService(array('loadContentByRemoteId'));
976
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
977
        $contentType = new ContentType(
978
            array(
979
                'id' => 123,
980
                'fieldDefinitions' => array(),
981
            )
982
        );
983
        $contentCreateStruct = new ContentCreateStruct(
984
            array(
985
                'ownerId' => 169,
986
                'alwaysAvailable' => false,
987
                'remoteId' => 'faraday',
988
                'mainLanguageCode' => 'eng-US',
989
                'contentType' => $contentType,
990
            )
991
        );
992
993
        $repositoryMock->expects($this->once())
994
            ->method('getCurrentUserReference')
995
            ->will($this->returnValue(new UserReference(169)));
996
997
        $contentTypeServiceMock->expects($this->once())
998
            ->method('loadContentType')
999
            ->with($this->equalTo(123))
1000
            ->will($this->returnValue($contentType));
1001
1002
        $repositoryMock->expects($this->once())
1003
            ->method('getContentTypeService')
1004
            ->will($this->returnValue($contentTypeServiceMock));
1005
1006
        $repositoryMock->expects($this->once())
1007
            ->method('canUser')
1008
            ->with(
1009
                $this->equalTo('content'),
1010
                $this->equalTo('create'),
1011
                $this->isInstanceOf(get_class($contentCreateStruct)),
1012
                $this->equalTo(array())
1013
            )->will($this->returnValue(true));
1014
1015
        $mockedService->expects($this->once())
1016
            ->method('loadContentByRemoteId')
1017
            ->with($contentCreateStruct->remoteId)
1018
            ->will($this->returnValue('Hello...'));
1019
1020
        $mockedService->createContent(
1021
            new ContentCreateStruct(
1022
                array(
1023
                    'remoteId' => 'faraday',
1024
                    'mainLanguageCode' => 'eng-US',
1025
                    'contentType' => $contentType,
1026
                )
1027
            ),
1028
            array()
1029
        );
1030
    }
1031
1032
    /**
1033
     * @param string $mainLanguageCode
1034
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1035
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1036
     *
1037
     * @return array
1038
     */
1039
    protected function mapStructFieldsForCreate($mainLanguageCode, $structFields, $fieldDefinitions)
1040
    {
1041
        $mappedFieldDefinitions = array();
1042
        foreach ($fieldDefinitions as $fieldDefinition) {
1043
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
1044
        }
1045
1046
        $mappedStructFields = array();
1047
        foreach ($structFields as $structField) {
1048
            if ($structField->languageCode === null) {
1049
                $languageCode = $mainLanguageCode;
1050
            } else {
1051
                $languageCode = $structField->languageCode;
1052
            }
1053
1054
            $mappedStructFields[$structField->fieldDefIdentifier][$languageCode] = (string)$structField->value;
1055
        }
1056
1057
        return $mappedStructFields;
1058
    }
1059
1060
    /**
1061
     * Returns full, possibly redundant array of field values, indexed by field definition
1062
     * identifier and language code.
1063
     *
1064
     * @throws \RuntimeException Method is intended to be used only with consistent fixtures
1065
     *
1066
     * @param string $mainLanguageCode
1067
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1068
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1069
     * @param array $languageCodes
1070
     *
1071
     * @return array
1072
     */
1073
    protected function determineValuesForCreate(
1074
        $mainLanguageCode,
1075
        array $structFields,
1076
        array $fieldDefinitions,
1077
        array $languageCodes
1078
    ) {
1079
        $mappedStructFields = $this->mapStructFieldsForCreate(
1080
            $mainLanguageCode,
1081
            $structFields,
1082
            $fieldDefinitions
1083
        );
1084
1085
        $values = array();
1086
1087
        foreach ($fieldDefinitions as $fieldDefinition) {
1088
            $identifier = $fieldDefinition->identifier;
1089
            foreach ($languageCodes as $languageCode) {
1090 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...
1091
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
1092
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
1093
                    } else {
1094
                        $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1095
                    }
1096
                    continue;
1097
                }
1098
1099 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...
1100
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
1101
                    continue;
1102
                }
1103
1104
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1105
            }
1106
        }
1107
1108
        return $this->stubValues($values);
1109
    }
1110
1111
    /**
1112
     * @param string $mainLanguageCode
1113
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1114
     *
1115
     * @return string[]
1116
     */
1117
    protected function determineLanguageCodesForCreate($mainLanguageCode, array $structFields)
1118
    {
1119
        $languageCodes = array();
1120
1121
        foreach ($structFields as $field) {
1122
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
1123
                continue;
1124
            }
1125
1126
            $languageCodes[$field->languageCode] = true;
1127
        }
1128
1129
        $languageCodes[$mainLanguageCode] = true;
1130
1131
        return array_keys($languageCodes);
1132
    }
1133
1134
    /**
1135
     * Asserts that calling createContent() with given API field set causes calling
1136
     * Handler::createContent() with given SPI field set.
1137
     *
1138
     * @param string $mainLanguageCode
1139
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1140
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
1141
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1142
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationCreateStructs
1143
     * @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...
1144
     * @param bool $execute
1145
     *
1146
     * @return mixed
1147
     */
1148
    protected function assertForTestCreateContentNonRedundantFieldSet(
1149
        $mainLanguageCode,
1150
        array $structFields,
1151
        array $spiFields,
1152
        array $fieldDefinitions,
1153
        array $locationCreateStructs = array(),
1154
        $withObjectStates = false,
1155
        $execute = true
1156
    ) {
1157
        $repositoryMock = $this->getRepositoryMock();
1158
        $mockedService = $this->getPartlyMockedContentService();
1159
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
1160
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
1161
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1162
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1163
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
1164
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
1165
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1166
        $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...
1167
        $domainMapperMock = $this->getDomainMapperMock();
1168
        $relationProcessorMock = $this->getRelationProcessorMock();
1169
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
1170
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
1171
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
1172
        $contentType = new ContentType(
1173
            array(
1174
                'id' => 123,
1175
                'fieldDefinitions' => $fieldDefinitions,
1176
                'nameSchema' => '<nameSchema>',
1177
            )
1178
        );
1179
        $contentCreateStruct = new ContentCreateStruct(
1180
            array(
1181
                'fields' => $structFields,
1182
                'mainLanguageCode' => $mainLanguageCode,
1183
                'contentType' => $contentType,
1184
                'alwaysAvailable' => false,
1185
                'ownerId' => 169,
1186
                'sectionId' => 1,
1187
            )
1188
        );
1189
1190
        $languageHandlerMock->expects($this->any())
1191
            ->method('loadByLanguageCode')
1192
            ->with($this->isType('string'))
1193
            ->will(
1194
                $this->returnCallback(
1195
                    function () {
1196
                        return new Language(array('id' => 4242));
1197
                    }
1198
                )
1199
            );
1200
1201
        $repositoryMock->expects($this->once())->method('beginTransaction');
1202
1203
        $contentTypeServiceMock->expects($this->once())
1204
            ->method('loadContentType')
1205
            ->with($this->equalTo($contentType->id))
1206
            ->will($this->returnValue($contentType));
1207
1208
        $repositoryMock->expects($this->once())
1209
            ->method('getContentTypeService')
1210
            ->will($this->returnValue($contentTypeServiceMock));
1211
1212
        $that = $this;
1213
        $repositoryMock->expects($this->once())
1214
            ->method('canUser')
1215
            ->with(
1216
                $this->equalTo('content'),
1217
                $this->equalTo('create'),
1218
                $this->isInstanceOf(APIContentCreateStruct::class),
1219
                $this->equalTo($locationCreateStructs)
1220
            )->will(
1221
                $this->returnCallback(
1222
                    function () use ($that, $contentCreateStruct) {
1223
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1224
1225
                        return true;
1226
                    }
1227
                )
1228
            );
1229
1230
        $domainMapperMock->expects($this->once())
1231
            ->method('getUniqueHash')
1232
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1233
            ->will(
1234
                $this->returnCallback(
1235
                    function ($object) use ($that, $contentCreateStruct) {
1236
                        $that->assertEquals($contentCreateStruct, $object);
1237
1238
                        return 'hash';
1239
                    }
1240
                )
1241
            );
1242
1243
        $fieldTypeMock->expects($this->any())
1244
            ->method('acceptValue')
1245
            ->will(
1246
                $this->returnCallback(
1247
                    function ($valueString) {
1248
                        return new ValueStub($valueString);
1249
                    }
1250
                )
1251
            );
1252
1253
        $fieldTypeMock->expects($this->any())
1254
            ->method('toPersistenceValue')
1255
            ->will(
1256
                $this->returnCallback(
1257
                    function (ValueStub $value) {
1258
                        return (string)$value;
1259
                    }
1260
                )
1261
            );
1262
1263
        $emptyValue = self::EMPTY_FIELD_VALUE;
1264
        $fieldTypeMock->expects($this->any())
1265
            ->method('isEmptyValue')
1266
            ->will(
1267
                $this->returnCallback(
1268
                    function (ValueStub $value) use ($emptyValue) {
1269
                        return $emptyValue === (string)$value;
1270
                    }
1271
                )
1272
            );
1273
1274
        $fieldTypeMock->expects($this->any())
1275
            ->method('validate')
1276
            ->will($this->returnValue(array()));
1277
1278
        $this->getFieldTypeRegistryMock()->expects($this->any())
1279
            ->method('getFieldType')
1280
            ->will($this->returnValue($fieldTypeMock));
1281
1282
        $relationProcessorMock
1283
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
1284
            ->method('appendFieldRelations')
1285
            ->with(
1286
                $this->isType('array'),
1287
                $this->isType('array'),
1288
                $this->isInstanceOf(SPIFieldType::class),
1289
                $this->isInstanceOf(Value::class),
1290
                $this->anything()
1291
            );
1292
1293
        $values = $this->determineValuesForCreate(
1294
            $mainLanguageCode,
1295
            $structFields,
1296
            $fieldDefinitions,
1297
            $languageCodes
1298
        );
1299
        $nameSchemaServiceMock->expects($this->once())
1300
            ->method('resolve')
1301
            ->with(
1302
                $this->equalTo($contentType->nameSchema),
1303
                $this->equalTo($contentType),
1304
                $this->equalTo($values),
1305
                $this->equalTo($languageCodes)
1306
            )->will($this->returnValue(array()));
1307
1308
        $relationProcessorMock->expects($this->any())
1309
            ->method('processFieldRelations')
1310
            ->with(
1311
                $this->isType('array'),
1312
                $this->equalTo(42),
1313
                $this->isType('int'),
1314
                $this->equalTo($contentType),
1315
                $this->equalTo(array())
1316
            );
1317
1318
        if (!$withObjectStates) {
1319
            $objectStateHandlerMock->expects($this->once())
1320
                ->method('loadAllGroups')
1321
                ->will($this->returnValue(array()));
1322
        }
1323
1324
        if ($execute) {
1325
            $spiContentCreateStruct = new SPIContentCreateStruct(
1326
                array(
1327
                    'name' => array(),
1328
                    'typeId' => 123,
1329
                    'sectionId' => 1,
1330
                    'ownerId' => 169,
1331
                    'remoteId' => 'hash',
1332
                    'fields' => $spiFields,
1333
                    'modified' => time(),
1334
                    'initialLanguageId' => 4242,
1335
                )
1336
            );
1337
            $spiContentCreateStruct2 = clone $spiContentCreateStruct;
1338
            ++$spiContentCreateStruct2->modified;
1339
1340
            $spiContent = new SPIContent(
1341
                array(
1342
                    'versionInfo' => new SPIContent\VersionInfo(
1343
                        array(
1344
                            'contentInfo' => new SPIContent\ContentInfo(array('id' => 42)),
1345
                            'versionNo' => 7,
1346
                        )
1347
                    ),
1348
                )
1349
            );
1350
1351
            $contentHandlerMock->expects($this->once())
1352
                ->method('create')
1353
                ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
1354
                ->will($this->returnValue($spiContent));
1355
1356
            $repositoryMock->expects($this->once())->method('commit');
1357
            $domainMapperMock->expects($this->once())
1358
                ->method('buildContentDomainObject')
1359
                ->with(
1360
                    $this->isInstanceOf(SPIContent::class),
1361
                    $this->equalTo($contentType)
1362
                );
1363
1364
            $mockedService->createContent($contentCreateStruct, array());
1365
        }
1366
1367
        return $contentCreateStruct;
1368
    }
1369
1370
    public function providerForTestCreateContentNonRedundantFieldSet1()
1371
    {
1372
        $spiFields = array(
1373
            new SPIField(
1374
                array(
1375
                    'fieldDefinitionId' => 'fieldDefinitionId',
1376
                    'type' => 'fieldTypeIdentifier',
1377
                    'value' => 'newValue',
1378
                    'languageCode' => 'eng-US',
1379
                )
1380
            ),
1381
        );
1382
1383
        return array(
1384
            // 0. Without language set
1385
            array(
1386
                'eng-US',
1387
                array(
1388
                    new Field(
1389
                        array(
1390
                            'fieldDefIdentifier' => 'identifier',
1391
                            'value' => 'newValue',
1392
                            'languageCode' => 'eng-US',
1393
                        )
1394
                    ),
1395
                ),
1396
                $spiFields,
1397
            ),
1398
            // 1. Without language set
1399
            array(
1400
                'eng-US',
1401
                array(
1402
                    new Field(
1403
                        array(
1404
                            'fieldDefIdentifier' => 'identifier',
1405
                            'value' => 'newValue',
1406
                            'languageCode' => null,
1407
                        )
1408
                    ),
1409
                ),
1410
                $spiFields,
1411
            ),
1412
        );
1413
    }
1414
1415
    /**
1416
     * Test for the createContent() method.
1417
     *
1418
     * Testing the simplest use case.
1419
     *
1420
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1421
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1422
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1423
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1424
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1425
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet1
1426
     */
1427
    public function testCreateContentNonRedundantFieldSet1($mainLanguageCode, $structFields, $spiFields)
1428
    {
1429
        $fieldDefinitions = array(
1430
            new FieldDefinition(
1431
                array(
1432
                    'id' => 'fieldDefinitionId',
1433
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1434
                    'isTranslatable' => false,
1435
                    'identifier' => 'identifier',
1436
                    'isRequired' => false,
1437
                    'defaultValue' => 'defaultValue',
1438
                )
1439
            ),
1440
        );
1441
1442
        $this->assertForTestCreateContentNonRedundantFieldSet(
1443
            $mainLanguageCode,
1444
            $structFields,
1445
            $spiFields,
1446
            $fieldDefinitions
1447
        );
1448
    }
1449
1450
    public function providerForTestCreateContentNonRedundantFieldSet2()
1451
    {
1452
        $spiFields = array(
1453
            new SPIField(
1454
                array(
1455
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1456
                    'type' => 'fieldTypeIdentifier',
1457
                    'value' => 'newValue1',
1458
                    'languageCode' => 'eng-US',
1459
                )
1460
            ),
1461
            new SPIField(
1462
                array(
1463
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1464
                    'type' => 'fieldTypeIdentifier',
1465
                    'value' => 'newValue2',
1466
                    'languageCode' => 'ger-DE',
1467
                )
1468
            ),
1469
        );
1470
1471
        return array(
1472
            // 0. With language set
1473
            array(
1474
                'eng-US',
1475
                array(
1476
                    new Field(
1477
                        array(
1478
                            'fieldDefIdentifier' => 'identifier1',
1479
                            'value' => 'newValue1',
1480
                            'languageCode' => 'eng-US',
1481
                        )
1482
                    ),
1483
                    new Field(
1484
                        array(
1485
                            'fieldDefIdentifier' => 'identifier2',
1486
                            'value' => 'newValue2',
1487
                            'languageCode' => 'ger-DE',
1488
                        )
1489
                    ),
1490
                ),
1491
                $spiFields,
1492
            ),
1493
            // 1. Without language set
1494
            array(
1495
                'eng-US',
1496
                array(
1497
                    new Field(
1498
                        array(
1499
                            'fieldDefIdentifier' => 'identifier1',
1500
                            'value' => 'newValue1',
1501
                            'languageCode' => null,
1502
                        )
1503
                    ),
1504
                    new Field(
1505
                        array(
1506
                            'fieldDefIdentifier' => 'identifier2',
1507
                            'value' => 'newValue2',
1508
                            'languageCode' => 'ger-DE',
1509
                        )
1510
                    ),
1511
                ),
1512
                $spiFields,
1513
            ),
1514
        );
1515
    }
1516
1517
    /**
1518
     * Test for the createContent() method.
1519
     *
1520
     * Testing multiple languages with multiple translatable fields with empty default value.
1521
     *
1522
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1523
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1524
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1525
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1526
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1527
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet2
1528
     */
1529
    public function testCreateContentNonRedundantFieldSet2($mainLanguageCode, $structFields, $spiFields)
1530
    {
1531
        $fieldDefinitions = array(
1532
            new FieldDefinition(
1533
                array(
1534
                    'id' => 'fieldDefinitionId1',
1535
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1536
                    'isTranslatable' => true,
1537
                    'identifier' => 'identifier1',
1538
                    'isRequired' => false,
1539
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1540
                )
1541
            ),
1542
            new FieldDefinition(
1543
                array(
1544
                    'id' => 'fieldDefinitionId2',
1545
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1546
                    'isTranslatable' => true,
1547
                    'identifier' => 'identifier2',
1548
                    'isRequired' => false,
1549
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1550
                )
1551
            ),
1552
        );
1553
1554
        $this->assertForTestCreateContentNonRedundantFieldSet(
1555
            $mainLanguageCode,
1556
            $structFields,
1557
            $spiFields,
1558
            $fieldDefinitions
1559
        );
1560
    }
1561
1562
    public function providerForTestCreateContentNonRedundantFieldSetComplex()
1563
    {
1564
        $spiFields0 = array(
1565
            new SPIField(
1566
                array(
1567
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1568
                    'type' => 'fieldTypeIdentifier',
1569
                    'value' => 'defaultValue2',
1570
                    'languageCode' => 'eng-US',
1571
                )
1572
            ),
1573
            new SPIField(
1574
                array(
1575
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1576
                    'type' => 'fieldTypeIdentifier',
1577
                    'value' => 'defaultValue4',
1578
                    'languageCode' => 'eng-US',
1579
                )
1580
            ),
1581
        );
1582
        $spiFields1 = array(
1583
            new SPIField(
1584
                array(
1585
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1586
                    'type' => 'fieldTypeIdentifier',
1587
                    'value' => 'newValue1',
1588
                    'languageCode' => 'ger-DE',
1589
                )
1590
            ),
1591
            new SPIField(
1592
                array(
1593
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1594
                    'type' => 'fieldTypeIdentifier',
1595
                    'value' => 'defaultValue2',
1596
                    'languageCode' => 'ger-DE',
1597
                )
1598
            ),
1599
            new SPIField(
1600
                array(
1601
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1602
                    'type' => 'fieldTypeIdentifier',
1603
                    'value' => 'newValue2',
1604
                    'languageCode' => 'eng-US',
1605
                )
1606
            ),
1607
            new SPIField(
1608
                array(
1609
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1610
                    'type' => 'fieldTypeIdentifier',
1611
                    'value' => 'newValue4',
1612
                    'languageCode' => 'eng-US',
1613
                )
1614
            ),
1615
        );
1616
1617
        return array(
1618
            // 0. Creating by default values only
1619
            array(
1620
                'eng-US',
1621
                array(),
1622
                $spiFields0,
1623
            ),
1624
            // 1. Multiple languages with language set
1625
            array(
1626
                'eng-US',
1627
                array(
1628
                    new Field(
1629
                        array(
1630
                            'fieldDefIdentifier' => 'identifier1',
1631
                            'value' => 'newValue1',
1632
                            'languageCode' => 'ger-DE',
1633
                        )
1634
                    ),
1635
                    new Field(
1636
                        array(
1637
                            'fieldDefIdentifier' => 'identifier2',
1638
                            'value' => 'newValue2',
1639
                            'languageCode' => 'eng-US',
1640
                        )
1641
                    ),
1642
                    new Field(
1643
                        array(
1644
                            'fieldDefIdentifier' => 'identifier4',
1645
                            'value' => 'newValue4',
1646
                            'languageCode' => 'eng-US',
1647
                        )
1648
                    ),
1649
                ),
1650
                $spiFields1,
1651
            ),
1652
            // 2. Multiple languages without language set
1653
            array(
1654
                'eng-US',
1655
                array(
1656
                    new Field(
1657
                        array(
1658
                            'fieldDefIdentifier' => 'identifier1',
1659
                            'value' => 'newValue1',
1660
                            'languageCode' => 'ger-DE',
1661
                        )
1662
                    ),
1663
                    new Field(
1664
                        array(
1665
                            'fieldDefIdentifier' => 'identifier2',
1666
                            'value' => 'newValue2',
1667
                            'languageCode' => null,
1668
                        )
1669
                    ),
1670
                    new Field(
1671
                        array(
1672
                            'fieldDefIdentifier' => 'identifier4',
1673
                            'value' => 'newValue4',
1674
                            'languageCode' => null,
1675
                        )
1676
                    ),
1677
                ),
1678
                $spiFields1,
1679
            ),
1680
        );
1681
    }
1682
1683
    protected function fixturesForTestCreateContentNonRedundantFieldSetComplex()
1684
    {
1685
        return array(
1686
            new FieldDefinition(
1687
                array(
1688
                    'id' => 'fieldDefinitionId1',
1689
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1690
                    'isTranslatable' => true,
1691
                    'identifier' => 'identifier1',
1692
                    'isRequired' => false,
1693
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1694
                )
1695
            ),
1696
            new FieldDefinition(
1697
                array(
1698
                    'id' => 'fieldDefinitionId2',
1699
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1700
                    'isTranslatable' => true,
1701
                    'identifier' => 'identifier2',
1702
                    'isRequired' => false,
1703
                    'defaultValue' => 'defaultValue2',
1704
                )
1705
            ),
1706
            new FieldDefinition(
1707
                array(
1708
                    'id' => 'fieldDefinitionId3',
1709
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1710
                    'isTranslatable' => false,
1711
                    'identifier' => 'identifier3',
1712
                    'isRequired' => false,
1713
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1714
                )
1715
            ),
1716
            new FieldDefinition(
1717
                array(
1718
                    'id' => 'fieldDefinitionId4',
1719
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1720
                    'isTranslatable' => false,
1721
                    'identifier' => 'identifier4',
1722
                    'isRequired' => false,
1723
                    'defaultValue' => 'defaultValue4',
1724
                )
1725
            ),
1726
        );
1727
    }
1728
1729
    /**
1730
     * Test for the createContent() method.
1731
     *
1732
     * Testing multiple languages with multiple translatable fields with empty default value.
1733
     *
1734
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1735
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1736
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1737
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1738
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1739
     * @dataProvider providerForTestCreateContentNonRedundantFieldSetComplex
1740
     */
1741
    public function testCreateContentNonRedundantFieldSetComplex($mainLanguageCode, $structFields, $spiFields)
1742
    {
1743
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
1744
1745
        $this->assertForTestCreateContentNonRedundantFieldSet(
1746
            $mainLanguageCode,
1747
            $structFields,
1748
            $spiFields,
1749
            $fieldDefinitions
1750
        );
1751
    }
1752
1753 View Code Duplication
    public function providerForTestCreateContentWithInvalidLanguage()
1754
    {
1755
        return array(
1756
            array(
1757
                'eng-GB',
1758
                array(
1759
                    new Field(
1760
                        array(
1761
                            'fieldDefIdentifier' => 'identifier',
1762
                            'value' => 'newValue',
1763
                            'languageCode' => 'Klingon',
1764
                        )
1765
                    ),
1766
                ),
1767
            ),
1768
            array(
1769
                'Klingon',
1770
                array(
1771
                    new Field(
1772
                        array(
1773
                            'fieldDefIdentifier' => 'identifier',
1774
                            'value' => 'newValue',
1775
                            'languageCode' => 'eng-GB',
1776
                        )
1777
                    ),
1778
                ),
1779
            ),
1780
        );
1781
    }
1782
1783
    /**
1784
     * Test for the updateContent() method.
1785
     *
1786
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1787
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1788
     * @dataProvider providerForTestCreateContentWithInvalidLanguage
1789
     */
1790
    public function testCreateContentWithInvalidLanguage($mainLanguageCode, $structFields)
1791
    {
1792
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1793
        $this->expectExceptionMessage('Could not find \'Language\' with identifier \'Klingon\'');
1794
1795
        $repositoryMock = $this->getRepositoryMock();
1796
        $mockedService = $this->getPartlyMockedContentService();
1797
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1798
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1799
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1800
        $domainMapperMock = $this->getDomainMapperMock();
1801
        $contentType = new ContentType(
1802
            array(
1803
                'id' => 123,
1804
                'fieldDefinitions' => array(),
1805
            )
1806
        );
1807
        $contentCreateStruct = new ContentCreateStruct(
1808
            array(
1809
                'fields' => $structFields,
1810
                'mainLanguageCode' => $mainLanguageCode,
1811
                'contentType' => $contentType,
1812
                'alwaysAvailable' => false,
1813
                'ownerId' => 169,
1814
                'sectionId' => 1,
1815
            )
1816
        );
1817
1818
        $languageHandlerMock->expects($this->any())
1819
            ->method('loadByLanguageCode')
1820
            ->with($this->isType('string'))
1821
            ->will(
1822
                $this->returnCallback(
1823 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...
1824
                        if ($languageCode === 'Klingon') {
1825
                            throw new NotFoundException('Language', 'Klingon');
1826
                        }
1827
1828
                        return new Language(array('id' => 4242));
1829
                    }
1830
                )
1831
            );
1832
1833
        $contentTypeServiceMock->expects($this->once())
1834
            ->method('loadContentType')
1835
            ->with($this->equalTo($contentType->id))
1836
            ->will($this->returnValue($contentType));
1837
1838
        $repositoryMock->expects($this->once())
1839
            ->method('getContentTypeService')
1840
            ->will($this->returnValue($contentTypeServiceMock));
1841
1842
        $that = $this;
1843
        $repositoryMock->expects($this->once())
1844
            ->method('canUser')
1845
            ->with(
1846
                $this->equalTo('content'),
1847
                $this->equalTo('create'),
1848
                $this->isInstanceOf(APIContentCreateStruct::class),
1849
                $this->equalTo(array())
1850
            )->will(
1851
                $this->returnCallback(
1852
                    function () use ($that, $contentCreateStruct) {
1853
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1854
1855
                        return true;
1856
                    }
1857
                )
1858
            );
1859
1860
        $domainMapperMock->expects($this->once())
1861
            ->method('getUniqueHash')
1862
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1863
            ->will(
1864
                $this->returnCallback(
1865
                    function ($object) use ($that, $contentCreateStruct) {
1866
                        $that->assertEquals($contentCreateStruct, $object);
1867
1868
                        return 'hash';
1869
                    }
1870
                )
1871
            );
1872
1873
        $mockedService->createContent($contentCreateStruct, array());
1874
    }
1875
1876
    protected function assertForCreateContentContentValidationException(
1877
        $mainLanguageCode,
1878
        $structFields,
1879
        $fieldDefinitions = array()
1880
    ) {
1881
        $repositoryMock = $this->getRepositoryMock();
1882
        $mockedService = $this->getPartlyMockedContentService(array('loadContentByRemoteId'));
1883
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1884
        $contentType = new ContentType(
1885
            array(
1886
                'id' => 123,
1887
                'fieldDefinitions' => $fieldDefinitions,
1888
            )
1889
        );
1890
        $contentCreateStruct = new ContentCreateStruct(
1891
            array(
1892
                'ownerId' => 169,
1893
                'alwaysAvailable' => false,
1894
                'remoteId' => 'faraday',
1895
                'mainLanguageCode' => $mainLanguageCode,
1896
                'fields' => $structFields,
1897
                'contentType' => $contentType,
1898
            )
1899
        );
1900
1901
        $contentTypeServiceMock->expects($this->once())
1902
            ->method('loadContentType')
1903
            ->with($this->equalTo(123))
1904
            ->will($this->returnValue($contentType));
1905
1906
        $repositoryMock->expects($this->once())
1907
            ->method('getContentTypeService')
1908
            ->will($this->returnValue($contentTypeServiceMock));
1909
1910
        $repositoryMock->expects($this->once())
1911
            ->method('canUser')
1912
            ->with(
1913
                $this->equalTo('content'),
1914
                $this->equalTo('create'),
1915
                $this->isInstanceOf(get_class($contentCreateStruct)),
1916
                $this->equalTo(array())
1917
            )->will($this->returnValue(true));
1918
1919
        $mockedService->expects($this->once())
1920
            ->method('loadContentByRemoteId')
1921
            ->with($contentCreateStruct->remoteId)
1922
            ->will(
1923
                $this->throwException(new NotFoundException('Content', 'faraday'))
1924
            );
1925
1926
        $mockedService->createContent($contentCreateStruct, array());
1927
    }
1928
1929 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition()
1930
    {
1931
        return array(
1932
            array(
1933
                'eng-GB',
1934
                array(
1935
                    new Field(
1936
                        array(
1937
                            'fieldDefIdentifier' => 'identifier',
1938
                            'value' => 'newValue',
1939
                            'languageCode' => 'eng-GB',
1940
                        )
1941
                    ),
1942
                ),
1943
            ),
1944
        );
1945
    }
1946
1947
    /**
1948
     * Test for the createContent() method.
1949
     *
1950
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1951
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1952
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1953
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition
1954
     */
1955
    public function testCreateContentThrowsContentValidationExceptionFieldDefinition($mainLanguageCode, $structFields)
1956
    {
1957
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
1958
        $this->expectExceptionMessage('Field definition \'identifier\' does not exist in given ContentType');
1959
1960
        $this->assertForCreateContentContentValidationException(
1961
            $mainLanguageCode,
1962
            $structFields,
1963
            array()
1964
        );
1965
    }
1966
1967 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionTranslation()
1968
    {
1969
        return array(
1970
            array(
1971
                'eng-GB',
1972
                array(
1973
                    new Field(
1974
                        array(
1975
                            'fieldDefIdentifier' => 'identifier',
1976
                            'value' => 'newValue',
1977
                            'languageCode' => 'eng-US',
1978
                        )
1979
                    ),
1980
                ),
1981
            ),
1982
        );
1983
    }
1984
1985
    /**
1986
     * Test for the createContent() method.
1987
     *
1988
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1989
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1990
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1991
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
1992
     */
1993 View Code Duplication
    public function testCreateContentThrowsContentValidationExceptionTranslation($mainLanguageCode, $structFields)
1994
    {
1995
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
1996
        $this->expectExceptionMessage('A value is set for non translatable field definition \'identifier\' with language \'eng-US\'');
1997
1998
        $fieldDefinitions = array(
1999
            new FieldDefinition(
2000
                array(
2001
                    'id' => 'fieldDefinitionId1',
2002
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2003
                    'isTranslatable' => false,
2004
                    'identifier' => 'identifier',
2005
                    'isRequired' => false,
2006
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
2007
                )
2008
            ),
2009
        );
2010
2011
        $this->assertForCreateContentContentValidationException(
2012
            $mainLanguageCode,
2013
            $structFields,
2014
            $fieldDefinitions
2015
        );
2016
    }
2017
2018
    /**
2019
     * Asserts behaviour necessary for testing ContentFieldValidationException because of required
2020
     * field being empty.
2021
     *
2022
     * @param string $mainLanguageCode
2023
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2024
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2025
     *
2026
     * @return mixed
2027
     */
2028
    protected function assertForTestCreateContentRequiredField(
2029
        $mainLanguageCode,
2030
        array $structFields,
2031
        array $fieldDefinitions
2032
    ) {
2033
        $repositoryMock = $this->getRepositoryMock();
2034
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2035
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2036
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2037
        $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...
2038
        $domainMapperMock = $this->getDomainMapperMock();
2039
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2040
        $contentType = new ContentType(
2041
            array(
2042
                'id' => 123,
2043
                'fieldDefinitions' => $fieldDefinitions,
2044
                'nameSchema' => '<nameSchema>',
2045
            )
2046
        );
2047
        $contentCreateStruct = new ContentCreateStruct(
2048
            array(
2049
                'fields' => $structFields,
2050
                'mainLanguageCode' => $mainLanguageCode,
2051
                'contentType' => $contentType,
2052
                'alwaysAvailable' => false,
2053
                'ownerId' => 169,
2054
                'sectionId' => 1,
2055
            )
2056
        );
2057
2058
        $languageHandlerMock->expects($this->any())
2059
            ->method('loadByLanguageCode')
2060
            ->with($this->isType('string'))
2061
            ->will(
2062
                $this->returnCallback(
2063
                    function () {
2064
                        return new Language(array('id' => 4242));
2065
                    }
2066
                )
2067
            );
2068
2069
        $contentTypeServiceMock->expects($this->once())
2070
            ->method('loadContentType')
2071
            ->with($this->equalTo($contentType->id))
2072
            ->will($this->returnValue($contentType));
2073
2074
        $repositoryMock->expects($this->once())
2075
            ->method('getContentTypeService')
2076
            ->will($this->returnValue($contentTypeServiceMock));
2077
2078
        $that = $this;
2079
        $repositoryMock->expects($this->once())
2080
            ->method('canUser')
2081
            ->with(
2082
                $this->equalTo('content'),
2083
                $this->equalTo('create'),
2084
                $this->isInstanceOf(APIContentCreateStruct::class),
2085
                $this->equalTo(array())
2086
            )->will(
2087
                $this->returnCallback(
2088
                    function () use ($that, $contentCreateStruct) {
2089
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2090
2091
                        return true;
2092
                    }
2093
                )
2094
            );
2095
2096
        $domainMapperMock->expects($this->once())
2097
            ->method('getUniqueHash')
2098
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2099
            ->will(
2100
                $this->returnCallback(
2101
                    function ($object) use ($that, $contentCreateStruct) {
2102
                        $that->assertEquals($contentCreateStruct, $object);
2103
2104
                        return 'hash';
2105
                    }
2106
                )
2107
            );
2108
2109
        $fieldTypeMock->expects($this->any())
2110
            ->method('acceptValue')
2111
            ->will(
2112
                $this->returnCallback(
2113
                    function ($valueString) {
2114
                        return new ValueStub($valueString);
2115
                    }
2116
                )
2117
            );
2118
2119
        $emptyValue = self::EMPTY_FIELD_VALUE;
2120
        $fieldTypeMock->expects($this->any())
2121
            ->method('isEmptyValue')
2122
            ->will(
2123
                $this->returnCallback(
2124
                    function (ValueStub $value) use ($emptyValue) {
2125
                        return $emptyValue === (string)$value;
2126
                    }
2127
                )
2128
            );
2129
2130
        $fieldTypeMock->expects($this->any())
2131
            ->method('validate')
2132
            ->will($this->returnValue(array()));
2133
2134
        $this->getFieldTypeRegistryMock()->expects($this->any())
2135
            ->method('getFieldType')
2136
            ->will($this->returnValue($fieldTypeMock));
2137
2138
        return $contentCreateStruct;
2139
    }
2140
2141 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionRequiredField()
2142
    {
2143
        return array(
2144
            array(
2145
                'eng-US',
2146
                array(
2147
                    new Field(
2148
                        array(
2149
                            'fieldDefIdentifier' => 'identifier',
2150
                            'value' => self::EMPTY_FIELD_VALUE,
2151
                            'languageCode' => null,
2152
                        )
2153
                    ),
2154
                ),
2155
                'identifier',
2156
                'eng-US',
2157
            ),
2158
        );
2159
    }
2160
2161
    /**
2162
     * Test for the createContent() method.
2163
     *
2164
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2165
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2166
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2167
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionRequiredField
2168
     */
2169
    public function testCreateContentRequiredField(
2170
        $mainLanguageCode,
2171
        $structFields,
2172
        $identifier,
2173
        $languageCode
2174
    ) {
2175
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
2176
2177
        $fieldDefinitions = array(
2178
            new FieldDefinition(
2179
                array(
2180
                    'id' => 'fieldDefinitionId',
2181
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2182
                    'isTranslatable' => true,
2183
                    'identifier' => 'identifier',
2184
                    'isRequired' => true,
2185
                    'defaultValue' => 'defaultValue',
2186
                )
2187
            ),
2188
        );
2189
        $contentCreateStruct = $this->assertForTestCreateContentRequiredField(
2190
            $mainLanguageCode,
2191
            $structFields,
2192
            $fieldDefinitions
2193
        );
2194
2195
        $mockedService = $this->getPartlyMockedContentService();
2196
2197
        try {
2198
            $mockedService->createContent($contentCreateStruct, array());
2199
        } catch (ContentValidationException $e) {
2200
            $this->assertEquals(
2201
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
2202
                $e->getMessage()
2203
            );
2204
2205
            throw $e;
2206
        }
2207
    }
2208
2209
    /**
2210
     * Asserts behaviour necessary for testing ContentFieldValidationException because of
2211
     * field not being valid.
2212
     *
2213
     * @param string $mainLanguageCode
2214
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2215
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2216
     *
2217
     * @return mixed
2218
     */
2219
    protected function assertForTestCreateContentThrowsContentFieldValidationException(
2220
        $mainLanguageCode,
2221
        array $structFields,
2222
        array $fieldDefinitions
2223
    ) {
2224
        $repositoryMock = $this->getRepositoryMock();
2225
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2226
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2227
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2228
        $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...
2229
        $domainMapperMock = $this->getDomainMapperMock();
2230
        $relationProcessorMock = $this->getRelationProcessorMock();
2231
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2232
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
2233
        $contentType = new ContentType(
2234
            array(
2235
                'id' => 123,
2236
                'fieldDefinitions' => $fieldDefinitions,
2237
                'nameSchema' => '<nameSchema>',
2238
            )
2239
        );
2240
        $contentCreateStruct = new ContentCreateStruct(
2241
            array(
2242
                'fields' => $structFields,
2243
                'mainLanguageCode' => $mainLanguageCode,
2244
                'contentType' => $contentType,
2245
                'alwaysAvailable' => false,
2246
                'ownerId' => 169,
2247
                'sectionId' => 1,
2248
            )
2249
        );
2250
2251
        $languageHandlerMock->expects($this->any())
2252
            ->method('loadByLanguageCode')
2253
            ->with($this->isType('string'))
2254
            ->will(
2255
                $this->returnCallback(
2256
                    function () {
2257
                        return new Language(array('id' => 4242));
2258
                    }
2259
                )
2260
            );
2261
2262
        $contentTypeServiceMock->expects($this->once())
2263
            ->method('loadContentType')
2264
            ->with($this->equalTo($contentType->id))
2265
            ->will($this->returnValue($contentType));
2266
2267
        $repositoryMock->expects($this->once())
2268
            ->method('getContentTypeService')
2269
            ->will($this->returnValue($contentTypeServiceMock));
2270
2271
        $that = $this;
2272
        $repositoryMock->expects($this->once())
2273
            ->method('canUser')
2274
            ->with(
2275
                $this->equalTo('content'),
2276
                $this->equalTo('create'),
2277
                $this->isInstanceOf(APIContentCreateStruct::class),
2278
                $this->equalTo(array())
2279
            )->will(
2280
                $this->returnCallback(
2281
                    function () use ($that, $contentCreateStruct) {
2282
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2283
2284
                        return true;
2285
                    }
2286
                )
2287
            );
2288
2289
        $domainMapperMock->expects($this->once())
2290
            ->method('getUniqueHash')
2291
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2292
            ->will(
2293
                $this->returnCallback(
2294
                    function ($object) use ($that, $contentCreateStruct) {
2295
                        $that->assertEquals($contentCreateStruct, $object);
2296
2297
                        return 'hash';
2298
                    }
2299
                )
2300
            );
2301
2302
        $this->getFieldTypeRegistryMock()->expects($this->any())
2303
            ->method('getFieldType')
2304
            ->will($this->returnValue($fieldTypeMock));
2305
2306
        $relationProcessorMock
2307
            ->expects($this->any())
2308
            ->method('appendFieldRelations')
2309
            ->with(
2310
                $this->isType('array'),
2311
                $this->isType('array'),
2312
                $this->isInstanceOf(SPIFieldType::class),
2313
                $this->isInstanceOf(Value::class),
2314
                $this->anything()
2315
            );
2316
2317
        $fieldValues = $this->determineValuesForCreate(
2318
            $mainLanguageCode,
2319
            $structFields,
2320
            $fieldDefinitions,
2321
            $languageCodes
2322
        );
2323
        $allFieldErrors = array();
2324
        $validateCount = 0;
2325
        $emptyValue = self::EMPTY_FIELD_VALUE;
2326
        foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
2327
            foreach ($fieldValues[$fieldDefinition->identifier] as $languageCode => $value) {
2328
                $fieldTypeMock->expects($this->at($validateCount++))
2329
                    ->method('acceptValue')
2330
                    ->will(
2331
                        $this->returnCallback(
2332
                            function ($valueString) {
2333
                                return new ValueStub($valueString);
2334
                            }
2335
                        )
2336
                    );
2337
2338
                $fieldTypeMock->expects($this->at($validateCount++))
2339
                    ->method('isEmptyValue')
2340
                    ->will(
2341
                        $this->returnCallback(
2342
                            function (ValueStub $value) use ($emptyValue) {
2343
                                return $emptyValue === (string)$value;
2344
                            }
2345
                        )
2346
                    );
2347
2348
                if (self::EMPTY_FIELD_VALUE === (string)$value) {
2349
                    continue;
2350
                }
2351
2352
                $fieldTypeMock->expects($this->at($validateCount++))
2353
                    ->method('validate')
2354
                    ->with(
2355
                        $this->equalTo($fieldDefinition),
2356
                        $this->equalTo($value)
2357
                    )->will($this->returnArgument(1));
2358
2359
                $allFieldErrors[$fieldDefinition->id][$languageCode] = $value;
2360
            }
2361
        }
2362
2363
        return array($contentCreateStruct, $allFieldErrors);
2364
    }
2365
2366
    public function providerForTestCreateContentThrowsContentFieldValidationException()
2367
    {
2368
        return $this->providerForTestCreateContentNonRedundantFieldSetComplex();
2369
    }
2370
2371
    /**
2372
     * Test for the createContent() method.
2373
     *
2374
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2375
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2376
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2377
     * @dataProvider providerForTestCreateContentThrowsContentFieldValidationException
2378
     */
2379 View Code Duplication
    public function testCreateContentThrowsContentFieldValidationException($mainLanguageCode, $structFields)
2380
    {
2381
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
2382
        $this->expectExceptionMessage('Content fields did not validate');
2383
2384
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
2385
        list($contentCreateStruct, $allFieldErrors) =
2386
            $this->assertForTestCreateContentThrowsContentFieldValidationException(
2387
                $mainLanguageCode,
2388
                $structFields,
2389
                $fieldDefinitions
2390
            );
2391
2392
        $mockedService = $this->getPartlyMockedContentService();
2393
2394
        try {
2395
            $mockedService->createContent($contentCreateStruct);
2396
        } catch (ContentFieldValidationException $e) {
2397
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
2398
            throw $e;
2399
        }
2400
    }
2401
2402
    /**
2403
     * Test for the createContent() method.
2404
     *
2405
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2406
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2407
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2408
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2409
     */
2410
    public function testCreateContentWithLocations()
2411
    {
2412
        $spiFields = array(
2413
            new SPIField(
2414
                array(
2415
                    'fieldDefinitionId' => 'fieldDefinitionId',
2416
                    'type' => 'fieldTypeIdentifier',
2417
                    'value' => 'defaultValue',
2418
                    'languageCode' => 'eng-US',
2419
                )
2420
            ),
2421
        );
2422
        $fieldDefinitions = array(
2423
            new FieldDefinition(
2424
                array(
2425
                    'id' => 'fieldDefinitionId',
2426
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2427
                    'isTranslatable' => false,
2428
                    'identifier' => 'identifier',
2429
                    'isRequired' => false,
2430
                    'defaultValue' => 'defaultValue',
2431
                )
2432
            ),
2433
        );
2434
2435
        // Set up a simple case that will pass
2436
        $locationCreateStruct1 = new LocationCreateStruct(array('parentLocationId' => 321));
2437
        $locationCreateStruct2 = new LocationCreateStruct(array('parentLocationId' => 654));
2438
        $locationCreateStructs = array($locationCreateStruct1, $locationCreateStruct2);
2439
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2440
            'eng-US',
2441
            array(),
2442
            $spiFields,
2443
            $fieldDefinitions,
2444
            $locationCreateStructs,
2445
            false,
2446
            // Do not execute
2447
            false
2448
        );
2449
2450
        $repositoryMock = $this->getRepositoryMock();
2451
        $mockedService = $this->getPartlyMockedContentService();
2452
        $locationServiceMock = $this->getLocationServiceMock();
2453
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2454
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2455
        $domainMapperMock = $this->getDomainMapperMock();
2456
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2457
        $parentLocation = new Location(array('contentInfo' => new ContentInfo(array('sectionId' => 1))));
2458
2459
        $locationServiceMock->expects($this->at(0))
2460
            ->method('loadLocation')
2461
            ->with($this->equalTo(321))
2462
            ->will($this->returnValue($parentLocation));
2463
2464
        $locationServiceMock->expects($this->at(1))
2465
            ->method('loadLocation')
2466
            ->with($this->equalTo(654))
2467
            ->will($this->returnValue($parentLocation));
2468
2469
        $repositoryMock->expects($this->atLeastOnce())
2470
            ->method('getLocationService')
2471
            ->will($this->returnValue($locationServiceMock));
2472
2473
        $domainMapperMock->expects($this->at(1))
2474
            ->method('buildSPILocationCreateStruct')
2475
            ->with(
2476
                $this->equalTo($locationCreateStruct1),
2477
                $this->equalTo($parentLocation),
2478
                $this->equalTo(true),
2479
                $this->equalTo(null),
2480
                $this->equalTo(null)
2481
            )->will($this->returnValue($spiLocationCreateStruct));
2482
2483
        $domainMapperMock->expects($this->at(2))
2484
            ->method('buildSPILocationCreateStruct')
2485
            ->with(
2486
                $this->equalTo($locationCreateStruct2),
2487
                $this->equalTo($parentLocation),
2488
                $this->equalTo(false),
2489
                $this->equalTo(null),
2490
                $this->equalTo(null)
2491
            )->will($this->returnValue($spiLocationCreateStruct));
2492
2493
        $spiContentCreateStruct = new SPIContentCreateStruct(
2494
            array(
2495
                'name' => array(),
2496
                'typeId' => 123,
2497
                'sectionId' => 1,
2498
                'ownerId' => 169,
2499
                'remoteId' => 'hash',
2500
                'fields' => $spiFields,
2501
                'modified' => time(),
2502
                'initialLanguageId' => 4242,
2503
                'locations' => array($spiLocationCreateStruct, $spiLocationCreateStruct),
2504
            )
2505
        );
2506
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2507
        ++$spiContentCreateStruct2->modified;
2508
2509
        $spiContent = new SPIContent(
2510
            array(
2511
                'versionInfo' => new SPIContent\VersionInfo(
2512
                    array(
2513
                        'contentInfo' => new SPIContent\ContentInfo(array('id' => 42)),
2514
                        'versionNo' => 7,
2515
                    )
2516
                ),
2517
            )
2518
        );
2519
2520
        $handlerMock->expects($this->once())
2521
            ->method('create')
2522
            ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
2523
            ->will($this->returnValue($spiContent));
2524
2525
        $domainMapperMock->expects($this->once())
2526
            ->method('buildContentDomainObject')
2527
            ->with(
2528
                $this->isInstanceOf(SPIContent::class),
2529
                $this->isInstanceOf(APIContentType::class)
2530
            );
2531
2532
        $repositoryMock->expects($this->once())->method('commit');
2533
2534
        // Execute
2535
        $mockedService->createContent($contentCreateStruct, $locationCreateStructs);
2536
    }
2537
2538
    /**
2539
     * Test for the createContent() method.
2540
     *
2541
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2542
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2543
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2544
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2545
     */
2546
    public function testCreateContentWithLocationsDuplicateUnderParent()
2547
    {
2548
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2549
        $this->expectExceptionMessage('Multiple LocationCreateStructs with the same parent Location \'321\' are given');
2550
2551
        $fieldDefinitions = array(
2552
            new FieldDefinition(
2553
                array(
2554
                    'id' => 'fieldDefinitionId',
2555
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2556
                    'isTranslatable' => false,
2557
                    'identifier' => 'identifier',
2558
                    'isRequired' => false,
2559
                    'defaultValue' => 'defaultValue',
2560
                )
2561
            ),
2562
        );
2563
2564
        $repositoryMock = $this->getRepositoryMock();
2565
        $mockedService = $this->getPartlyMockedContentService();
2566
        $locationServiceMock = $this->getLocationServiceMock();
2567
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2568
        $domainMapperMock = $this->getDomainMapperMock();
2569
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2570
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2571
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2572
        $parentLocation = new Location(array('id' => 321));
2573
        $locationCreateStruct = new LocationCreateStruct(array('parentLocationId' => 321));
2574
        $locationCreateStructs = array($locationCreateStruct, clone $locationCreateStruct);
2575
        $contentType = new ContentType(
2576
            array(
2577
                'id' => 123,
2578
                'fieldDefinitions' => $fieldDefinitions,
2579
                'nameSchema' => '<nameSchema>',
2580
            )
2581
        );
2582
        $contentCreateStruct = new ContentCreateStruct(
2583
            array(
2584
                'fields' => array(),
2585
                'mainLanguageCode' => 'eng-US',
2586
                'contentType' => $contentType,
2587
                'alwaysAvailable' => false,
2588
                'ownerId' => 169,
2589
                'sectionId' => 1,
2590
            )
2591
        );
2592
2593
        $languageHandlerMock->expects($this->any())
2594
            ->method('loadByLanguageCode')
2595
            ->with($this->isType('string'))
2596
            ->will(
2597
                $this->returnCallback(
2598
                    function () {
2599
                        return new Language(array('id' => 4242));
2600
                    }
2601
                )
2602
            );
2603
2604
        $contentTypeServiceMock->expects($this->once())
2605
            ->method('loadContentType')
2606
            ->with($this->equalTo($contentType->id))
2607
            ->will($this->returnValue($contentType));
2608
2609
        $repositoryMock->expects($this->once())
2610
            ->method('getContentTypeService')
2611
            ->will($this->returnValue($contentTypeServiceMock));
2612
2613
        $that = $this;
2614
        $repositoryMock->expects($this->once())
2615
            ->method('canUser')
2616
            ->with(
2617
                $this->equalTo('content'),
2618
                $this->equalTo('create'),
2619
                $this->isInstanceOf(APIContentCreateStruct::class),
2620
                $this->equalTo($locationCreateStructs)
2621
            )->will(
2622
                $this->returnCallback(
2623
                    function () use ($that, $contentCreateStruct) {
2624
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2625
2626
                        return true;
2627
                    }
2628
                )
2629
            );
2630
2631
        $domainMapperMock->expects($this->once())
2632
            ->method('getUniqueHash')
2633
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2634
            ->will(
2635
                $this->returnCallback(
2636
                    function ($object) use ($that, $contentCreateStruct) {
2637
                        $that->assertEquals($contentCreateStruct, $object);
2638
2639
                        return 'hash';
2640
                    }
2641
                )
2642
            );
2643
2644
        $locationServiceMock->expects($this->once())
2645
            ->method('loadLocation')
2646
            ->with($this->equalTo(321))
2647
            ->will($this->returnValue($parentLocation));
2648
2649
        $repositoryMock->expects($this->any())
2650
            ->method('getLocationService')
2651
            ->will($this->returnValue($locationServiceMock));
2652
2653
        $domainMapperMock->expects($this->any())
2654
            ->method('buildSPILocationCreateStruct')
2655
            ->with(
2656
                $this->equalTo($locationCreateStruct),
2657
                $this->equalTo($parentLocation),
2658
                $this->equalTo(true),
2659
                $this->equalTo(null),
2660
                $this->equalTo(null)
2661
            )->will($this->returnValue($spiLocationCreateStruct));
2662
2663
        $mockedService->createContent(
2664
            $contentCreateStruct,
2665
            $locationCreateStructs
2666
        );
2667
    }
2668
2669
    /**
2670
     * Test for the createContent() method.
2671
     *
2672
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2673
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2674
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2675
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2676
     */
2677
    public function testCreateContentObjectStates()
2678
    {
2679
        $spiFields = array(
2680
            new SPIField(
2681
                array(
2682
                    'fieldDefinitionId' => 'fieldDefinitionId',
2683
                    'type' => 'fieldTypeIdentifier',
2684
                    'value' => 'defaultValue',
2685
                    'languageCode' => 'eng-US',
2686
                )
2687
            ),
2688
        );
2689
        $fieldDefinitions = array(
2690
            new FieldDefinition(
2691
                array(
2692
                    'id' => 'fieldDefinitionId',
2693
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2694
                    'isTranslatable' => false,
2695
                    'identifier' => 'identifier',
2696
                    'isRequired' => false,
2697
                    'defaultValue' => 'defaultValue',
2698
                )
2699
            ),
2700
        );
2701
        $objectStateGroups = array(
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...
2702
            new SPIObjectStateGroup(array('id' => 10)),
2703
            new SPIObjectStateGroup(array('id' => 20)),
2704
        );
2705
2706
        // Set up a simple case that will pass
2707
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2708
            'eng-US',
2709
            array(),
2710
            $spiFields,
2711
            $fieldDefinitions,
2712
            array(),
2713
            true,
2714
            // Do not execute
2715
            false
2716
        );
2717
        $timestamp = time();
2718
        $contentCreateStruct->modificationDate = new \DateTime("@{$timestamp}");
2719
2720
        $repositoryMock = $this->getRepositoryMock();
2721
        $mockedService = $this->getPartlyMockedContentService();
2722
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2723
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2724
        $domainMapperMock = $this->getDomainMapperMock();
2725
2726
        $this->mockGetDefaultObjectStates();
2727
        $this->mockSetDefaultObjectStates();
2728
2729
        $spiContentCreateStruct = new SPIContentCreateStruct(
2730
            array(
2731
                'name' => array(),
2732
                'typeId' => 123,
2733
                'sectionId' => 1,
2734
                'ownerId' => 169,
2735
                'remoteId' => 'hash',
2736
                'fields' => $spiFields,
2737
                'modified' => $timestamp,
2738
                'initialLanguageId' => 4242,
2739
                'locations' => array(),
2740
            )
2741
        );
2742
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2743
        ++$spiContentCreateStruct2->modified;
2744
2745
        $spiContent = new SPIContent(
2746
            array(
2747
                'versionInfo' => new SPIContent\VersionInfo(
2748
                    array(
2749
                        'contentInfo' => new SPIContent\ContentInfo(array('id' => 42)),
2750
                        'versionNo' => 7,
2751
                    )
2752
                ),
2753
            )
2754
        );
2755
2756
        $handlerMock->expects($this->once())
2757
            ->method('create')
2758
            ->with($this->equalTo($spiContentCreateStruct))
2759
            ->will($this->returnValue($spiContent));
2760
2761
        $domainMapperMock->expects($this->once())
2762
            ->method('buildContentDomainObject')
2763
            ->with(
2764
                $this->isInstanceOf(SPIContent::class),
2765
                $this->isInstanceOf(APIContentType::class)
2766
            );
2767
2768
        $repositoryMock->expects($this->once())->method('commit');
2769
2770
        // Execute
2771
        $mockedService->createContent($contentCreateStruct, array());
2772
    }
2773
2774
    /**
2775
     * Test for the createContent() method.
2776
     *
2777
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2778
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2779
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2780
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2781
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2782
     */
2783
    public function testCreateContentWithRollback()
2784
    {
2785
        $this->expectException(\Exception::class);
2786
        $this->expectExceptionMessage('Store failed');
2787
2788
        $fieldDefinitions = array(
2789
            new FieldDefinition(
2790
                array(
2791
                    'id' => 'fieldDefinitionId',
2792
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2793
                    'isTranslatable' => false,
2794
                    'identifier' => 'identifier',
2795
                    'isRequired' => false,
2796
                    'defaultValue' => 'defaultValue',
2797
                )
2798
            ),
2799
        );
2800
2801
        // Setup a simple case that will pass
2802
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2803
            'eng-US',
2804
            array(),
2805
            array(),
2806
            $fieldDefinitions,
2807
            array(),
2808
            false,
2809
            // Do not execute test
2810
            false
2811
        );
2812
2813
        $repositoryMock = $this->getRepositoryMock();
2814
        $repositoryMock->expects($this->never())->method('commit');
2815
        $repositoryMock->expects($this->once())->method('rollback');
2816
2817
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
2818
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
2819
        $contentHandlerMock->expects($this->once())
2820
            ->method('create')
2821
            ->with($this->anything())
2822
            ->will($this->throwException(new \Exception('Store failed')));
2823
2824
        // Execute
2825
        $this->partlyMockedContentService->createContent($contentCreateStruct, array());
2826
    }
2827
2828
    public function providerForTestUpdateContentThrowsBadStateException()
2829
    {
2830
        return array(
2831
            array(VersionInfo::STATUS_PUBLISHED),
2832
            array(VersionInfo::STATUS_ARCHIVED),
2833
        );
2834
    }
2835
2836
    /**
2837
     * Test for the updateContent() method.
2838
     *
2839
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2840
     * @dataProvider providerForTestUpdateContentThrowsBadStateException
2841
     */
2842
    public function testUpdateContentThrowsBadStateException($status)
2843
    {
2844
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
2845
2846
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
2847
        $contentUpdateStruct = new ContentUpdateStruct();
2848
        $versionInfo = new VersionInfo(
2849
            array(
2850
                'contentInfo' => new ContentInfo(array('id' => 42)),
2851
                'versionNo' => 7,
2852
                'status' => $status,
2853
            )
2854
        );
2855
        $content = new Content(
2856
            array(
2857
                'versionInfo' => $versionInfo,
2858
                'internalFields' => array(),
2859
            )
2860
        );
2861
2862
        $mockedService->expects($this->once())
2863
            ->method('loadContent')
2864
            ->with(
2865
                $this->equalTo(42),
2866
                $this->equalTo(null),
2867
                $this->equalTo(7)
2868
            )->will(
2869
                $this->returnValue($content)
2870
            );
2871
2872
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2873
    }
2874
2875
    /**
2876
     * Test for the updateContent() method.
2877
     *
2878
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2879
     */
2880
    public function testUpdateContentThrowsUnauthorizedException()
2881
    {
2882
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
2883
2884
        $permissionResolverMock = $this->getPermissionResolverMock();
2885
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
2886
        $contentUpdateStruct = new ContentUpdateStruct();
2887
        $versionInfo = new VersionInfo(
2888
            array(
2889
                'contentInfo' => new ContentInfo(array('id' => 42)),
2890
                'versionNo' => 7,
2891
                'status' => VersionInfo::STATUS_DRAFT,
2892
            )
2893
        );
2894
        $content = new Content(
2895
            array(
2896
                'versionInfo' => $versionInfo,
2897
                'internalFields' => array(),
2898
            )
2899
        );
2900
2901
        $mockedService->expects($this->once())
2902
            ->method('loadContent')
2903
            ->with(
2904
                $this->equalTo(42),
2905
                $this->equalTo(null),
2906
                $this->equalTo(7)
2907
            )->will(
2908
                $this->returnValue($content)
2909
            );
2910
2911
        $permissionResolverMock->expects($this->once())
2912
            ->method('canUser')
2913
            ->with(
2914
                $this->equalTo('content'),
2915
                $this->equalTo('edit'),
2916
                $this->equalTo($content),
2917
                $this->isType('array')
2918
            )->will($this->returnValue(false));
2919
2920
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2921
    }
2922
2923
    /**
2924
     * @param string $initialLanguageCode
2925
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2926
     * @param string[] $existingLanguages
2927
     *
2928
     * @return string[]
2929
     */
2930
    protected function determineLanguageCodesForUpdate($initialLanguageCode, array $structFields, $existingLanguages)
2931
    {
2932
        $languageCodes = array_fill_keys($existingLanguages, true);
2933
        if ($initialLanguageCode !== null) {
2934
            $languageCodes[$initialLanguageCode] = true;
2935
        }
2936
2937
        foreach ($structFields as $field) {
2938
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
2939
                continue;
2940
            }
2941
2942
            $languageCodes[$field->languageCode] = true;
2943
        }
2944
2945
        return array_keys($languageCodes);
2946
    }
2947
2948
    /**
2949
     * @param string $initialLanguageCode
2950
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2951
     * @param string $mainLanguageCode
2952
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2953
     *
2954
     * @return array
2955
     */
2956
    protected function mapStructFieldsForUpdate($initialLanguageCode, $structFields, $mainLanguageCode, $fieldDefinitions)
2957
    {
2958
        $initialLanguageCode = $initialLanguageCode ?: $mainLanguageCode;
2959
2960
        $mappedFieldDefinitions = array();
2961
        foreach ($fieldDefinitions as $fieldDefinition) {
2962
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
2963
        }
2964
2965
        $mappedStructFields = array();
2966
        foreach ($structFields as $structField) {
2967
            $identifier = $structField->fieldDefIdentifier;
2968
2969
            if ($structField->languageCode !== null) {
2970
                $languageCode = $structField->languageCode;
2971
            } elseif ($mappedFieldDefinitions[$identifier]->isTranslatable) {
2972
                $languageCode = $initialLanguageCode;
2973
            } else {
2974
                $languageCode = $mainLanguageCode;
2975
            }
2976
2977
            $mappedStructFields[$identifier][$languageCode] = (string)$structField->value;
2978
        }
2979
2980
        return $mappedStructFields;
2981
    }
2982
2983
    /**
2984
     * Returns full, possibly redundant array of field values, indexed by field definition
2985
     * identifier and language code.
2986
     *
2987
     * @param string $initialLanguageCode
2988
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2989
     * @param \eZ\Publish\Core\Repository\Values\Content\Content $content
2990
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2991
     * @param array $languageCodes
2992
     *
2993
     * @return array
2994
     */
2995
    protected function determineValuesForUpdate(
2996
        $initialLanguageCode,
2997
        array $structFields,
2998
        Content $content,
2999
        array $fieldDefinitions,
3000
        array $languageCodes
3001
    ) {
3002
        $mainLanguageCode = $content->versionInfo->contentInfo->mainLanguageCode;
3003
3004
        $mappedStructFields = $this->mapStructFieldsForUpdate(
3005
            $initialLanguageCode,
3006
            $structFields,
3007
            $mainLanguageCode,
3008
            $fieldDefinitions
3009
        );
3010
3011
        $values = array();
3012
3013
        foreach ($fieldDefinitions as $fieldDefinition) {
3014
            $identifier = $fieldDefinition->identifier;
3015
            foreach ($languageCodes as $languageCode) {
3016 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...
3017
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
3018
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
3019
                    } else {
3020
                        $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$mainLanguageCode];
3021
                    }
3022
                    continue;
3023
                }
3024
3025 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...
3026
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
3027
                    continue;
3028
                }
3029
3030
                if (isset($content->fields[$identifier][$languageCode])) {
3031
                    $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$languageCode];
3032
                    continue;
3033
                }
3034
3035
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
3036
            }
3037
        }
3038
3039
        return $this->stubValues($values);
3040
    }
3041
3042
    protected function stubValues(array $fieldValues)
3043
    {
3044
        foreach ($fieldValues as &$languageValues) {
3045
            foreach ($languageValues as &$value) {
3046
                $value = new ValueStub($value);
3047
            }
3048
        }
3049
3050
        return $fieldValues;
3051
    }
3052
3053
    /**
3054
     * Asserts that calling updateContent() with given API field set causes calling
3055
     * Handler::updateContent() with given SPI field set.
3056
     *
3057
     * @param string $initialLanguageCode
3058
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
3059
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
3060
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $existingFields
3061
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
3062
     * @param bool $execute
3063
     *
3064
     * @return mixed
3065
     */
3066
    protected function assertForTestUpdateContentNonRedundantFieldSet(
3067
        $initialLanguageCode,
3068
        array $structFields,
3069
        array $spiFields,
3070
        array $existingFields,
3071
        array $fieldDefinitions,
3072
        $execute = true
3073
    ) {
3074
        $repositoryMock = $this->getRepositoryMock();
3075
        $permissionResolverMock = $this->getPermissionResolverMock();
3076
        $mockedService = $this->getPartlyMockedContentService(array('loadContent', 'loadRelations'));
3077
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
3078
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
3079
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
3080
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
3081
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
3082
        $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...
3083
        $domainMapperMock = $this->getDomainMapperMock();
3084
        $relationProcessorMock = $this->getRelationProcessorMock();
3085
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
3086
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
3087
        $existingLanguageCodes = array_map(
3088
            function (Field $field) {
3089
                return $field->languageCode;
3090
            },
3091
            $existingFields
3092
        );
3093
        $languageCodes = $this->determineLanguageCodesForUpdate(
3094
            $initialLanguageCode,
3095
            $structFields,
3096
            $existingLanguageCodes
3097
        );
3098
        $versionInfo = new VersionInfo(
3099
            array(
3100
                'contentInfo' => new ContentInfo(
3101
                    array(
3102
                        'id' => 42,
3103
                        'contentTypeId' => 24,
3104
                        'mainLanguageCode' => 'eng-GB',
3105
                    )
3106
                ),
3107
                'versionNo' => 7,
3108
                'languageCodes' => $existingLanguageCodes,
3109
                'status' => VersionInfo::STATUS_DRAFT,
3110
            )
3111
        );
3112
        $content = new Content(
3113
            array(
3114
                'versionInfo' => $versionInfo,
3115
                'internalFields' => $existingFields,
3116
            )
3117
        );
3118
        $contentType = new ContentType(array('fieldDefinitions' => $fieldDefinitions));
3119
3120
        $languageHandlerMock->expects($this->any())
3121
            ->method('loadByLanguageCode')
3122
            ->with($this->isType('string'))
3123
            ->will(
3124
                $this->returnCallback(
3125
                    function () {
3126
                        return new Language(array('id' => 4242));
3127
                    }
3128
                )
3129
            );
3130
3131
        $mockedService->expects($this->once())
3132
            ->method('loadContent')
3133
            ->with(
3134
                $this->equalTo(42),
3135
                $this->equalTo(null),
3136
                $this->equalTo(7)
3137
            )->will(
3138
                $this->returnValue($content)
3139
            );
3140
3141
        $repositoryMock->expects($this->once())->method('beginTransaction');
3142
3143
        $permissionResolverMock->expects($this->once())
3144
            ->method('canUser')
3145
            ->with(
3146
                $this->equalTo('content'),
3147
                $this->equalTo('edit'),
3148
                $this->equalTo($content),
3149
                $this->isType('array')
3150
            )->will($this->returnValue(true));
3151
3152
        $contentTypeServiceMock->expects($this->once())
3153
            ->method('loadContentType')
3154
            ->with($this->equalTo(24))
3155
            ->will($this->returnValue($contentType));
3156
3157
        $repositoryMock->expects($this->once())
3158
            ->method('getContentTypeService')
3159
            ->will($this->returnValue($contentTypeServiceMock));
3160
3161
        $repositoryMock->expects($this->once())
3162
            ->method('getCurrentUserReference')
3163
            ->will($this->returnValue(new UserReference(169)));
3164
3165
        $fieldTypeMock->expects($this->any())
3166
            ->method('acceptValue')
3167
            ->will(
3168
                $this->returnCallback(
3169
                    function ($valueString) {
3170
                        return new ValueStub($valueString);
3171
                    }
3172
                )
3173
            );
3174
3175
        $emptyValue = self::EMPTY_FIELD_VALUE;
3176
        $fieldTypeMock->expects($this->any())
3177
            ->method('toPersistenceValue')
3178
            ->will(
3179
                $this->returnCallback(
3180
                    function (ValueStub $value) {
3181
                        return (string)$value;
3182
                    }
3183
                )
3184
            );
3185
3186
        $fieldTypeMock->expects($this->any())
3187
            ->method('isEmptyValue')
3188
            ->will(
3189
                $this->returnCallback(
3190
                    function (ValueStub $value) use ($emptyValue) {
3191
                        return $emptyValue === (string)$value;
3192
                    }
3193
                )
3194
            );
3195
3196
        $fieldTypeMock->expects($this->any())
3197
            ->method('validate')
3198
            ->will($this->returnValue(array()));
3199
3200
        $this->getFieldTypeRegistryMock()->expects($this->any())
3201
            ->method('getFieldType')
3202
            ->will($this->returnValue($fieldTypeMock));
3203
3204
        $relationProcessorMock
3205
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
3206
            ->method('appendFieldRelations')
3207
            ->with(
3208
                $this->isType('array'),
3209
                $this->isType('array'),
3210
                $this->isInstanceOf(SPIFieldType::class),
3211
                $this->isInstanceOf(Value::class),
3212
                $this->anything()
3213
            );
3214
3215
        $values = $this->determineValuesForUpdate(
3216
            $initialLanguageCode,
3217
            $structFields,
3218
            $content,
3219
            $fieldDefinitions,
3220
            $languageCodes
3221
        );
3222
        $nameSchemaServiceMock->expects($this->once())
3223
            ->method('resolveNameSchema')
3224
            ->with(
3225
                $this->equalTo($content),
3226
                $this->equalTo($values),
3227
                $this->equalTo($languageCodes)
3228
            )->will($this->returnValue(array()));
3229
3230
        $existingRelations = array('RELATIONS!!!');
3231
        $mockedService->expects($this->once())
3232
            ->method('loadRelations')
3233
            ->with($content->versionInfo)
3234
            ->will($this->returnValue($existingRelations));
3235
        $relationProcessorMock->expects($this->any())
3236
            ->method('processFieldRelations')
3237
            ->with(
3238
                $this->isType('array'),
3239
                $this->equalTo(42),
3240
                $this->isType('int'),
3241
                $this->equalTo($contentType),
3242
                $this->equalTo($existingRelations)
3243
            );
3244
3245
        $contentUpdateStruct = new ContentUpdateStruct(
3246
            array(
3247
                'fields' => $structFields,
3248
                'initialLanguageCode' => $initialLanguageCode,
3249
            )
3250
        );
3251
3252
        if ($execute) {
3253
            $spiContentUpdateStruct = new SPIContentUpdateStruct(
3254
                array(
3255
                    'creatorId' => 169,
3256
                    'fields' => $spiFields,
3257
                    'modificationDate' => time(),
3258
                    'initialLanguageId' => 4242,
3259
                )
3260
            );
3261
3262
            // During code coverage runs, timestamp might differ 1-3 seconds
3263
            $spiContentUpdateStructTs1 = clone $spiContentUpdateStruct;
3264
            ++$spiContentUpdateStructTs1->modificationDate;
3265
3266
            $spiContentUpdateStructTs2 = clone $spiContentUpdateStructTs1;
3267
            ++$spiContentUpdateStructTs2->modificationDate;
3268
3269
            $spiContentUpdateStructTs3 = clone $spiContentUpdateStructTs2;
3270
            ++$spiContentUpdateStructTs3->modificationDate;
3271
3272
            $spiContent = new SPIContent(
3273
                array(
3274
                    'versionInfo' => new SPIContent\VersionInfo(
3275
                        array(
3276
                            'contentInfo' => new SPIContent\ContentInfo(array('id' => 42)),
3277
                            'versionNo' => 7,
3278
                        )
3279
                    ),
3280
                )
3281
            );
3282
3283
            $contentHandlerMock->expects($this->once())
3284
                ->method('updateContent')
3285
                ->with(
3286
                    42,
3287
                    7,
3288
                    $this->logicalOr($spiContentUpdateStruct, $spiContentUpdateStructTs1, $spiContentUpdateStructTs2, $spiContentUpdateStructTs3)
3289
                )
3290
                ->will($this->returnValue($spiContent));
3291
3292
            $repositoryMock->expects($this->once())->method('commit');
3293
            $domainMapperMock->expects($this->once())
3294
                ->method('buildContentDomainObject')
3295
                ->with(
3296
                    $this->isInstanceOf(SPIContent::class),
3297
                    $this->isInstanceOf(APIContentType::class)
3298
                );
3299
3300
            $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
3301
        }
3302
3303
        return array($content->versionInfo, $contentUpdateStruct);
3304
    }
3305
3306
    public function providerForTestUpdateContentNonRedundantFieldSet1()
3307
    {
3308
        $spiFields = array(
3309
            new SPIField(
3310
                array(
3311
                    'id' => '100',
3312
                    'fieldDefinitionId' => 'fieldDefinitionId',
3313
                    'type' => 'fieldTypeIdentifier',
3314
                    'value' => 'newValue',
3315
                    'languageCode' => 'eng-GB',
3316
                    'versionNo' => 7,
3317
                )
3318
            ),
3319
        );
3320
3321
        return array(
3322
            // With languages set
3323
            array(
3324
                'eng-GB',
3325
                array(
3326
                    new Field(
3327
                        array(
3328
                            'fieldDefIdentifier' => 'identifier',
3329
                            'value' => 'newValue',
3330
                            'languageCode' => 'eng-GB',
3331
                        )
3332
                    ),
3333
                ),
3334
                $spiFields,
3335
            ),
3336
            // Without languages set
3337
            array(
3338
                null,
3339
                array(
3340
                    new Field(
3341
                        array(
3342
                            'fieldDefIdentifier' => 'identifier',
3343
                            'value' => 'newValue',
3344
                            'languageCode' => null,
3345
                        )
3346
                    ),
3347
                ),
3348
                $spiFields,
3349
            ),
3350
            // Adding new language without fields
3351
            array(
3352
                'eng-US',
3353
                array(),
3354
                array(),
3355
            ),
3356
        );
3357
    }
3358
3359
    /**
3360
     * Test for the updateContent() method.
3361
     *
3362
     * Testing the simplest use case.
3363
     *
3364
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3365
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3366
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3367
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet1
3368
     */
3369 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet1($initialLanguageCode, $structFields, $spiFields)
3370
    {
3371
        $existingFields = array(
3372
            new Field(
3373
                array(
3374
                    'id' => '100',
3375
                    'fieldDefIdentifier' => 'identifier',
3376
                    'value' => 'initialValue',
3377
                    'languageCode' => 'eng-GB',
3378
                )
3379
            ),
3380
        );
3381
3382
        $fieldDefinitions = array(
3383
            new FieldDefinition(
3384
                array(
3385
                    'id' => 'fieldDefinitionId',
3386
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3387
                    'isTranslatable' => false,
3388
                    'identifier' => 'identifier',
3389
                    'isRequired' => false,
3390
                    'defaultValue' => 'defaultValue',
3391
                )
3392
            ),
3393
        );
3394
3395
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3396
            $initialLanguageCode,
3397
            $structFields,
3398
            $spiFields,
3399
            $existingFields,
3400
            $fieldDefinitions
3401
        );
3402
    }
3403
3404
    public function providerForTestUpdateContentNonRedundantFieldSet2()
3405
    {
3406
        $spiFields0 = array(
3407
            new SPIField(
3408
                array(
3409
                    'id' => '100',
3410
                    'fieldDefinitionId' => 'fieldDefinitionId',
3411
                    'type' => 'fieldTypeIdentifier',
3412
                    'value' => 'newValue',
3413
                    'languageCode' => 'eng-GB',
3414
                    'versionNo' => 7,
3415
                )
3416
            ),
3417
        );
3418
        $spiFields1 = array(
3419
            new SPIField(
3420
                array(
3421
                    'id' => null,
3422
                    'fieldDefinitionId' => 'fieldDefinitionId',
3423
                    'type' => 'fieldTypeIdentifier',
3424
                    'value' => 'newValue',
3425
                    'languageCode' => 'eng-US',
3426
                    'versionNo' => 7,
3427
                )
3428
            ),
3429
        );
3430
        $spiFields2 = array(
3431
            new SPIField(
3432
                array(
3433
                    'id' => 100,
3434
                    'fieldDefinitionId' => 'fieldDefinitionId',
3435
                    'type' => 'fieldTypeIdentifier',
3436
                    'value' => 'newValue2',
3437
                    'languageCode' => 'eng-GB',
3438
                    'versionNo' => 7,
3439
                )
3440
            ),
3441
            new SPIField(
3442
                array(
3443
                    'id' => null,
3444
                    'fieldDefinitionId' => 'fieldDefinitionId',
3445
                    'type' => 'fieldTypeIdentifier',
3446
                    'value' => 'newValue1',
3447
                    'languageCode' => 'eng-US',
3448
                    'versionNo' => 7,
3449
                )
3450
            ),
3451
        );
3452
3453
        return array(
3454
            // 0. With languages set
3455
            array(
3456
                'eng-GB',
3457
                array(
3458
                    new Field(
3459
                        array(
3460
                            'fieldDefIdentifier' => 'identifier',
3461
                            'value' => 'newValue',
3462
                            'languageCode' => 'eng-GB',
3463
                        )
3464
                    ),
3465
                ),
3466
                $spiFields0,
3467
            ),
3468
            // 1. Without languages set
3469
            array(
3470
                null,
3471
                array(
3472
                    new Field(
3473
                        array(
3474
                            'fieldDefIdentifier' => 'identifier',
3475
                            'value' => 'newValue',
3476
                            'languageCode' => null,
3477
                        )
3478
                    ),
3479
                ),
3480
                $spiFields0,
3481
            ),
3482
            // 2. New language with language set
3483
            array(
3484
                'eng-GB',
3485
                array(
3486
                    new Field(
3487
                        array(
3488
                            'fieldDefIdentifier' => 'identifier',
3489
                            'value' => 'newValue',
3490
                            'languageCode' => 'eng-US',
3491
                        )
3492
                    ),
3493
                ),
3494
                $spiFields1,
3495
            ),
3496
            // 3. New language without language set
3497
            array(
3498
                'eng-US',
3499
                array(
3500
                    new Field(
3501
                        array(
3502
                            'fieldDefIdentifier' => 'identifier',
3503
                            'value' => 'newValue',
3504
                            'languageCode' => null,
3505
                        )
3506
                    ),
3507
                ),
3508
                $spiFields1,
3509
            ),
3510
            // 4. New language and existing language with language set
3511
            array(
3512
                'eng-GB',
3513
                array(
3514
                    new Field(
3515
                        array(
3516
                            'fieldDefIdentifier' => 'identifier',
3517
                            'value' => 'newValue1',
3518
                            'languageCode' => 'eng-US',
3519
                        )
3520
                    ),
3521
                    new Field(
3522
                        array(
3523
                            'fieldDefIdentifier' => 'identifier',
3524
                            'value' => 'newValue2',
3525
                            'languageCode' => 'eng-GB',
3526
                        )
3527
                    ),
3528
                ),
3529
                $spiFields2,
3530
            ),
3531
            // 5. New language and existing language without language set
3532
            array(
3533
                'eng-US',
3534
                array(
3535
                    new Field(
3536
                        array(
3537
                            'fieldDefIdentifier' => 'identifier',
3538
                            'value' => 'newValue1',
3539
                            'languageCode' => null,
3540
                        )
3541
                    ),
3542
                    new Field(
3543
                        array(
3544
                            'fieldDefIdentifier' => 'identifier',
3545
                            'value' => 'newValue2',
3546
                            'languageCode' => 'eng-GB',
3547
                        )
3548
                    ),
3549
                ),
3550
                $spiFields2,
3551
            ),
3552
            // 6. Adding new language without fields
3553
            array(
3554
                'eng-US',
3555
                array(),
3556
                array(
3557
                    new SPIField(
3558
                        array(
3559
                            'id' => null,
3560
                            'fieldDefinitionId' => 'fieldDefinitionId',
3561
                            'type' => 'fieldTypeIdentifier',
3562
                            'value' => 'defaultValue',
3563
                            'languageCode' => 'eng-US',
3564
                            'versionNo' => 7,
3565
                        )
3566
                    ),
3567
                ),
3568
            ),
3569
        );
3570
    }
3571
3572
    /**
3573
     * Test for the updateContent() method.
3574
     *
3575
     * Testing with translatable field.
3576
     *
3577
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3578
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3579
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3580
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet2
3581
     */
3582 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet2($initialLanguageCode, $structFields, $spiFields)
3583
    {
3584
        $existingFields = array(
3585
            new Field(
3586
                array(
3587
                    'id' => '100',
3588
                    'fieldDefIdentifier' => 'identifier',
3589
                    'value' => 'initialValue',
3590
                    'languageCode' => 'eng-GB',
3591
                )
3592
            ),
3593
        );
3594
3595
        $fieldDefinitions = array(
3596
            new FieldDefinition(
3597
                array(
3598
                    'id' => 'fieldDefinitionId',
3599
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3600
                    'isTranslatable' => true,
3601
                    'identifier' => 'identifier',
3602
                    'isRequired' => false,
3603
                    'defaultValue' => 'defaultValue',
3604
                )
3605
            ),
3606
        );
3607
3608
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3609
            $initialLanguageCode,
3610
            $structFields,
3611
            $spiFields,
3612
            $existingFields,
3613
            $fieldDefinitions
3614
        );
3615
    }
3616
3617
    public function providerForTestUpdateContentNonRedundantFieldSet3()
3618
    {
3619
        $spiFields0 = array(
3620
            new SPIField(
3621
                array(
3622
                    'id' => null,
3623
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3624
                    'type' => 'fieldTypeIdentifier',
3625
                    'value' => 'newValue1',
3626
                    'languageCode' => 'eng-US',
3627
                    'versionNo' => 7,
3628
                )
3629
            ),
3630
        );
3631
        $spiFields1 = array(
3632
            new SPIField(
3633
                array(
3634
                    'id' => 100,
3635
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3636
                    'type' => 'fieldTypeIdentifier',
3637
                    'value' => 'newValue2',
3638
                    'languageCode' => 'eng-GB',
3639
                    'versionNo' => 7,
3640
                )
3641
            ),
3642
            new SPIField(
3643
                array(
3644
                    'id' => null,
3645
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3646
                    'type' => 'fieldTypeIdentifier',
3647
                    'value' => 'newValue1',
3648
                    'languageCode' => 'eng-US',
3649
                    'versionNo' => 7,
3650
                )
3651
            ),
3652
        );
3653
        $spiFields2 = array(
3654
            new SPIField(
3655
                array(
3656
                    'id' => 100,
3657
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3658
                    'type' => 'fieldTypeIdentifier',
3659
                    'value' => 'newValue2',
3660
                    'languageCode' => 'eng-GB',
3661
                    'versionNo' => 7,
3662
                )
3663
            ),
3664
            new SPIField(
3665
                array(
3666
                    'id' => null,
3667
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3668
                    'type' => 'fieldTypeIdentifier',
3669
                    'value' => 'newValue1',
3670
                    'languageCode' => 'eng-US',
3671
                    'versionNo' => 7,
3672
                )
3673
            ),
3674
            new SPIField(
3675
                array(
3676
                    'id' => 101,
3677
                    'fieldDefinitionId' => 'fieldDefinitionId2',
3678
                    'type' => 'fieldTypeIdentifier',
3679
                    'value' => 'newValue3',
3680
                    'languageCode' => 'eng-GB',
3681
                    'versionNo' => 7,
3682
                )
3683
            ),
3684
        );
3685
        $spiFields3 = array(
3686
            new SPIField(
3687
                array(
3688
                    'id' => null,
3689
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3690
                    'type' => 'fieldTypeIdentifier',
3691
                    'value' => 'defaultValue1',
3692
                    'languageCode' => 'eng-US',
3693
                    'versionNo' => 7,
3694
                )
3695
            ),
3696
        );
3697
3698
        return array(
3699
            // 0. ew language with language set
3700
            array(
3701
                'eng-US',
3702
                array(
3703
                    new Field(
3704
                        array(
3705
                            'fieldDefIdentifier' => 'identifier1',
3706
                            'value' => 'newValue1',
3707
                            'languageCode' => 'eng-US',
3708
                        )
3709
                    ),
3710
                ),
3711
                $spiFields0,
3712
            ),
3713
            // 1. New language without language set
3714
            array(
3715
                'eng-US',
3716
                array(
3717
                    new Field(
3718
                        array(
3719
                            'fieldDefIdentifier' => 'identifier1',
3720
                            'value' => 'newValue1',
3721
                            'languageCode' => null,
3722
                        )
3723
                    ),
3724
                ),
3725
                $spiFields0,
3726
            ),
3727
            // 2. New language and existing language with language set
3728
            array(
3729
                'eng-US',
3730
                array(
3731
                    new Field(
3732
                        array(
3733
                            'fieldDefIdentifier' => 'identifier1',
3734
                            'value' => 'newValue1',
3735
                            'languageCode' => 'eng-US',
3736
                        )
3737
                    ),
3738
                    new Field(
3739
                        array(
3740
                            'fieldDefIdentifier' => 'identifier1',
3741
                            'value' => 'newValue2',
3742
                            'languageCode' => 'eng-GB',
3743
                        )
3744
                    ),
3745
                ),
3746
                $spiFields1,
3747
            ),
3748
            // 3. New language and existing language without language set
3749
            array(
3750
                'eng-US',
3751
                array(
3752
                    new Field(
3753
                        array(
3754
                            'fieldDefIdentifier' => 'identifier1',
3755
                            'value' => 'newValue1',
3756
                            'languageCode' => null,
3757
                        )
3758
                    ),
3759
                    new Field(
3760
                        array(
3761
                            'fieldDefIdentifier' => 'identifier1',
3762
                            'value' => 'newValue2',
3763
                            'languageCode' => 'eng-GB',
3764
                        )
3765
                    ),
3766
                ),
3767
                $spiFields1,
3768
            ),
3769
            // 4. New language and existing language with untranslatable field, with language set
3770
            array(
3771
                'eng-US',
3772
                array(
3773
                    new Field(
3774
                        array(
3775
                            'fieldDefIdentifier' => 'identifier1',
3776
                            'value' => 'newValue1',
3777
                            'languageCode' => 'eng-US',
3778
                        )
3779
                    ),
3780
                    new Field(
3781
                        array(
3782
                            'fieldDefIdentifier' => 'identifier1',
3783
                            'value' => 'newValue2',
3784
                            'languageCode' => 'eng-GB',
3785
                        )
3786
                    ),
3787
                    new Field(
3788
                        array(
3789
                            'fieldDefIdentifier' => 'identifier2',
3790
                            'value' => 'newValue3',
3791
                            'languageCode' => 'eng-GB',
3792
                        )
3793
                    ),
3794
                ),
3795
                $spiFields2,
3796
            ),
3797
            // 5. New language and existing language with untranslatable field, without language set
3798
            array(
3799
                'eng-US',
3800
                array(
3801
                    new Field(
3802
                        array(
3803
                            'fieldDefIdentifier' => 'identifier1',
3804
                            'value' => 'newValue1',
3805
                            'languageCode' => null,
3806
                        )
3807
                    ),
3808
                    new Field(
3809
                        array(
3810
                            'fieldDefIdentifier' => 'identifier1',
3811
                            'value' => 'newValue2',
3812
                            'languageCode' => 'eng-GB',
3813
                        )
3814
                    ),
3815
                    new Field(
3816
                        array(
3817
                            'fieldDefIdentifier' => 'identifier2',
3818
                            'value' => 'newValue3',
3819
                            'languageCode' => null,
3820
                        )
3821
                    ),
3822
                ),
3823
                $spiFields2,
3824
            ),
3825
            // 6. Adding new language without fields
3826
            array(
3827
                'eng-US',
3828
                array(),
3829
                $spiFields3,
3830
            ),
3831
        );
3832
    }
3833
3834
    /**
3835
     * Test for the updateContent() method.
3836
     *
3837
     * Testing with new language and untranslatable field.
3838
     *
3839
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3840
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3841
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3842
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet3
3843
     */
3844
    public function testUpdateContentNonRedundantFieldSet3($initialLanguageCode, $structFields, $spiFields)
3845
    {
3846
        $existingFields = array(
3847
            new Field(
3848
                array(
3849
                    'id' => '100',
3850
                    'fieldDefIdentifier' => 'identifier1',
3851
                    'value' => 'initialValue1',
3852
                    'languageCode' => 'eng-GB',
3853
                )
3854
            ),
3855
            new Field(
3856
                array(
3857
                    'id' => '101',
3858
                    'fieldDefIdentifier' => 'identifier2',
3859
                    'value' => 'initialValue2',
3860
                    'languageCode' => 'eng-GB',
3861
                )
3862
            ),
3863
        );
3864
3865
        $fieldDefinitions = array(
3866
            new FieldDefinition(
3867
                array(
3868
                    'id' => 'fieldDefinitionId1',
3869
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3870
                    'isTranslatable' => true,
3871
                    'identifier' => 'identifier1',
3872
                    'isRequired' => false,
3873
                    'defaultValue' => 'defaultValue1',
3874
                )
3875
            ),
3876
            new FieldDefinition(
3877
                array(
3878
                    'id' => 'fieldDefinitionId2',
3879
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3880
                    'isTranslatable' => false,
3881
                    'identifier' => 'identifier2',
3882
                    'isRequired' => false,
3883
                    'defaultValue' => 'defaultValue2',
3884
                )
3885
            ),
3886
        );
3887
3888
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3889
            $initialLanguageCode,
3890
            $structFields,
3891
            $spiFields,
3892
            $existingFields,
3893
            $fieldDefinitions
3894
        );
3895
    }
3896
3897
    public function providerForTestUpdateContentNonRedundantFieldSet4()
3898
    {
3899
        $spiFields0 = array(
3900
            new SPIField(
3901
                array(
3902
                    'id' => null,
3903
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3904
                    'type' => 'fieldTypeIdentifier',
3905
                    'value' => 'newValue1',
3906
                    'languageCode' => 'eng-US',
3907
                    'versionNo' => 7,
3908
                )
3909
            ),
3910
        );
3911
        $spiFields1 = array(
3912
            new SPIField(
3913
                array(
3914
                    'id' => 100,
3915
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3916
                    'type' => 'fieldTypeIdentifier',
3917
                    'value' => self::EMPTY_FIELD_VALUE,
3918
                    'languageCode' => 'eng-GB',
3919
                    'versionNo' => 7,
3920
                )
3921
            ),
3922
            new SPIField(
3923
                array(
3924
                    'id' => null,
3925
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3926
                    'type' => 'fieldTypeIdentifier',
3927
                    'value' => 'newValue1',
3928
                    'languageCode' => 'eng-US',
3929
                    'versionNo' => 7,
3930
                )
3931
            ),
3932
        );
3933
        $spiFields2 = array(
3934
            new SPIField(
3935
                array(
3936
                    'id' => 100,
3937
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3938
                    'type' => 'fieldTypeIdentifier',
3939
                    'value' => self::EMPTY_FIELD_VALUE,
3940
                    'languageCode' => 'eng-GB',
3941
                    'versionNo' => 7,
3942
                )
3943
            ),
3944
        );
3945
3946
        return array(
3947
            // 0. New translation with empty field by default
3948
            array(
3949
                'eng-US',
3950
                array(
3951
                    new Field(
3952
                        array(
3953
                            'fieldDefIdentifier' => 'identifier1',
3954
                            'value' => 'newValue1',
3955
                            'languageCode' => 'eng-US',
3956
                        )
3957
                    ),
3958
                ),
3959
                $spiFields0,
3960
            ),
3961
            // 1. New translation with empty field by default, without language set
3962
            array(
3963
                'eng-US',
3964
                array(
3965
                    new Field(
3966
                        array(
3967
                            'fieldDefIdentifier' => 'identifier1',
3968
                            'value' => 'newValue1',
3969
                            'languageCode' => null,
3970
                        )
3971
                    ),
3972
                ),
3973
                $spiFields0,
3974
            ),
3975
            // 2. New translation with empty field given
3976
            array(
3977
                'eng-US',
3978
                array(
3979
                    new Field(
3980
                        array(
3981
                            'fieldDefIdentifier' => 'identifier1',
3982
                            'value' => 'newValue1',
3983
                            'languageCode' => 'eng-US',
3984
                        )
3985
                    ),
3986
                    new Field(
3987
                        array(
3988
                            'fieldDefIdentifier' => 'identifier2',
3989
                            'value' => self::EMPTY_FIELD_VALUE,
3990
                            'languageCode' => 'eng-US',
3991
                        )
3992
                    ),
3993
                ),
3994
                $spiFields0,
3995
            ),
3996
            // 3. New translation with empty field given, without language set
3997
            array(
3998
                'eng-US',
3999
                array(
4000
                    new Field(
4001
                        array(
4002
                            'fieldDefIdentifier' => 'identifier1',
4003
                            'value' => 'newValue1',
4004
                            'languageCode' => null,
4005
                        )
4006
                    ),
4007
                    new Field(
4008
                        array(
4009
                            'fieldDefIdentifier' => 'identifier2',
4010
                            'value' => self::EMPTY_FIELD_VALUE,
4011
                            'languageCode' => null,
4012
                        )
4013
                    ),
4014
                ),
4015
                $spiFields0,
4016
            ),
4017
            // 4. Updating existing language with empty value
4018
            array(
4019
                'eng-US',
4020
                array(
4021
                    new Field(
4022
                        array(
4023
                            'fieldDefIdentifier' => 'identifier1',
4024
                            'value' => 'newValue1',
4025
                            'languageCode' => 'eng-US',
4026
                        )
4027
                    ),
4028
                    new Field(
4029
                        array(
4030
                            'fieldDefIdentifier' => 'identifier1',
4031
                            'value' => self::EMPTY_FIELD_VALUE,
4032
                            'languageCode' => 'eng-GB',
4033
                        )
4034
                    ),
4035
                ),
4036
                $spiFields1,
4037
            ),
4038
            // 5. Updating existing language with empty value, without language set
4039
            array(
4040
                'eng-US',
4041
                array(
4042
                    new Field(
4043
                        array(
4044
                            'fieldDefIdentifier' => 'identifier1',
4045
                            'value' => 'newValue1',
4046
                            'languageCode' => null,
4047
                        )
4048
                    ),
4049
                    new Field(
4050
                        array(
4051
                            'fieldDefIdentifier' => 'identifier1',
4052
                            'value' => self::EMPTY_FIELD_VALUE,
4053
                            'languageCode' => 'eng-GB',
4054
                        )
4055
                    ),
4056
                ),
4057
                $spiFields1,
4058
            ),
4059
            // 6. Updating existing language with empty value and adding new language with empty value
4060
            array(
4061
                'eng-US',
4062
                array(
4063
                    new Field(
4064
                        array(
4065
                            'fieldDefIdentifier' => 'identifier1',
4066
                            'value' => self::EMPTY_FIELD_VALUE,
4067
                            'languageCode' => 'eng-US',
4068
                        )
4069
                    ),
4070
                    new Field(
4071
                        array(
4072
                            'fieldDefIdentifier' => 'identifier1',
4073
                            'value' => self::EMPTY_FIELD_VALUE,
4074
                            'languageCode' => 'eng-GB',
4075
                        )
4076
                    ),
4077
                ),
4078
                $spiFields2,
4079
            ),
4080
            // 7. Updating existing language with empty value and adding new language with empty value,
4081
            // without language set
4082
            array(
4083
                'eng-US',
4084
                array(
4085
                    new Field(
4086
                        array(
4087
                            'fieldDefIdentifier' => 'identifier1',
4088
                            'value' => self::EMPTY_FIELD_VALUE,
4089
                            'languageCode' => null,
4090
                        )
4091
                    ),
4092
                    new Field(
4093
                        array(
4094
                            'fieldDefIdentifier' => 'identifier1',
4095
                            'value' => self::EMPTY_FIELD_VALUE,
4096
                            'languageCode' => 'eng-GB',
4097
                        )
4098
                    ),
4099
                ),
4100
                $spiFields2,
4101
            ),
4102
            // 8. Adding new language with no fields given
4103
            array(
4104
                'eng-US',
4105
                array(),
4106
                array(),
4107
            ),
4108
            // 9. Adding new language with fields
4109
            array(
4110
                'eng-US',
4111
                array(
4112
                    new Field(
4113
                        array(
4114
                            'fieldDefIdentifier' => 'identifier1',
4115
                            'value' => self::EMPTY_FIELD_VALUE,
4116
                            'languageCode' => 'eng-US',
4117
                        )
4118
                    ),
4119
                ),
4120
                array(),
4121
            ),
4122
            // 10. Adding new language with fields, without language set
4123
            array(
4124
                'eng-US',
4125
                array(
4126
                    new Field(
4127
                        array(
4128
                            'fieldDefIdentifier' => 'identifier1',
4129
                            'value' => self::EMPTY_FIELD_VALUE,
4130
                            'languageCode' => null,
4131
                        )
4132
                    ),
4133
                ),
4134
                array(),
4135
            ),
4136
        );
4137
    }
4138
4139
    /**
4140
     * Test for the updateContent() method.
4141
     *
4142
     * Testing with empty values.
4143
     *
4144
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4145
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4146
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4147
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet4
4148
     */
4149
    public function testUpdateContentNonRedundantFieldSet4($initialLanguageCode, $structFields, $spiFields)
4150
    {
4151
        $existingFields = array(
4152
            new Field(
4153
                array(
4154
                    'id' => '100',
4155
                    'fieldDefIdentifier' => 'identifier1',
4156
                    'value' => 'initialValue1',
4157
                    'languageCode' => 'eng-GB',
4158
                )
4159
            ),
4160
            new Field(
4161
                array(
4162
                    'id' => '101',
4163
                    'fieldDefIdentifier' => 'identifier2',
4164
                    'value' => 'initialValue2',
4165
                    'languageCode' => 'eng-GB',
4166
                )
4167
            ),
4168
        );
4169
4170
        $fieldDefinitions = array(
4171
            new FieldDefinition(
4172
                array(
4173
                    'id' => 'fieldDefinitionId1',
4174
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4175
                    'isTranslatable' => true,
4176
                    'identifier' => 'identifier1',
4177
                    'isRequired' => false,
4178
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4179
                )
4180
            ),
4181
            new FieldDefinition(
4182
                array(
4183
                    'id' => 'fieldDefinitionId2',
4184
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4185
                    'isTranslatable' => true,
4186
                    'identifier' => 'identifier2',
4187
                    'isRequired' => false,
4188
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4189
                )
4190
            ),
4191
        );
4192
4193
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4194
            $initialLanguageCode,
4195
            $structFields,
4196
            $spiFields,
4197
            $existingFields,
4198
            $fieldDefinitions
4199
        );
4200
    }
4201
4202
    /**
4203
     * @todo add first field empty
4204
     *
4205
     * @return array
4206
     */
4207
    public function providerForTestUpdateContentNonRedundantFieldSetComplex()
4208
    {
4209
        $spiFields0 = array(
4210
            new SPIField(
4211
                array(
4212
                    'id' => 100,
4213
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4214
                    'type' => 'fieldTypeIdentifier',
4215
                    'value' => 'newValue1-eng-GB',
4216
                    'languageCode' => 'eng-GB',
4217
                    'versionNo' => 7,
4218
                )
4219
            ),
4220
            new SPIField(
4221
                array(
4222
                    'id' => null,
4223
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4224
                    'type' => 'fieldTypeIdentifier',
4225
                    'value' => 'newValue4',
4226
                    'languageCode' => 'eng-US',
4227
                    'versionNo' => 7,
4228
                )
4229
            ),
4230
        );
4231
        $spiFields1 = array(
4232
            new SPIField(
4233
                array(
4234
                    'id' => 100,
4235
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4236
                    'type' => 'fieldTypeIdentifier',
4237
                    'value' => 'newValue1-eng-GB',
4238
                    'languageCode' => 'eng-GB',
4239
                    'versionNo' => 7,
4240
                )
4241
            ),
4242
            new SPIField(
4243
                array(
4244
                    'id' => null,
4245
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4246
                    'type' => 'fieldTypeIdentifier',
4247
                    'value' => 'newValue2',
4248
                    'languageCode' => 'eng-US',
4249
                    'versionNo' => 7,
4250
                )
4251
            ),
4252
            new SPIField(
4253
                array(
4254
                    'id' => null,
4255
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4256
                    'type' => 'fieldTypeIdentifier',
4257
                    'value' => 'defaultValue4',
4258
                    'languageCode' => 'eng-US',
4259
                    'versionNo' => 7,
4260
                )
4261
            ),
4262
        );
4263
        $spiFields2 = array(
4264
            new SPIField(
4265
                array(
4266
                    'id' => 100,
4267
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4268
                    'type' => 'fieldTypeIdentifier',
4269
                    'value' => 'newValue1-eng-GB',
4270
                    'languageCode' => 'eng-GB',
4271
                    'versionNo' => 7,
4272
                )
4273
            ),
4274
            new SPIField(
4275
                array(
4276
                    'id' => null,
4277
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4278
                    'type' => 'fieldTypeIdentifier',
4279
                    'value' => 'newValue2',
4280
                    'languageCode' => 'eng-US',
4281
                    'versionNo' => 7,
4282
                )
4283
            ),
4284
            new SPIField(
4285
                array(
4286
                    'id' => null,
4287
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4288
                    'type' => 'fieldTypeIdentifier',
4289
                    'value' => 'defaultValue4',
4290
                    'languageCode' => 'ger-DE',
4291
                    'versionNo' => 7,
4292
                )
4293
            ),
4294
            new SPIField(
4295
                array(
4296
                    'id' => null,
4297
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4298
                    'type' => 'fieldTypeIdentifier',
4299
                    'value' => 'defaultValue4',
4300
                    'languageCode' => 'eng-US',
4301
                    'versionNo' => 7,
4302
                )
4303
            ),
4304
        );
4305
4306
        return array(
4307
            // 0. Add new language and update existing
4308
            array(
4309
                'eng-US',
4310
                array(
4311
                    new Field(
4312
                        array(
4313
                            'fieldDefIdentifier' => 'identifier4',
4314
                            'value' => 'newValue4',
4315
                            'languageCode' => 'eng-US',
4316
                        )
4317
                    ),
4318
                    new Field(
4319
                        array(
4320
                            'fieldDefIdentifier' => 'identifier1',
4321
                            'value' => 'newValue1-eng-GB',
4322
                            'languageCode' => 'eng-GB',
4323
                        )
4324
                    ),
4325
                ),
4326
                $spiFields0,
4327
            ),
4328
            // 1. Add new language and update existing, without language set
4329
            array(
4330
                'eng-US',
4331
                array(
4332
                    new Field(
4333
                        array(
4334
                            'fieldDefIdentifier' => 'identifier4',
4335
                            'value' => 'newValue4',
4336
                            'languageCode' => null,
4337
                        )
4338
                    ),
4339
                    new Field(
4340
                        array(
4341
                            'fieldDefIdentifier' => 'identifier1',
4342
                            'value' => 'newValue1-eng-GB',
4343
                            'languageCode' => 'eng-GB',
4344
                        )
4345
                    ),
4346
                ),
4347
                $spiFields0,
4348
            ),
4349
            // 2. Add new language and update existing variant
4350
            array(
4351
                'eng-US',
4352
                array(
4353
                    new Field(
4354
                        array(
4355
                            'fieldDefIdentifier' => 'identifier2',
4356
                            'value' => 'newValue2',
4357
                            'languageCode' => 'eng-US',
4358
                        )
4359
                    ),
4360
                    new Field(
4361
                        array(
4362
                            'fieldDefIdentifier' => 'identifier1',
4363
                            'value' => 'newValue1-eng-GB',
4364
                            'languageCode' => 'eng-GB',
4365
                        )
4366
                    ),
4367
                ),
4368
                $spiFields1,
4369
            ),
4370
            // 3. Add new language and update existing variant, without language set
4371
            array(
4372
                'eng-US',
4373
                array(
4374
                    new Field(
4375
                        array(
4376
                            'fieldDefIdentifier' => 'identifier2',
4377
                            'value' => 'newValue2',
4378
                            'languageCode' => null,
4379
                        )
4380
                    ),
4381
                    new Field(
4382
                        array(
4383
                            'fieldDefIdentifier' => 'identifier1',
4384
                            'value' => 'newValue1-eng-GB',
4385
                            'languageCode' => 'eng-GB',
4386
                        )
4387
                    ),
4388
                ),
4389
                $spiFields1,
4390
            ),
4391
            // 4. Update with multiple languages
4392
            array(
4393
                'ger-DE',
4394
                array(
4395
                    new Field(
4396
                        array(
4397
                            'fieldDefIdentifier' => 'identifier2',
4398
                            'value' => 'newValue2',
4399
                            'languageCode' => 'eng-US',
4400
                        )
4401
                    ),
4402
                    new Field(
4403
                        array(
4404
                            'fieldDefIdentifier' => 'identifier1',
4405
                            'value' => 'newValue1-eng-GB',
4406
                            'languageCode' => 'eng-GB',
4407
                        )
4408
                    ),
4409
                ),
4410
                $spiFields2,
4411
            ),
4412
            // 5. Update with multiple languages without language set
4413
            array(
4414
                'ger-DE',
4415
                array(
4416
                    new Field(
4417
                        array(
4418
                            'fieldDefIdentifier' => 'identifier2',
4419
                            'value' => 'newValue2',
4420
                            'languageCode' => 'eng-US',
4421
                        )
4422
                    ),
4423
                    new Field(
4424
                        array(
4425
                            'fieldDefIdentifier' => 'identifier1',
4426
                            'value' => 'newValue1-eng-GB',
4427
                            'languageCode' => null,
4428
                        )
4429
                    ),
4430
                ),
4431
                $spiFields2,
4432
            ),
4433
        );
4434
    }
4435
4436
    protected function fixturesForTestUpdateContentNonRedundantFieldSetComplex()
4437
    {
4438
        $existingFields = array(
4439
            new Field(
4440
                array(
4441
                    'id' => '100',
4442
                    'fieldDefIdentifier' => 'identifier1',
4443
                    'value' => 'initialValue1',
4444
                    'languageCode' => 'eng-GB',
4445
                )
4446
            ),
4447
            new Field(
4448
                array(
4449
                    'id' => '101',
4450
                    'fieldDefIdentifier' => 'identifier2',
4451
                    'value' => 'initialValue2',
4452
                    'languageCode' => 'eng-GB',
4453
                )
4454
            ),
4455
            new Field(
4456
                array(
4457
                    'id' => '102',
4458
                    'fieldDefIdentifier' => 'identifier3',
4459
                    'value' => 'initialValue3',
4460
                    'languageCode' => 'eng-GB',
4461
                )
4462
            ),
4463
            new Field(
4464
                array(
4465
                    'id' => '103',
4466
                    'fieldDefIdentifier' => 'identifier4',
4467
                    'value' => 'initialValue4',
4468
                    'languageCode' => 'eng-GB',
4469
                )
4470
            ),
4471
        );
4472
4473
        $fieldDefinitions = array(
4474
            new FieldDefinition(
4475
                array(
4476
                    'id' => 'fieldDefinitionId1',
4477
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4478
                    'isTranslatable' => false,
4479
                    'identifier' => 'identifier1',
4480
                    'isRequired' => false,
4481
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4482
                )
4483
            ),
4484
            new FieldDefinition(
4485
                array(
4486
                    'id' => 'fieldDefinitionId2',
4487
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4488
                    'isTranslatable' => true,
4489
                    'identifier' => 'identifier2',
4490
                    'isRequired' => false,
4491
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4492
                )
4493
            ),
4494
            new FieldDefinition(
4495
                array(
4496
                    'id' => 'fieldDefinitionId3',
4497
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4498
                    'isTranslatable' => false,
4499
                    'identifier' => 'identifier3',
4500
                    'isRequired' => false,
4501
                    'defaultValue' => 'defaultValue3',
4502
                )
4503
            ),
4504
            new FieldDefinition(
4505
                array(
4506
                    'id' => 'fieldDefinitionId4',
4507
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4508
                    'isTranslatable' => true,
4509
                    'identifier' => 'identifier4',
4510
                    'isRequired' => false,
4511
                    'defaultValue' => 'defaultValue4',
4512
                )
4513
            ),
4514
        );
4515
4516
        return array($existingFields, $fieldDefinitions);
4517
    }
4518
4519
    /**
4520
     * Test for the updateContent() method.
4521
     *
4522
     * Testing more complex cases.
4523
     *
4524
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4525
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4526
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4527
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSetComplex
4528
     */
4529
    public function testUpdateContentNonRedundantFieldSetComplex($initialLanguageCode, $structFields, $spiFields)
4530
    {
4531
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
4532
4533
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4534
            $initialLanguageCode,
4535
            $structFields,
4536
            $spiFields,
4537
            $existingFields,
4538
            $fieldDefinitions
4539
        );
4540
    }
4541
4542 View Code Duplication
    public function providerForTestUpdateContentWithInvalidLanguage()
4543
    {
4544
        return array(
4545
            array(
4546
                'eng-GB',
4547
                array(
4548
                    new Field(
4549
                        array(
4550
                            'fieldDefIdentifier' => 'identifier',
4551
                            'value' => 'newValue',
4552
                            'languageCode' => 'Klingon',
4553
                        )
4554
                    ),
4555
                ),
4556
            ),
4557
            array(
4558
                'Klingon',
4559
                array(
4560
                    new Field(
4561
                        array(
4562
                            'fieldDefIdentifier' => 'identifier',
4563
                            'value' => 'newValue',
4564
                            'languageCode' => 'eng-GB',
4565
                        )
4566
                    ),
4567
                ),
4568
            ),
4569
        );
4570
    }
4571
4572
    /**
4573
     * Test for the updateContent() method.
4574
     *
4575
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4576
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4577
     * @dataProvider providerForTestUpdateContentWithInvalidLanguage
4578
     */
4579
    public function testUpdateContentWithInvalidLanguage($initialLanguageCode, $structFields)
4580
    {
4581
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
4582
        $this->expectExceptionMessage('Could not find \'Language\' with identifier \'Klingon\'');
4583
4584
        $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...
4585
        $permissionResolverMock = $this->getPermissionResolverMock();
4586
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
4587
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4588
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4589
        $versionInfo = new VersionInfo(
4590
            array(
4591
                'contentInfo' => new ContentInfo(
4592
                    array(
4593
                        'id' => 42,
4594
                        'contentTypeId' => 24,
4595
                        'mainLanguageCode' => 'eng-GB',
4596
                    )
4597
                ),
4598
                'versionNo' => 7,
4599
                'languageCodes' => array('eng-GB'),
4600
                'status' => VersionInfo::STATUS_DRAFT,
4601
            )
4602
        );
4603
        $content = new Content(
4604
            array(
4605
                'versionInfo' => $versionInfo,
4606
                'internalFields' => array(),
4607
            )
4608
        );
4609
4610
        $languageHandlerMock->expects($this->any())
4611
            ->method('loadByLanguageCode')
4612
            ->with($this->isType('string'))
4613
            ->will(
4614
                $this->returnCallback(
4615 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...
4616
                        if ($languageCode === 'Klingon') {
4617
                            throw new NotFoundException('Language', 'Klingon');
4618
                        }
4619
4620
                        return new Language(array('id' => 4242));
4621
                    }
4622
                )
4623
            );
4624
4625
        $mockedService->expects($this->once())
4626
            ->method('loadContent')
4627
            ->with(
4628
                $this->equalTo(42),
4629
                $this->equalTo(null),
4630
                $this->equalTo(7)
4631
            )->will(
4632
                $this->returnValue($content)
4633
            );
4634
4635
        $permissionResolverMock->expects($this->once())
4636
            ->method('canUser')
4637
            ->with(
4638
                $this->equalTo('content'),
4639
                $this->equalTo('edit'),
4640
                $this->equalTo($content),
4641
                $this->isType('array')
4642
            )->will($this->returnValue(true));
4643
4644
        $contentUpdateStruct = new ContentUpdateStruct(
4645
            array(
4646
                'fields' => $structFields,
4647
                'initialLanguageCode' => $initialLanguageCode,
4648
            )
4649
        );
4650
4651
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4652
    }
4653
4654
    protected function assertForUpdateContentContentValidationException(
4655
        $initialLanguageCode,
4656
        $structFields,
4657
        $fieldDefinitions = array()
4658
    ) {
4659
        $repositoryMock = $this->getRepositoryMock();
4660
        $permissionResolverMock = $this->getPermissionResolverMock();
4661
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
4662
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4663
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4664
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4665
        $versionInfo = new VersionInfo(
4666
            array(
4667
                'contentInfo' => new ContentInfo(
4668
                    array(
4669
                        'id' => 42,
4670
                        'contentTypeId' => 24,
4671
                        'mainLanguageCode' => 'eng-GB',
4672
                    )
4673
                ),
4674
                'versionNo' => 7,
4675
                'languageCodes' => array('eng-GB'),
4676
                'status' => VersionInfo::STATUS_DRAFT,
4677
            )
4678
        );
4679
        $content = new Content(
4680
            array(
4681
                'versionInfo' => $versionInfo,
4682
                'internalFields' => array(),
4683
            )
4684
        );
4685
        $contentType = new ContentType(array('fieldDefinitions' => $fieldDefinitions));
4686
4687
        $languageHandlerMock->expects($this->any())
4688
            ->method('loadByLanguageCode')
4689
            ->with($this->isType('string'))
4690
            ->will(
4691
                $this->returnCallback(
4692 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...
4693
                        if ($languageCode === 'Klingon') {
4694
                            throw new NotFoundException('Language', 'Klingon');
4695
                        }
4696
4697
                        return new Language(array('id' => 4242));
4698
                    }
4699
                )
4700
            );
4701
4702
        $mockedService->expects($this->once())
4703
            ->method('loadContent')
4704
            ->with(
4705
                $this->equalTo(42),
4706
                $this->equalTo(null),
4707
                $this->equalTo(7)
4708
            )->will(
4709
                $this->returnValue($content)
4710
            );
4711
4712
        $permissionResolverMock->expects($this->once())
4713
            ->method('canUser')
4714
            ->with(
4715
                $this->equalTo('content'),
4716
                $this->equalTo('edit'),
4717
                $this->equalTo($content),
4718
                $this->isType('array')
4719
            )->will($this->returnValue(true));
4720
4721
        $contentTypeServiceMock->expects($this->once())
4722
            ->method('loadContentType')
4723
            ->with($this->equalTo(24))
4724
            ->will($this->returnValue($contentType));
4725
4726
        $repositoryMock->expects($this->once())
4727
            ->method('getContentTypeService')
4728
            ->will($this->returnValue($contentTypeServiceMock));
4729
4730
        $contentUpdateStruct = new ContentUpdateStruct(
4731
            array(
4732
                'fields' => $structFields,
4733
                'initialLanguageCode' => $initialLanguageCode,
4734
            )
4735
        );
4736
4737
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4738
    }
4739
4740 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition()
4741
    {
4742
        return array(
4743
            array(
4744
                'eng-GB',
4745
                array(
4746
                    new Field(
4747
                        array(
4748
                            'fieldDefIdentifier' => 'identifier',
4749
                            'value' => 'newValue',
4750
                            'languageCode' => 'eng-GB',
4751
                        )
4752
                    ),
4753
                ),
4754
            ),
4755
        );
4756
    }
4757
4758
    /**
4759
     * Test for the updateContent() method.
4760
     *
4761
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4762
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4763
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4764
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition
4765
     */
4766
    public function testUpdateContentThrowsContentValidationExceptionFieldDefinition($initialLanguageCode, $structFields)
4767
    {
4768
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
4769
        $this->expectExceptionMessage('Field definition \'identifier\' does not exist in given ContentType');
4770
4771
        $this->assertForUpdateContentContentValidationException(
4772
            $initialLanguageCode,
4773
            $structFields,
4774
            array()
4775
        );
4776
    }
4777
4778 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionTranslation()
4779
    {
4780
        return array(
4781
            array(
4782
                'eng-US',
4783
                array(
4784
                    new Field(
4785
                        array(
4786
                            'fieldDefIdentifier' => 'identifier',
4787
                            'value' => 'newValue',
4788
                            'languageCode' => 'eng-US',
4789
                        )
4790
                    ),
4791
                ),
4792
            ),
4793
        );
4794
    }
4795
4796
    /**
4797
     * Test for the updateContent() method.
4798
     *
4799
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4800
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4801
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4802
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionTranslation
4803
     */
4804 View Code Duplication
    public function testUpdateContentThrowsContentValidationExceptionTranslation($initialLanguageCode, $structFields)
4805
    {
4806
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
4807
        $this->expectExceptionMessage('A value is set for non translatable field definition \'identifier\' with language \'eng-US\'');
4808
4809
        $fieldDefinitions = array(
4810
            new FieldDefinition(
4811
                array(
4812
                    'id' => 'fieldDefinitionId1',
4813
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4814
                    'isTranslatable' => false,
4815
                    'identifier' => 'identifier',
4816
                    'isRequired' => false,
4817
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4818
                )
4819
            ),
4820
        );
4821
4822
        $this->assertForUpdateContentContentValidationException(
4823
            $initialLanguageCode,
4824
            $structFields,
4825
            $fieldDefinitions
4826
        );
4827
    }
4828
4829
    public function assertForTestUpdateContentRequiredField(
4830
        $initialLanguageCode,
4831
        $structFields,
4832
        $existingFields,
4833
        $fieldDefinitions
4834
    ) {
4835
        $repositoryMock = $this->getRepositoryMock();
4836
        $permissionResolver = $this->getPermissionResolverMock();
4837
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
4838
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4839
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4840
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4841
        $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...
4842
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
4843
        $existingLanguageCodes = array_map(
4844
            function (Field $field) {
4845
                return $field->languageCode;
4846
            },
4847
            $existingFields
4848
        );
4849
        $versionInfo = new VersionInfo(
4850
            array(
4851
                'contentInfo' => new ContentInfo(
4852
                    array(
4853
                        'id' => 42,
4854
                        'contentTypeId' => 24,
4855
                        'mainLanguageCode' => 'eng-GB',
4856
                    )
4857
                ),
4858
                'versionNo' => 7,
4859
                'languageCodes' => $existingLanguageCodes,
4860
                'status' => VersionInfo::STATUS_DRAFT,
4861
            )
4862
        );
4863
        $content = new Content(
4864
            array(
4865
                'versionInfo' => $versionInfo,
4866
                'internalFields' => $existingFields,
4867
            )
4868
        );
4869
        $contentType = new ContentType(array('fieldDefinitions' => $fieldDefinitions));
4870
4871
        $languageHandlerMock->expects($this->any())
4872
            ->method('loadByLanguageCode')
4873
            ->with($this->isType('string'))
4874
            ->will(
4875
                $this->returnCallback(
4876
                    function () {
4877
                        return new Language(array('id' => 4242));
4878
                    }
4879
                )
4880
            );
4881
4882
        $mockedService->expects($this->once())
4883
            ->method('loadContent')
4884
            ->with(
4885
                $this->equalTo(42),
4886
                $this->equalTo(null),
4887
                $this->equalTo(7)
4888
            )->will(
4889
                $this->returnValue($content)
4890
            );
4891
4892
        $permissionResolver->expects($this->once())
4893
            ->method('canUser')
4894
            ->with(
4895
                $this->equalTo('content'),
4896
                $this->equalTo('edit'),
4897
                $this->equalTo($content),
4898
                $this->isType('array')
4899
            )->will($this->returnValue(true));
4900
4901
        $contentTypeServiceMock->expects($this->once())
4902
            ->method('loadContentType')
4903
            ->with($this->equalTo(24))
4904
            ->will($this->returnValue($contentType));
4905
4906
        $repositoryMock->expects($this->once())
4907
            ->method('getContentTypeService')
4908
            ->will($this->returnValue($contentTypeServiceMock));
4909
4910
        $fieldTypeMock->expects($this->any())
4911
            ->method('acceptValue')
4912
            ->will(
4913
                $this->returnCallback(
4914
                    function ($valueString) {
4915
                        return new ValueStub($valueString);
4916
                    }
4917
                )
4918
            );
4919
4920
        $emptyValue = self::EMPTY_FIELD_VALUE;
4921
        $fieldTypeMock->expects($this->any())
4922
            ->method('isEmptyValue')
4923
            ->will(
4924
                $this->returnCallback(
4925
                    function (ValueStub $value) use ($emptyValue) {
4926
                        return $emptyValue === (string)$value;
4927
                    }
4928
                )
4929
            );
4930
4931
        $fieldTypeMock->expects($this->any())
4932
            ->method('validate')
4933
            ->with(
4934
                $this->isInstanceOf(APIFieldDefinition::class),
4935
                $this->isInstanceOf(Value::class)
4936
            );
4937
4938
        $this->getFieldTypeRegistryMock()->expects($this->any())
4939
            ->method('getFieldType')
4940
            ->will($this->returnValue($fieldTypeMock));
4941
4942
        $contentUpdateStruct = new ContentUpdateStruct(
4943
            array(
4944
                'fields' => $structFields,
4945
                'initialLanguageCode' => $initialLanguageCode,
4946
            )
4947
        );
4948
4949
        return array($content->versionInfo, $contentUpdateStruct);
4950
    }
4951
4952 View Code Duplication
    public function providerForTestUpdateContentRequiredField()
4953
    {
4954
        return array(
4955
            array(
4956
                'eng-US',
4957
                array(
4958
                    new Field(
4959
                        array(
4960
                            'fieldDefIdentifier' => 'identifier',
4961
                            'value' => self::EMPTY_FIELD_VALUE,
4962
                            'languageCode' => null,
4963
                        )
4964
                    ),
4965
                ),
4966
                'identifier',
4967
                'eng-US',
4968
            ),
4969
        );
4970
    }
4971
4972
    /**
4973
     * Test for the updateContent() method.
4974
     *
4975
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4976
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4977
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4978
     * @dataProvider providerForTestUpdateContentRequiredField
4979
     */
4980
    public function testUpdateContentRequiredField(
4981
        $initialLanguageCode,
4982
        $structFields,
4983
        $identifier,
4984
        $languageCode
4985
    ) {
4986
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
4987
4988
        $existingFields = array(
4989
            new Field(
4990
                array(
4991
                    'id' => '100',
4992
                    'fieldDefIdentifier' => 'identifier',
4993
                    'value' => 'initialValue',
4994
                    'languageCode' => 'eng-GB',
4995
                )
4996
            ),
4997
        );
4998
        $fieldDefinitions = array(
4999
            new FieldDefinition(
5000
                array(
5001
                    'id' => 'fieldDefinitionId',
5002
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5003
                    'isTranslatable' => true,
5004
                    'identifier' => 'identifier',
5005
                    'isRequired' => true,
5006
                    'defaultValue' => 'defaultValue',
5007
                )
5008
            ),
5009
        );
5010
        list($versionInfo, $contentUpdateStruct) =
5011
            $this->assertForTestUpdateContentRequiredField(
5012
                $initialLanguageCode,
5013
                $structFields,
5014
                $existingFields,
5015
                $fieldDefinitions
5016
            );
5017
5018
        try {
5019
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5020
        } catch (ContentValidationException $e) {
5021
            $this->assertEquals(
5022
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
5023
                $e->getMessage()
5024
            );
5025
5026
            throw $e;
5027
        }
5028
    }
5029
5030
    public function assertForTestUpdateContentThrowsContentFieldValidationException(
5031
        $initialLanguageCode,
5032
        $structFields,
5033
        $existingFields,
5034
        $fieldDefinitions
5035
    ) {
5036
        $repositoryMock = $this->getRepositoryMock();
5037
        $permissionResolverMock = $this->getPermissionResolverMock();
5038
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
5039
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
5040
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
5041
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5042
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
5043
        $existingLanguageCodes = array_map(
5044
            function (Field $field) {
5045
                return $field->languageCode;
5046
            },
5047
            $existingFields
5048
        );
5049
        $languageCodes = $this->determineLanguageCodesForUpdate(
5050
            $initialLanguageCode,
5051
            $structFields,
5052
            $existingLanguageCodes
5053
        );
5054
        $versionInfo = new VersionInfo(
5055
            array(
5056
                'contentInfo' => new ContentInfo(
5057
                    array(
5058
                        'id' => 42,
5059
                        'contentTypeId' => 24,
5060
                        'mainLanguageCode' => 'eng-GB',
5061
                    )
5062
                ),
5063
                'versionNo' => 7,
5064
                'languageCodes' => $existingLanguageCodes,
5065
                'status' => VersionInfo::STATUS_DRAFT,
5066
            )
5067
        );
5068
        $content = new Content(
5069
            array(
5070
                'versionInfo' => $versionInfo,
5071
                'internalFields' => $existingFields,
5072
            )
5073
        );
5074
        $contentType = new ContentType(array('fieldDefinitions' => $fieldDefinitions));
5075
5076
        $languageHandlerMock->expects($this->any())
5077
            ->method('loadByLanguageCode')
5078
            ->with($this->isType('string'))
5079
            ->will(
5080
                $this->returnCallback(
5081
                    function () {
5082
                        return new Language(array('id' => 4242));
5083
                    }
5084
                )
5085
            );
5086
5087
        $mockedService->expects($this->once())
5088
            ->method('loadContent')
5089
            ->with(
5090
                $this->equalTo(42),
5091
                $this->equalTo(null),
5092
                $this->equalTo(7)
5093
            )->will(
5094
                $this->returnValue($content)
5095
            );
5096
5097
        $permissionResolverMock->expects($this->once())
5098
            ->method('canUser')
5099
            ->with(
5100
                $this->equalTo('content'),
5101
                $this->equalTo('edit'),
5102
                $this->equalTo($content),
5103
                $this->isType('array')
5104
            )->will($this->returnValue(true));
5105
5106
        $contentTypeServiceMock->expects($this->once())
5107
            ->method('loadContentType')
5108
            ->with($this->equalTo(24))
5109
            ->will($this->returnValue($contentType));
5110
5111
        $repositoryMock->expects($this->once())
5112
            ->method('getContentTypeService')
5113
            ->will($this->returnValue($contentTypeServiceMock));
5114
5115
        $fieldValues = $this->determineValuesForUpdate(
5116
            $initialLanguageCode,
5117
            $structFields,
5118
            $content,
5119
            $fieldDefinitions,
5120
            $languageCodes
5121
        );
5122
        $allFieldErrors = array();
5123
        $emptyValue = self::EMPTY_FIELD_VALUE;
5124
5125
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5126
            ->method('acceptValue')
5127
            ->will(
5128
                $this->returnCallback(
5129
                    function ($valueString) {
5130
                        return new ValueStub($valueString);
5131
                    }
5132
                )
5133
            );
5134
5135
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5136
            ->method('isEmptyValue')
5137
            ->will(
5138
                $this->returnCallback(
5139
                    function (ValueStub $value) use ($emptyValue) {
5140
                        return $emptyValue === (string)$value;
5141
                    }
5142
                )
5143
            );
5144
5145
        $fieldTypeMock
5146
            ->expects($this->any())
5147
            ->method('validate')
5148
            ->willReturnArgument(1);
5149
5150
        $this->getFieldTypeRegistryMock()->expects($this->any())
5151
            ->method('getFieldType')
5152
            ->will($this->returnValue($fieldTypeMock));
5153
5154
        $contentUpdateStruct = new ContentUpdateStruct(
5155
            array(
5156
                'fields' => $structFields,
5157
                'initialLanguageCode' => $initialLanguageCode,
5158
            )
5159
        );
5160
5161
        return array($content->versionInfo, $contentUpdateStruct, $allFieldErrors);
5162
    }
5163
5164
    public function providerForTestUpdateContentThrowsContentFieldValidationException()
5165
    {
5166
        $allFieldErrors = [
5167
            [
5168
                'fieldDefinitionId1' => [
5169
                    'eng-GB' => 'newValue1-eng-GB',
5170
                    'eng-US' => 'newValue1-eng-GB',
5171
                ],
5172
                'fieldDefinitionId2' => [
5173
                    'eng-GB' => 'initialValue2',
5174
                ],
5175
                'fieldDefinitionId3' => [
5176
                    'eng-GB' => 'initialValue3',
5177
                    'eng-US' => 'initialValue3',
5178
                ],
5179
                'fieldDefinitionId4' => [
5180
                    'eng-GB' => 'initialValue4',
5181
                    'eng-US' => 'newValue4',
5182
                ],
5183
            ],
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
                    'eng-US' => 'newValue2',
5209
                ],
5210
                'fieldDefinitionId3' => [
5211
                    'eng-GB' => 'initialValue3',
5212
                    'eng-US' => 'initialValue3',
5213
                ],
5214
                'fieldDefinitionId4' => [
5215
                    'eng-GB' => 'initialValue4',
5216
                    'eng-US' => 'defaultValue4',
5217
                ],
5218
            ],
5219
            [
5220
                'fieldDefinitionId1' => [
5221
                    'eng-GB' => 'newValue1-eng-GB',
5222
                    'eng-US' => 'newValue1-eng-GB',
5223
                ],
5224
                'fieldDefinitionId2' => [
5225
                    'eng-GB' => 'initialValue2',
5226
                    'eng-US' => 'newValue2',
5227
                ],
5228
                'fieldDefinitionId3' => [
5229
                    'eng-GB' => 'initialValue3',
5230
                    'eng-US' => 'initialValue3',
5231
                ],
5232
                'fieldDefinitionId4' => [
5233
                    'eng-GB' => 'initialValue4',
5234
                    'eng-US' => 'defaultValue4',
5235
                ],
5236
            ],
5237
            [
5238
                'fieldDefinitionId1' => [
5239
                    'eng-GB' => 'newValue1-eng-GB',
5240
                    'ger-DE' => 'newValue1-eng-GB',
5241
                    'eng-US' => 'newValue1-eng-GB',
5242
                ],
5243
                'fieldDefinitionId2' => [
5244
                    'eng-GB' => 'initialValue2',
5245
                    'eng-US' => 'newValue2',
5246
                ],
5247
                'fieldDefinitionId3' => [
5248
                    'eng-GB' => 'initialValue3',
5249
                    'ger-DE' => 'initialValue3',
5250
                    'eng-US' => 'initialValue3',
5251
                ],
5252
                'fieldDefinitionId4' => [
5253
                    'eng-GB' => 'initialValue4',
5254
                    'eng-US' => 'defaultValue4',
5255
                    'ger-DE' => 'defaultValue4',
5256
                ],
5257
            ],
5258
            [
5259
                'fieldDefinitionId1' => [
5260
                    'eng-US' => 'newValue1-eng-GB',
5261
                    'ger-DE' => 'newValue1-eng-GB',
5262
                ],
5263
                'fieldDefinitionId2' => [
5264
                    'eng-US' => 'newValue2',
5265
                ],
5266
                'fieldDefinitionId3' => [
5267
                    'ger-DE' => 'initialValue3',
5268
                    'eng-US' => 'initialValue3',
5269
                ],
5270
                'fieldDefinitionId4' => [
5271
                    'ger-DE' => 'defaultValue4',
5272
                    'eng-US' => 'defaultValue4',
5273
                ],
5274
            ],
5275
        ];
5276
5277
        $data = $this->providerForTestUpdateContentNonRedundantFieldSetComplex();
5278
        $count = count($data);
5279
        for ($i = 0; $i < $count; ++$i) {
5280
            $data[$i][] = $allFieldErrors[$i];
5281
        }
5282
5283
        return $data;
5284
    }
5285
5286
    /**
5287
     * Test for the updateContent() method.
5288
     *
5289
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5290
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5291
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5292
     * @dataProvider providerForTestUpdateContentThrowsContentFieldValidationException
5293
     */
5294 View Code Duplication
    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...
5295
    {
5296
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
5297
        $this->expectExceptionMessage('Content fields did not validate');
5298
5299
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
5300
        list($versionInfo, $contentUpdateStruct) =
5301
            $this->assertForTestUpdateContentThrowsContentFieldValidationException(
5302
                $initialLanguageCode,
5303
                $structFields,
5304
                $existingFields,
5305
                $fieldDefinitions
5306
            );
5307
5308
        try {
5309
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5310
        } catch (ContentFieldValidationException $e) {
5311
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
5312
            throw $e;
5313
        }
5314
    }
5315
5316
    /**
5317
     * Test for the updateContent() method.
5318
     *
5319
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5320
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5321
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5322
     */
5323
    public function testUpdateContentTransactionRollback()
5324
    {
5325
        $this->expectException(\Exception::class);
5326
        $this->expectExceptionMessage('Store failed');
5327
5328
        $existingFields = array(
5329
            new Field(
5330
                array(
5331
                    'id' => '100',
5332
                    'fieldDefIdentifier' => 'identifier',
5333
                    'value' => 'initialValue',
5334
                    'languageCode' => 'eng-GB',
5335
                )
5336
            ),
5337
        );
5338
5339
        $fieldDefinitions = array(
5340
            new FieldDefinition(
5341
                array(
5342
                    'id' => 'fieldDefinitionId',
5343
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5344
                    'isTranslatable' => false,
5345
                    'identifier' => 'identifier',
5346
                    'isRequired' => false,
5347
                    'defaultValue' => 'defaultValue',
5348
                )
5349
            ),
5350
        );
5351
5352
        // Setup a simple case that will pass
5353
        list($versionInfo, $contentUpdateStruct) = $this->assertForTestUpdateContentNonRedundantFieldSet(
5354
            'eng-US',
5355
            array(),
5356
            array(),
5357
            $existingFields,
5358
            $fieldDefinitions,
5359
            // Do not execute test
5360
            false
5361
        );
5362
5363
        $repositoryMock = $this->getRepositoryMock();
5364
        $repositoryMock->expects($this->never())->method('commit');
5365
        $repositoryMock->expects($this->once())->method('rollback');
5366
5367
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5368
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5369
        $contentHandlerMock->expects($this->once())
5370
            ->method('updateContent')
5371
            ->with(
5372
                $this->anything(),
5373
                $this->anything(),
5374
                $this->anything()
5375
            )->will($this->throwException(new \Exception('Store failed')));
5376
5377
        // Execute
5378
        $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5379
    }
5380
5381
    /**
5382
     * Test for the copyContent() method.
5383
     *
5384
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5385
     */
5386
    public function testCopyContentThrowsUnauthorizedException()
5387
    {
5388
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
5389
5390
        $repository = $this->getRepositoryMock();
5391
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
5392
        $contentInfo = $this->createMock(APIContentInfo::class);
5393
        $locationCreateStruct = new LocationCreateStruct();
5394
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5395
        $locationServiceMock = $this->getLocationServiceMock();
5396
5397
        $repository->expects($this->once())
5398
            ->method('getLocationService')
5399
            ->will($this->returnValue($locationServiceMock))
5400
        ;
5401
5402
        $locationServiceMock->expects($this->once())
5403
            ->method('loadLocation')
5404
            ->with(
5405
                $locationCreateStruct->parentLocationId
5406
            )
5407
            ->will($this->returnValue($location))
5408
        ;
5409
5410
        $contentInfo->expects($this->any())
5411
            ->method('__get')
5412
            ->with('sectionId')
5413
            ->will($this->returnValue(42));
5414
5415
        $repository->expects($this->once())
5416
            ->method('canUser')
5417
            ->with(
5418
                'content',
5419
                'create',
5420
                $contentInfo,
5421
                [$location]
5422
            )
5423
            ->will($this->returnValue(false));
5424
5425
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
5426
        $contentService->copyContent($contentInfo, $locationCreateStruct);
5427
    }
5428
5429
    /**
5430
     * Test for the copyContent() method.
5431
     *
5432
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5433
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5434
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5435
     */
5436
    public function testCopyContent()
5437
    {
5438
        $repositoryMock = $this->getRepositoryMock();
5439
        $contentService = $this->getPartlyMockedContentService(array(
5440
            'internalLoadContentInfo',
5441
            'internalLoadContent',
5442
            'getUnixTimestamp',
5443
        ));
5444
        $locationServiceMock = $this->getLocationServiceMock();
5445
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5446
        $locationCreateStruct = new LocationCreateStruct();
5447
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5448
        $user = $this->getStubbedUser(14);
5449
5450
        $permissionResolverMock = $this->getPermissionResolverMock();
5451
5452
        $permissionResolverMock
5453
            ->method('getCurrentUserReference')
5454
            ->willReturn($user);
5455
5456
        $repositoryMock
5457
            ->method('getPermissionResolver')
5458
            ->willReturn($permissionResolverMock);
5459
5460
        $repositoryMock->expects($this->exactly(3))
5461
            ->method('getLocationService')
5462
            ->will($this->returnValue($locationServiceMock));
5463
5464
        $locationServiceMock->expects($this->once())
5465
            ->method('loadLocation')
5466
            ->with($locationCreateStruct->parentLocationId)
5467
            ->will($this->returnValue($location))
5468
        ;
5469
5470
        $contentInfoMock->expects($this->any())
5471
            ->method('__get')
5472
            ->with('id')
5473
            ->will($this->returnValue(42));
5474
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5475
5476
        $versionInfoMock->expects($this->any())
5477
            ->method('__get')
5478
            ->will(
5479
                $this->returnValueMap(
5480
                    array(
5481
                        array('versionNo', 123),
5482
                    )
5483
                )
5484
            );
5485
5486
        $versionInfoMock->expects($this->once())
5487
            ->method('isDraft')
5488
            ->willReturn(true);
5489
5490
        $versionInfoMock->expects($this->once())
5491
            ->method('getContentInfo')
5492
            ->will($this->returnValue($contentInfoMock));
5493
5494
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5495
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5496
        $domainMapperMock = $this->getDomainMapperMock();
5497
5498
        $repositoryMock->expects($this->once())->method('beginTransaction');
5499
        $repositoryMock->expects($this->once())->method('commit');
5500
        $repositoryMock->expects($this->once())
5501
            ->method('canUser')
5502
            ->with(
5503
                'content',
5504
                'create',
5505
                $contentInfoMock,
5506
                [$location]
5507
            )
5508
            ->will($this->returnValue(true));
5509
5510
        $spiContentInfo = new SPIContentInfo(array('id' => 42));
5511
        $spiVersionInfo = new SPIVersionInfo(
5512
            array(
5513
                'contentInfo' => $spiContentInfo,
5514
                'creationDate' => 123456,
5515
            )
5516
        );
5517
        $spiContent = new SPIContent(array('versionInfo' => $spiVersionInfo));
5518
        $contentHandlerMock->expects($this->once())
5519
            ->method('copy')
5520
            ->with(42, null)
5521
            ->will($this->returnValue($spiContent));
5522
5523
        $this->mockGetDefaultObjectStates();
5524
        $this->mockSetDefaultObjectStates();
5525
5526
        $domainMapperMock->expects($this->once())
5527
            ->method('buildVersionInfoDomainObject')
5528
            ->with($spiVersionInfo)
5529
            ->will($this->returnValue($versionInfoMock));
5530
5531
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5532
        $content = $this->mockPublishVersion(123456, 126666);
5533
        $locationServiceMock->expects($this->once())
5534
            ->method('createLocation')
5535
            ->with(
5536
                $content->getVersionInfo()->getContentInfo(),
5537
                $locationCreateStruct
5538
            );
5539
5540
        $contentService->expects($this->once())
5541
            ->method('internalLoadContent')
5542
            ->with(
5543
                $content->id
5544
            )
5545
            ->will($this->returnValue($content));
5546
5547
        $contentService->expects($this->once())
5548
            ->method('getUnixTimestamp')
5549
            ->will($this->returnValue(126666));
5550
5551
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5552
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5553
    }
5554
5555
    /**
5556
     * Test for the copyContent() method.
5557
     *
5558
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5559
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5560
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5561
     */
5562
    public function testCopyContentWithVersionInfo()
5563
    {
5564
        $repositoryMock = $this->getRepositoryMock();
5565
        $contentService = $this->getPartlyMockedContentService(array(
5566
            'internalLoadContentInfo',
5567
            'internalLoadContent',
5568
            'getUnixTimestamp',
5569
        ));
5570
        $locationServiceMock = $this->getLocationServiceMock();
5571
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5572
        $locationCreateStruct = new LocationCreateStruct();
5573
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5574
        $user = $this->getStubbedUser(14);
5575
5576
        $permissionResolverMock = $this->getPermissionResolverMock();
5577
5578
        $permissionResolverMock
5579
            ->method('getCurrentUserReference')
5580
            ->willReturn($user);
5581
5582
        $repositoryMock
5583
            ->method('getPermissionResolver')
5584
            ->willReturn($permissionResolverMock);
5585
5586
        $repositoryMock->expects($this->exactly(3))
5587
            ->method('getLocationService')
5588
            ->will($this->returnValue($locationServiceMock));
5589
5590
        $locationServiceMock->expects($this->once())
5591
            ->method('loadLocation')
5592
            ->with($locationCreateStruct->parentLocationId)
5593
            ->will($this->returnValue($location))
5594
        ;
5595
5596
        $contentInfoMock->expects($this->any())
5597
            ->method('__get')
5598
            ->with('id')
5599
            ->will($this->returnValue(42));
5600
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5601
5602
        $versionInfoMock->expects($this->any())
5603
            ->method('__get')
5604
            ->will(
5605
                $this->returnValueMap(
5606
                    array(
5607
                        array('versionNo', 123),
5608
                    )
5609
                )
5610
            );
5611
        $versionInfoMock->expects($this->once())
5612
            ->method('isDraft')
5613
            ->willReturn(true);
5614
        $versionInfoMock->expects($this->once())
5615
            ->method('getContentInfo')
5616
            ->will($this->returnValue($contentInfoMock));
5617
5618
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5619
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5620
        $domainMapperMock = $this->getDomainMapperMock();
5621
5622
        $repositoryMock->expects($this->once())->method('beginTransaction');
5623
        $repositoryMock->expects($this->once())->method('commit');
5624
        $repositoryMock->expects($this->once())
5625
            ->method('canUser')
5626
            ->with(
5627
                'content',
5628
                'create',
5629
                $contentInfoMock,
5630
                [$location]
5631
            )
5632
            ->will($this->returnValue(true));
5633
5634
        $spiContentInfo = new SPIContentInfo(array('id' => 42));
5635
        $spiVersionInfo = new SPIVersionInfo(
5636
            array(
5637
                'contentInfo' => $spiContentInfo,
5638
                'creationDate' => 123456,
5639
            )
5640
        );
5641
        $spiContent = new SPIContent(array('versionInfo' => $spiVersionInfo));
5642
        $contentHandlerMock->expects($this->once())
5643
            ->method('copy')
5644
            ->with(42, 123)
5645
            ->will($this->returnValue($spiContent));
5646
5647
        $this->mockGetDefaultObjectStates();
5648
        $this->mockSetDefaultObjectStates();
5649
5650
        $domainMapperMock->expects($this->once())
5651
            ->method('buildVersionInfoDomainObject')
5652
            ->with($spiVersionInfo)
5653
            ->will($this->returnValue($versionInfoMock));
5654
5655
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5656
        $content = $this->mockPublishVersion(123456, 126666);
5657
        $locationServiceMock->expects($this->once())
5658
            ->method('createLocation')
5659
            ->with(
5660
                $content->getVersionInfo()->getContentInfo(),
5661
                $locationCreateStruct
5662
            );
5663
5664
        $contentService->expects($this->once())
5665
            ->method('internalLoadContent')
5666
            ->with(
5667
                $content->id
5668
            )
5669
            ->will($this->returnValue($content));
5670
5671
        $contentService->expects($this->once())
5672
            ->method('getUnixTimestamp')
5673
            ->will($this->returnValue(126666));
5674
5675
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5676
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, $versionInfoMock);
5677
    }
5678
5679
    /**
5680
     * Test for the copyContent() method.
5681
     *
5682
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5683
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5684
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5685
     */
5686
    public function testCopyContentWithRollback()
5687
    {
5688
        $this->expectException(\Exception::class);
5689
        $this->expectExceptionMessage('Handler threw an exception');
5690
5691
        $repositoryMock = $this->getRepositoryMock();
5692
        $contentService = $this->getPartlyMockedContentService();
5693
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5694
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5695
        $locationCreateStruct = new LocationCreateStruct();
5696
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5697
        $locationServiceMock = $this->getLocationServiceMock();
5698
        $user = $this->getStubbedUser(14);
5699
5700
        $permissionResolverMock = $this->getPermissionResolverMock();
5701
5702
        $permissionResolverMock
5703
            ->method('getCurrentUserReference')
5704
            ->willReturn($user);
5705
5706
        $repositoryMock
5707
            ->method('getPermissionResolver')
5708
            ->willReturn($permissionResolverMock);
5709
5710
        $repositoryMock->expects($this->once())
5711
            ->method('getLocationService')
5712
            ->will($this->returnValue($locationServiceMock))
5713
        ;
5714
5715
        $locationServiceMock->expects($this->once())
5716
            ->method('loadLocation')
5717
            ->with($locationCreateStruct->parentLocationId)
5718
            ->will($this->returnValue($location))
5719
        ;
5720
5721
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5722
        $contentInfoMock->expects($this->any())
5723
            ->method('__get')
5724
            ->with('id')
5725
            ->will($this->returnValue(42));
5726
5727
        $this->mockGetDefaultObjectStates();
5728
5729
        $repositoryMock->expects($this->once())->method('beginTransaction');
5730
        $repositoryMock->expects($this->once())->method('rollback');
5731
        $repositoryMock->expects($this->once())
5732
            ->method('canUser')
5733
            ->with(
5734
                'content',
5735
                'create',
5736
                $contentInfoMock,
5737
                [$location]
5738
            )
5739
            ->will($this->returnValue(true));
5740
5741
        $contentHandlerMock->expects($this->once())
5742
            ->method('copy')
5743
            ->with(42, null)
5744
            ->will($this->throwException(new Exception('Handler threw an exception')));
5745
5746
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5747
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5748
    }
5749
5750
    /**
5751
     * Reusable method for setting exceptions on buildContentDomainObject usage.
5752
     *
5753
     * Plain usage as in when content type is loaded directly.
5754
     *
5755
     * @param \eZ\Publish\SPI\Persistence\Content $spiContent
5756
     * @param array $translations
5757
     * @param bool $useAlwaysAvailable
5758
     *
5759
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\Values\Content\Content
5760
     */
5761
    private function mockBuildContentDomainObject(SPIContent $spiContent, array $translations = null, bool $useAlwaysAvailable = null)
5762
    {
5763
        $contentTypeId = $spiContent->versionInfo->contentInfo->contentTypeId;
5764
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5765
        $repositoryMock = $this->getRepositoryMock();
5766
5767
        $contentType = new ContentType([
5768
            'id' => $contentTypeId,
5769
            'fieldDefinitions' => [],
5770
        ]);
5771
5772
        $repositoryMock->expects($this->once())
5773
            ->method('getContentTypeService')
5774
            ->willReturn($contentTypeServiceMock);
5775
5776
        $contentTypeServiceMock->expects($this->once())
5777
            ->method('loadContentType')
5778
            ->with($this->equalTo($contentTypeId))
5779
            ->willReturn($contentType);
5780
5781
        $content = $this->createMock(APIContent::class);
5782
5783
        $this->getDomainMapperMock()
5784
            ->expects($this->once())
5785
            ->method('buildContentDomainObject')
5786
            ->with($spiContent, $contentType, $translations ?? [], $useAlwaysAvailable)
5787
            ->willReturn($content);
5788
5789
        return $content;
5790
    }
5791
5792
    protected function mockGetDefaultObjectStates()
5793
    {
5794
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5795
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5796
5797
        $objectStateGroups = array(
5798
            new SPIObjectStateGroup(array('id' => 10)),
5799
            new SPIObjectStateGroup(array('id' => 20)),
5800
        );
5801
5802
        /* @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5803
        $objectStateHandlerMock->expects($this->once())
5804
            ->method('loadAllGroups')
5805
            ->will($this->returnValue($objectStateGroups));
5806
5807
        $objectStateHandlerMock->expects($this->at(1))
5808
            ->method('loadObjectStates')
5809
            ->with($this->equalTo(10))
5810
            ->will(
5811
                $this->returnValue(
5812
                    array(
5813
                        new SPIObjectState(array('id' => 11, 'groupId' => 10)),
5814
                        new SPIObjectState(array('id' => 12, 'groupId' => 10)),
5815
                    )
5816
                )
5817
            );
5818
5819
        $objectStateHandlerMock->expects($this->at(2))
5820
            ->method('loadObjectStates')
5821
            ->with($this->equalTo(20))
5822
            ->will(
5823
                $this->returnValue(
5824
                    array(
5825
                        new SPIObjectState(array('id' => 21, 'groupId' => 20)),
5826
                        new SPIObjectState(array('id' => 22, 'groupId' => 20)),
5827
                    )
5828
                )
5829
            );
5830
    }
5831
5832
    protected function mockSetDefaultObjectStates()
5833
    {
5834
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5835
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5836
5837
        $defaultObjectStates = array(
5838
            new SPIObjectState(array('id' => 11, 'groupId' => 10)),
5839
            new SPIObjectState(array('id' => 21, 'groupId' => 20)),
5840
        );
5841
        foreach ($defaultObjectStates as $index => $objectState) {
5842
            $objectStateHandlerMock->expects($this->at($index + 3))
5843
                ->method('setContentState')
5844
                ->with(
5845
                    42,
5846
                    $objectState->groupId,
5847
                    $objectState->id
5848
                );
5849
        }
5850
    }
5851
5852
    /**
5853
     * @param int|null $publicationDate
5854
     * @param int|null $modificationDate
5855
     *
5856
     * @return \eZ\Publish\API\Repository\Values\Content\Content
5857
     */
5858
    protected function mockPublishVersion($publicationDate = null, $modificationDate = null)
5859
    {
5860
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5861
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5862
        /* @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5863
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5864
        $metadataUpdateStruct = new SPIMetadataUpdateStruct();
5865
5866
        $spiContent = new SPIContent([
5867
            'versionInfo' => new VersionInfo([
5868
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
5869
            ]),
5870
        ]);
5871
5872
        $contentMock = $this->mockBuildContentDomainObject($spiContent);
5873
        $contentMock->expects($this->any())
5874
            ->method('__get')
5875
            ->will(
5876
                $this->returnValueMap(
5877
                    [
5878
                        ['id', 42],
5879
                        ['contentInfo', $contentInfoMock],
5880
                        ['versionInfo', $versionInfoMock],
5881
                    ]
5882
                )
5883
            );
5884
        $contentMock->expects($this->any())
5885
            ->method('getVersionInfo')
5886
            ->will($this->returnValue($versionInfoMock));
5887
        $versionInfoMock->expects($this->any())
5888
            ->method('getContentInfo')
5889
            ->will($this->returnValue($contentInfoMock));
5890
        $versionInfoMock->expects($this->any())
5891
            ->method('__get')
5892
            ->will(
5893
                $this->returnValueMap(
5894
                    [
5895
                        ['languageCodes', ['eng-GB']],
5896
                    ]
5897
                )
5898
            );
5899
        $contentInfoMock->expects($this->any())
5900
            ->method('__get')
5901
            ->will(
5902
                $this->returnValueMap(
5903
                    array(
5904
                        array('alwaysAvailable', true),
5905
                        array('mainLanguageCode', 'eng-GB'),
5906
                    )
5907
                )
5908
            );
5909
5910
        $currentTime = time();
5911
        if ($publicationDate === null && $versionInfoMock->versionNo === 1) {
5912
            $publicationDate = $currentTime;
5913
        }
5914
5915
        // Account for 1 second of test execution time
5916
        $metadataUpdateStruct->publicationDate = $publicationDate;
5917
        $metadataUpdateStruct->modificationDate = $modificationDate ?? $currentTime;
5918
5919
        $contentHandlerMock->expects($this->once())
5920
            ->method('publish')
5921
            ->with(
5922
                42,
5923
                123,
5924
                $metadataUpdateStruct
5925
            )
5926
            ->will($this->returnValue($spiContent));
5927
5928
        /* @var \eZ\Publish\API\Repository\Values\Content\Content $contentMock */
5929
        $this->mockPublishUrlAliasesForContent($contentMock);
5930
5931
        return $contentMock;
5932
    }
5933
5934
    /**
5935
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
5936
     */
5937
    protected function mockPublishUrlAliasesForContent(APIContent $content)
5938
    {
5939
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
5940
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandlerMock */
5941
        $urlAliasHandlerMock = $this->getPersistenceMock()->urlAliasHandler();
5942
        $locationServiceMock = $this->getLocationServiceMock();
5943
        $location = $this->createMock(APILocation::class);
5944
5945
        $location->expects($this->at(0))
5946
            ->method('__get')
5947
            ->with('id')
5948
            ->will($this->returnValue(123));
5949
        $location->expects($this->at(1))
5950
            ->method('__get')
5951
            ->with('parentLocationId')
5952
            ->will($this->returnValue(456));
5953
5954
        $urlAliasNames = array('eng-GB' => 'hello');
5955
        $nameSchemaServiceMock->expects($this->once())
5956
            ->method('resolveUrlAliasSchema')
5957
            ->with($content)
5958
            ->will($this->returnValue($urlAliasNames));
5959
5960
        $locationServiceMock->expects($this->once())
5961
            ->method('loadLocations')
5962
            ->with($content->getVersionInfo()->getContentInfo())
5963
            ->will($this->returnValue(array($location)));
5964
5965
        $urlAliasHandlerMock->expects($this->once())
5966
            ->method('publishUrlAliasForLocation')
5967
            ->with(123, 456, 'hello', 'eng-GB', true, true);
5968
5969
        $location->expects($this->at(2))
5970
            ->method('__get')
5971
            ->with('id')
5972
            ->will($this->returnValue(123));
5973
5974
        $location->expects($this->at(3))
5975
            ->method('__get')
5976
            ->with('parentLocationId')
5977
            ->will($this->returnValue(456));
5978
5979
        $urlAliasHandlerMock->expects($this->once())
5980
            ->method('archiveUrlAliasesForDeletedTranslations')
5981
            ->with(123, 456, ['eng-GB']);
5982
    }
5983
5984
    protected $domainMapperMock;
5985
5986
    /**
5987
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\DomainMapper
5988
     */
5989
    protected function getDomainMapperMock()
5990
    {
5991
        if (!isset($this->domainMapperMock)) {
5992
            $this->domainMapperMock = $this->createMock(DomainMapper::class);
5993
        }
5994
5995
        return $this->domainMapperMock;
5996
    }
5997
5998
    protected $relationProcessorMock;
5999
6000
    /**
6001
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\RelationProcessor
6002
     */
6003
    protected function getRelationProcessorMock()
6004
    {
6005
        if (!isset($this->relationProcessorMock)) {
6006
            $this->relationProcessorMock = $this->createMock(RelationProcessor::class);
6007
        }
6008
6009
        return $this->relationProcessorMock;
6010
    }
6011
6012
    protected $nameSchemaServiceMock;
6013
6014
    /**
6015
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\NameSchemaService
6016
     */
6017
    protected function getNameSchemaServiceMock()
6018
    {
6019
        if (!isset($this->nameSchemaServiceMock)) {
6020
            $this->nameSchemaServiceMock = $this->createMock(NameSchemaService::class);
6021
        }
6022
6023
        return $this->nameSchemaServiceMock;
6024
    }
6025
6026
    protected $contentTypeServiceMock;
6027
6028
    /**
6029
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\ContentTypeService
6030
     */
6031
    protected function getContentTypeServiceMock()
6032
    {
6033
        if (!isset($this->contentTypeServiceMock)) {
6034
            $this->contentTypeServiceMock = $this->createMock(APIContentTypeService::class);
6035
        }
6036
6037
        return $this->contentTypeServiceMock;
6038
    }
6039
6040
    protected $locationServiceMock;
6041
6042
    /**
6043
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\LocationService
6044
     */
6045
    protected function getLocationServiceMock()
6046
    {
6047
        if (!isset($this->locationServiceMock)) {
6048
            $this->locationServiceMock = $this->createMock(APILocationService::class);
6049
        }
6050
6051
        return $this->locationServiceMock;
6052
    }
6053
6054
    /**
6055
     * @var \eZ\Publish\Core\Repository\ContentService
6056
     */
6057
    protected $partlyMockedContentService;
6058
6059
    /**
6060
     * Returns the content service to test with $methods mocked.
6061
     *
6062
     * Injected Repository comes from {@see getRepositoryMock()} and persistence handler from {@see getPersistenceMock()}
6063
     *
6064
     * @param string[] $methods
6065
     *
6066
     * @return \eZ\Publish\Core\Repository\ContentService|\PHPUnit\Framework\MockObject\MockObject
6067
     */
6068
    protected function getPartlyMockedContentService(array $methods = null)
6069
    {
6070
        if (!isset($this->partlyMockedContentService)) {
6071
            $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...
6072
                ->setMethods($methods)
6073
                ->setConstructorArgs(
6074
                    array(
6075
                        $this->getRepositoryMock(),
6076
                        $this->getPersistenceMock(),
6077
                        $this->getDomainMapperMock(),
6078
                        $this->getRelationProcessorMock(),
6079
                        $this->getNameSchemaServiceMock(),
6080
                        $this->getFieldTypeRegistryMock(),
6081
                        array(),
6082
                    )
6083
                )
6084
                ->getMock();
6085
        }
6086
6087
        return $this->partlyMockedContentService;
6088
    }
6089
6090
    /**
6091
     * @return \eZ\Publish\API\Repository\Repository|\PHPUnit\Framework\MockObject\MockObject
6092
     */
6093
    protected function getRepositoryMock(): Repository
6094
    {
6095
        $repositoryMock = parent::getRepositoryMock();
6096
        $repositoryMock
6097
            ->expects($this->any())
6098
            ->method('getPermissionResolver')
6099
            ->willReturn($this->getPermissionResolverMock());
6100
6101
        return $repositoryMock;
6102
    }
6103
}
6104